2016-11-04 3 views
0

지금까지 해결할 수 없었던 클래스 계층 구조에서 문제가 발생했습니다. 아래에서 템플릿 Base 클래스 자체가 템플릿이 아닌 다른 클래스 (아래 예제에서는 AbsoluteBase)에서 상속하는 최소 예제를 얻습니다.초기화 목록의 템플릿 클래스 생성자를 통해 비 템플릿 기본 클래스의 생성자를 호출합니다.

#include <iostream> 
using namespace std; 

class AbsolutBase { 
    protected: 
     int number; 

     AbsoluteBase(int _number) { 
      number = _number; 
     } 
     virtual ~AbsoluteBase() {} 
     virtual void print() const = 0; 
}; 

template <typename T> class Base : virtual public AbsoluteBase { 
    public: 
     Base(int _number) : AbsoluteBase(_number) {} 

     virtual void print() const { 
      cout << number << endl; 
     } 
}; 

template <typename T> class Derived : public Base<T> { 
    public: 
     Derived(int _number) : Base<T>::Base(_number) {} 
}; 

int main() { 
    Derived<char> object(100); 
    object.print(); 
} 

그래서 각 생성자는 부모의 생성자를 호출하고 인자로 내려 AbsoluteBase 모든 방법을 정수를 전달합니다 클래스 Derived 다음의 템플릿 인수는 Bases' 템플릿 인수 인 상태 Base에서 상속됩니다. 코드를 컴파일 할 때 내가 얻을 : Derived의 초기화 목록에 생성자를 호출 할 때

error: no matching function for call to 'AbsoluteBase::AbsoluteBase()' 
note: candidates are: AbsoluteBase::AbsoluteBase(int) 
note: candidate expects 1 argument, 0 provided 

이 잘 Base 작품의 인스턴스를 만들기하지만, 컴파일러는 정수의 인수가 주어진 경우에도 생성자로 AbsolutBase()를 원한다. 분명히, AbsoluteBase에 기본 생성자를 정의 할 때 print() 함수는 가비지 값을 출력하지 않고 number에 전달했습니다.

내 전화 Base<T>::Base(int)에 뭔가 이상한 점이 있지만 그게 무엇인지는 알 수 없습니다. 모든 설명과 도움에 감사드립니다!

인사말, Benniczek

답변

0

당신은 전자 않고 class AbsolutBase로 절대 자료를 선언했다. 오타가 수정되어 잘 컴파일됩니다.

편집 : Absolute에서 가상 상속을하는 클래스 기반을 가지고 있다면 컴파일되지 않습니다. 가상 상속이 필요하지 않으면 (다중 상속 사용?) 클래스를 선언 할 수 있습니다. Base : public AbsoluteBase

가상 상속이 필요하면 (다이아몬드 문제) 파생 클래스에서 AbsoluteBase를 초기화해야합니다. Base가 AbsoluteBase를 가상으로 상속 받았기 때문에 Derived는 AbsoluteBase로부터 가상 상속받은 Base2도 상속받을 수 있습니다.이 상속은 가상 상속의 포인트이며 공통 클래스에서 상속받은 두 개의 클래스에서 상속받을 수 있습니다. 가상 상속이기 때문에 Base와 Base2가 AbsoluteBase에서 상속받을 수 있더라도 1 개의 AbsoluteBase 만있을 수 있습니다. 어떻게 초기화됩니까? 이것이 Derived가 직접 초기화해야하는 이유입니다. 따라서 AbsoluteBase의 복사본 하나가 만들어지면 초기화 방법을 잘 이해할 수 있습니다.

가상 상속을 필요로하지 않는다면 어설픈 것입니다. 아마 추측 할 수 없을 것입니다 ... 당신은 Base를 AbsoluteBase에서 공개적으로 상속 받고 하루 만 호출 할 수 있습니다.

+0

지금은 오타 때문에 멍청하다고 느낍니다. 그러나 위의 게시물에서 컴파일 된 코드에는 없습니다. 가상 상속에 관해서 : 아아, 나는 그 사실을 모르고 ... 다이아몬드 상속 문제가 더 많은 코드에서 발생할 수 있기 때문에 가상 상속을 사용했지만 대부분의 파생 클래스에서 초기화에 대해이 규칙을 알지 못하기 때문에 가상 상속을 사용했습니다. 고마워! – Benniczek

0

가상 상속 때문에. base 클래스가 을 다른 클래스에서 사실상 상속하면 base의 자식 클래스도 부모의 가상 부모 생성자를 호출해야합니다. 당신이 이것을하지 않았기 때문에, 컴파일러는 인자없는 AbsoluteBase의 ctor를 호출하려고합니다.

template <typename T> class Derived : public Base<T> { 
    public: 
     Derived(int _number) : AbsoluteBase(_number), Base<T>::Base(_number) {} 
}; 
+0

아래 표를 설명하는 사람은 누구입니까? –

+0

대단히 고맙습니다. 가상 상속에 대해이 규칙을 알지 못했습니다. – Benniczek

1

AbsoluteBase 가상 기본 클래스입니다 다음과 같이 그래서 당신은 코드에 있습니다. 따라서 이 가장 파생 된 클래스의 생성자로 초기화되어야합니다. 이니셜 라이저 AbsoluteBase(_number)은 유효하지만 Base<T> 유형의 객체를 직접 인스턴스화하는 경우에만 사용됩니다.

가장 좋은 해결책은 아마도 AbsoluteBase을 가상 기본 클래스로 만들지 않는 것입니다. 이 규칙에 대한

그 이유는 다음과 같습니다

class Silly: public Base<int>, Base<long> 
{ 
public: 
    Silly() : Base<int>::Base(1), Base<long>::Base(2) {} 
}; 

가 하나의 AbsoluteDerived 객체 (즉, virtual이 맥락에서 어떤 의미의)입니다 그래서 1 또는 2로 초기화됩니다?

관련 문제