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

Setting a default constructor for one type with multiple inheritance

本文关键字:一个 类型 设置 构造函数 默认 多重继承      更新时间:2023-10-16

我有两个类,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();。因此,我试图从Printer<Derived>继承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(),所以实现转发器类是一个麻烦,我尽量避免它。

如果您需要的只是访问Printer<Derived>Derived实例,那么您可以简单地将其cast down:

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

现场演示

或完全取消引用,使您的类符合EBO:

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

现场演示

如果你不能/不想触摸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;
};

现场演示

现在我有一个问题:基构造函数对Printer一无所知,因此无法以任何方式初始化它。

要做你正在尝试的事情,你将不能再使用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) {}
};  

您可以创建一个可变的模板捕获所有构造函数,它将参数传递给Base并根据需要构造Printer,如下所示

class Derived: ... {
   template<typename... Args>
   Derived(Args&&... args): Base(std::forward<Args>(args)...), Printer(*this) {}
}

我发现了一个非常简单的解决方案。让我们在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私有似乎使交易。

相关文章: