2016-11-04 142 views
0

我在类层次结构中遇到了一个问题,至今我都无法解决。下面是最小的示例,其中模板Base类本身继承自另一个不是模板的类(在下面的示例中称为AbsoluteBase)。类Derived然后从Base继承其模板参数也被Bases'模板参数:在初始化列表中通过模板类构造函数调用非模板基类的构造函数

#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一路。但是,编译代码时,我得到:

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

制作的作品Base的实例得很好,但在Derived初始化列表调用其构造函数时,编译器要AbsolutBase()作为构造即使整数给出参数。显然,在AbsoluteBase中定义默认构造函数时,print()函数会输出垃圾,因为没有值传递给number

因此,我的电话Base<T>::Base(int)有些事情必须是错的,但我看不到它是什么。我很感谢每一个解释和帮助!

问候, Benniczek

回答

0

你宣布绝对基地class AbsolutBase没有电子。编译错误修正了错字。

编辑:它也不会编译,如果你有类基地从绝对虚拟继承。除非你需要虚拟继承(使用多重继承?),你可以声明它类Base : public AbsoluteBase

如果你确实需要虚拟继承(钻石问题),你需要初始化Derived类中的AbsoluteBase。由于Base实际上是从AbsoluteBase继承的,因此Derived也可以继承Base2,它也实际上从AbsoluteBase继承(这是虚拟继承的一点,一个类可以继承自两个不同的继承自公共基础的不同类)。由于它是一个虚拟继承,即使Base和Base2可以从AbsoluteBase继承,也只能有一个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初始化?