为具有多重继承的一种类型设置默认构造函数
Setting a default constructor for one type with multiple inheritance
我有两个 class,Base
和 Derived
。 Derived
继承了所有 Base
的构造函数。另外,我有一个模板 class 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
可以有多个我不知道的构造函数(它也是一个模板 class),所以我不能实现所有的构造函数并且必须使用 using Base::Base
成语。
关于krzaq的回答:Printer
其实也有很多方法,不只是print()
,所以实现转发器class很麻烦,我尽量避免。
如果您只需要从 Printer<Derived>
访问 Derived
实例,那么您可以简单地将其转换为:
template<typename T>
class Printer {
public:
const T& object;
Printer() : object(static_cast<T&>(*this)) {}
void print() {
cout << object << endl;
}
};
或完全取消参考,使您的 class 有资格获得 EBO:
template<typename T>
class Printer {
public:
void print() {
cout << static_cast<T&>(*this) << endl;
}
};
如果您t/don也不想触及 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;
};
Now I have a problem: Base constructors know nothing about Printer and thus cannot initialize it in any way.
要执行您正在尝试的操作,您将无法再使用 using Base::Base
语句。您必须更明确地了解 Derived
实现的构造函数,以便它们每个都可以根据需要初始化 Printer
基础 class,例如:
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) {}
};
我找到了一个非常简单的解决方案。让我们在 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 私有化似乎可以达成协议。
您可以创建一个可变参数模板包罗万象的构造函数,它将参数传递给 Base 并根据需要构造 Printer,就像这样
class Derived: ... {
template<typename... Args>
Derived(Args&&... args): Base(std::forward<Args>(args)...), Printer(*this) {}
}
我有两个 class,Base
和 Derived
。 Derived
继承了所有 Base
的构造函数。另外,我有一个模板 class 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
可以有多个我不知道的构造函数(它也是一个模板 class),所以我不能实现所有的构造函数并且必须使用 using Base::Base
成语。
关于krzaq的回答:Printer
其实也有很多方法,不只是print()
,所以实现转发器class很麻烦,我尽量避免。
如果您只需要从 Printer<Derived>
访问 Derived
实例,那么您可以简单地将其转换为:
template<typename T>
class Printer {
public:
const T& object;
Printer() : object(static_cast<T&>(*this)) {}
void print() {
cout << object << endl;
}
};
或完全取消参考,使您的 class 有资格获得 EBO:
template<typename T>
class Printer {
public:
void print() {
cout << static_cast<T&>(*this) << endl;
}
};
如果您t/don也不想触及 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;
};
Now I have a problem: Base constructors know nothing about Printer and thus cannot initialize it in any way.
要执行您正在尝试的操作,您将无法再使用 using Base::Base
语句。您必须更明确地了解 Derived
实现的构造函数,以便它们每个都可以根据需要初始化 Printer
基础 class,例如:
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) {}
};
我找到了一个非常简单的解决方案。让我们在 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 私有化似乎可以达成协议。
您可以创建一个可变参数模板包罗万象的构造函数,它将参数传递给 Base 并根据需要构造 Printer,就像这样
class Derived: ... {
template<typename... Args>
Derived(Args&&... args): Base(std::forward<Args>(args)...), Printer(*this) {}
}