通过初始化列表

时间:2016-11-04 21:11:48

标签: c++ templates inheritance constructor

我在类层次结构中遇到了一个问题,到目前为止我无法解决。下面是一个最小的例子,其中模板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()函数会输出garbage,因为没有值传递给number

因此我对Base<T>::Base(int)的呼吁有些不对劲,但我无法看到它是什么。我很感激每一个解释和帮助!

问候, Benniczek

3 个答案:

答案 0 :(得分: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初始化的?

答案 1 :(得分:0)

您在没有e的情况下将Absolute Base声明为class AbsolutBase。用错字修复编译就好了。

编辑:如果您有从Absolute进行虚拟继承的类库,它也将无法编译。除非您需要虚拟继承(使用多重继承?),否则可以将其声明为类Base : public AbsoluteBase

如果确实需要虚拟继承(钻石问题),则需要在Derived类中初始化AbsoluteBase。鉴于Base实际上继承自AbsoluteBase,Derived也可以从Base2继承,它也实际上从AbsoluteBase继承(这是虚拟继承的一点,一个类可以从两个不同的类继承,它们本身从一个公共基础继承)。由于它是一个虚拟继承,即使Base和Base2可以从AbsoluteBase继承,也只能有一个AbsoluteBase,那么它是如何初始化的呢?这就是Derived需要直接初始化它的原因,这样当制作一份AbsoluteBase时,就可以很好地理解它是如何被初始化的。

同样,这很麻烦,如果你不需要虚拟继承(你可能不会猜测......)你可以公开地从AbsoluteBase继承Base并称之为一天。

答案 2 :(得分:0)

由于虚拟继承。当base类从另一个类继承虚拟时,base的子类还必须调用其父级的虚拟父级的构造函数。由于你没有这样做,编译器试图调用无参数AbsoluteBase的ctor。所以你只需编写如下代码:

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