2017-05-16 7 views
1

클래스 Base에는 컨트롤이 없으며 모든 클래스 함수에 대한 멤버 포인터를 허용하는 함수가 있습니다. 그것은 다음과 같이 사용하기위한 것입니다 : (내가 알지도에 대한 관심을 둘 것을) Base 저장이 포인터를포인터 - 투 - 멤버 함수 및 다중 상속

class Derived : public Base { 
    void bindProperties() { 
    Base::bindProperty("answer", &Derived::getAnswer); 
    } 

    int getAnswer() const { return 42; } 
}; 

어떤 방법을 나중에 나를 Derived::get("answer") 호출 할 수 있습니다 (물론,이 단순화 된 상황이다). 다중 상속은 우리가 단지를 상속하는 데 사용할만큼, 나쁘지 않다 생각

class ICalculator { 
    virtual int getAnswer() const; 
}; 

template<class T> 
class LifeAndUniverseCalculator : public T, public ICalculator { 
    virtual int getAnswer() const /* override */ { return 42; } 

    void bindProperties() { 
    T::bindProperty("answer", &ICalculator::getAnswer); // (*) 
    } 
}; 

:

아래쪽 측면은 우리가 과거에 현명하게 시도하고, 다중 상속을 사용했다고한다 하나의 "구체적인"기본 클래스 만 가질 수 있습니다. 때때로 우리는 (나는 또한에 대한 액세스 권한이없는) 파생 클래스 중 하나에서 때때로 Base에서 파생 싶어하기 때문에

템플릿은 - 그 관련성이없는 경우 당신은 내가 대신 T 앤 드롭의 Base을 쓴 척 수 템플릿.

어쨌든, 지금 데 문제는, 내가

LifeAndUniverseCalculator calc; 
calc.bindProperties(); 
int answer = calc.get("answer"); 

를 호출 할 때 내가 횡설수설를 얻을 수 있다는 것입니다. 나는 vtable을에 포인터 뭔가있을 수 있습니다 생각, 그래서 당신이 낸로합니다 (올바르게 오프셋, 그러나 명확하게 작동하지 않는 계산 것이라고 기대하고

T::bindProperty("answer", &LifeAndUniverseCalculator::getAnswer); 

에 의해

T::bindProperty("answer", &ICalculator::getAnswer); 

를 교체 시도 지금 쯤이면, 나는이 모든 것이 어떻게 작동하는지에 대해 두 번째 추측하고 있습니다.)

  • 는 다중 상속을 제거하고 (그것이 유일한 파생 클래스의)

  • 이 모든 래퍼 함수를 ​​만드는 LifeAndUniverseCalculator 직접 ICalculator에 최선을 다하는하기 등

    나는, 일부 옵션의 생각 ICalculator 내용은 LifeAndUniverseCalculator입니다. LifeAndUniverseCalculator::Calculator_GetAnswerICalculator::GetAnswer으로 전화하면됩니다.

바람직

  • 알고 내가 좋아하는 것

    , 간단한 방법으로 (*)로 표시된 선을 수정하는 방법이 있나요?

  • 그렇지 않은 경우 가장 좋은 해결책은 무엇입니까 (위의 대안 중 하나 또는 다른 것)?
  • 내가 Base의 작성자에게 연락 할 수 있고 기꺼이 수업을 변경할 수 있다면 내 설명에 따라 합당한 말을 할 수 있다면 구체적으로 물어야 할 것이 무엇인지 물어보십시오.

MCVE가 필요하면 on IDEOne 문제가 있다고 생각됩니다.하여 MCVE에서

+0

MCVE에서 멤버 포인터가 A 형 멤버에 대한 포인터 함수로 정의 된 함수 유형으로 캐스트되는 것이 문제가 될 수 있습니까? 반면 캐스팅되는 함수는 A가 아닌 멤버입니까? – jwimberley

+0

@jwimberley 지금까지 헤더 파일을 훑어 보면 알 수 있듯이 실제로 'Unknown'멤버를 가리키고 있지만 문제가 변경되지 않는다고 생각합니다 (아이디어는 아마도 'Unknown'이 0 바이트 임) . – CompuChip

+1

프로그램에 정의되지 않은 동작의 터미널 케이스가 있습니다. 이 방법으로는 공용체를 사용할 수 없으며 시도하면 충돌이 완전히 예상됩니다. –

답변

1

는 힘 (간략화하여 코드 Base::bindProperty 유사한) 기능은 A::bindFunctionA의 멤버 함수 B의 기능의 부재 캐스트. 이것은 뿌리 문제로 나를 때린다. 이가 std::function<int(void)>A::f의 유형을 변경하여 고정 할 수 있습니다 만이 변화

class A 
    : public ABase { 
public: 
    // int a, b; 

    class Unknown{}; 
    typedef int(A::*Function)(); 

    template<typename T, typename Func> 
    void bindFunction(T* owner, Func myf) { 
     f = std::bind(myf,owner); 
    } 

    int call() { 
     return f(); 
    } 

    //Function f; 
    std::function<int(void)> f; 
}; 

... 

class Combined 
: public A, public B { 
public:  
    Combined(int value) : B(value), A() {} 

    virtual void /*A::*/bind() /* override */ { 
     A::bindFunction(this, &Combined::getValue); 
    } 
}; 

, 당신의 MCVE 그러나

The answer to Life, The Universe and Everything is 42 

을 인쇄, 작동, 나는 인식이 나는 변경 코드 명시 적으로 언급 한 클래스에 속하며 수정할 수 없습니다. 이것은 실제로 Base이하는 것입니까? 다른 클래스의 멤버 함수를 자체의 멤버 함수로 캐스팅합니까? (또는 내 수정으로 인해 코드가 작동하는 동안 문제를 오인 했음).

+0

감사합니다 jwimberly, 내가 그 수업을 수정할 수는 없지만 나는 그것을 쓴 사람과 연락 할 수있는 위치에 있습니다. 당신의 도움으로 나는 변화에 대한 구체적인 요구를 할 수 있어야합니다. 적어도 upvote가 있으니, 내가 어떻게 계속되는지 알려 드리겠습니다. – CompuChip

+0

@n.m. 기준. 의 코멘트, 아마도 진짜 문제는 캐스트 기능 자체에 있으며, 이것이 내 "수정"(캐스트 제거)이 작동하는 이유입니다. – jwimberley