为具有多重继承的一种类型设置默认构造函数

时间:2016-10-11 21:26:03

标签: c++ inheritance multiple-inheritance

我有两个班级,BaseDerivedDerived继承了所有Base的构造函数。另外,我有一个模板类Printer<T>,它包含对T类型对象的引用,并且有一个方法print()以某种方式打印一个对象。这是一个最小的插图。

class Base {
public:
    Base(int x) : x(x) {}
    int x;
};

template<typename T>
class Printer {
public:
    const T& object;

    Printer(const T& object) : object(object) {}

    void print() {
        cout << object << endl;
    }
};

class Derived : public Base {
public:
    using Base::Base;
};

std::ostream& operator<<(std::ostream& out, const Derived& d) {
    return out << d.x;
}

int main() {
    Derived d(1);

    Printer<Derived>(d).print();
}

现在我想避免直接使用Printer并允许这样的语法:Derived d(1); d.print();。因此,我也试图从Derived继承Printer<Derived>

class Derived : public Base, public Printer<Derived> {
public:
    typedef Printer<Derived> MyPrinter;

    using Base::Base;

    Derived() : MyPrinter(*this) {}
};  

现在我遇到了一个问题:Base构造函数对Printer一无所知,因此无法以任何方式初始化它。我也不能在这里使用构造函数委托,因为Derived中使用的构造函数实际上是从Base继承的。

我可以以某种方式使Derived的默认构造函数由任何其他构造函数委托,甚至是继承的构造函数吗?或者也许还有其他一些模式来初始化多重继承中的第二个基础?

另一件可以强化一切的事情是,我无法访问Base代码,只能按原样使用它。

更新 关于Remy Lebeau的回答:Base可以有多个我不知道的构造函数(它也是模板类),所以我无法实现所有这些构造函数,并且必须使用using Base::Base成语。

关于krzaq的回答:Printer实际上也有很多方法,不仅仅是print(),所以实现转发类很麻烦,我试图避免它。

4 个答案:

答案 0 :(得分:1)

如果您只需要访问Derived中的Printer<Derived>个实例,那么您只需将其删除即可:

template<typename T>
class Printer {
public:
    const T& object;

    Printer() : object(static_cast<T&>(*this)) {}

    void print() {
        cout << object << endl;
    }
};

live demo

或完全取消参考资料,让您的课程符合EBO的条件:

template<typename T>
class Printer {
public:
    void print() {
        cout << static_cast<T&>(*this) << endl;
    }
};

live demo

如果您不能/不想触摸Printer,我会创建一个单独的模板PrinterForwarder以阻止print()对正确的打印机的调用:

template<typename T>
class PrinterForwarder
{
public:
    void print() {
        Printer<T>(static_cast<T&>(*this)).print();
    }
};

class Derived : public Base, public PrinterForwarder<Derived> {
public:
    using Base::Base;
};

live demo

答案 1 :(得分:1)

  

现在我遇到了一个问题:基础构造函数对打印机一无所知,因此无法以任何方式初始化它。

要执行您正在尝试的内容,您将无法再使用using Base::Base语句。您必须更明确地了解Derived实现的构造函数,因此他们可以根据需要初始化Printer基类,例如:

class Derived : public Base, public Printer<Derived> {
public:
    typedef Printer<Derived> MyPrinter;

    Derived() : Base(0), MyPrinter(*this) {}
    Derived(int x) : Base(x), MyPrinter(*this) {}
};  

或者:

class Derived : public Base, public Printer<Derived> {
public:
    typedef Printer<Derived> MyPrinter;

    Derived() : Derived(0) {}
    Derived(int x) : Base(x), MyPrinter(*this) {}
};  

答案 2 :(得分:1)

你可以创建一个variadic模板catch-all构造函数,它将参数传递给Base并根据需要构造Printer,就像这样

Game

答案 3 :(得分:0)

我找到了一个非常简单的解决方案。让我们在Printer中存储指向T的指针,而不是参考。

template<typename T>
class Printer {
public:
    const T* objectPtr;

    Printer() : objectPtr(nullptr) {}
    Printer(const T& object) : objectPtr(&object) {}

    void print() {
        if (objectPtr) {
            cout << *objectPtr << endl;
        } else {
            cout << static_cast<const T&>(*this) << endl;
        }
    }
};

看起来并不安全,但让Printer() ctor私有化似乎可以达成协议。