使用模板调用正确的派生类方法而不使用虚拟?
Calling proper derived class' method using templates without using virtual?
我有类似附加的东西。 我基本上有一个 Doer 类,我想从它的成员调用 Func(),而不使用虚拟或尽可能少的代码重复。 此外,提升也不是一种选择。 我知道这个例子可能不是那么清楚,但我希望你明白这个想法。 乙
class Base { // a bunch of shared base functionality. Cannot be instantiated by itself }
class D1 : public Base
{
void Func();
}
class D2 : public Base
{
void Func();
}
//----
class Doer
{
Doer(Base* b) : base(b) { }
void DoIt()
{
base->Func();
}
Base* base;
}
好吧,你可以Doer
模板化:
template<class T>
class Doer
{
public:
Doer(T* b) : base(b) { }
void DoIt()
{
base->Func();
}
private:
T* base;
};
但为此,我只想在Base
中添加一个virtual void Func()
。
请注意,无论哪种情况,您都可能希望公开Func
:-)
这种方法怎么样:
class Base { // a bunch of shared base functionality. Cannot be instantiated by itself
~Base() { //stuff }
void Func();
}
class D1 : public Base
{
void Func();
}
class D2 : public Base
{
void Func();
}
//----
class Doer
{
Doer(Base* b) : base(b) { }
void DoIt()
{
base->Func();
}
Base* base;
}
由于 Func() 不是虚拟的并且被子项重载,因此不应该有 vtable 或任何产生的性能损失,对吗?
此外,析构函数需要在基类上调用,但声明它是虚拟的会强加一个 vtable?
谁能澄清一下?
谢谢
你可以使用mixins!它们有利于优化(大量内联机会,没有虚拟方法调用),但有时有点难以推理。 下面是使用 mixins 实现的示例:
template<class Base> class Doer : Base {
public:
Doer() {}
void DoIt() {
this->Func();
}
};
class D1 {
public:
void Func() {
cout<<"Hello from D1"<<endl;
}
};
class D2 {
public:
void Func() {
cout<<"Hello from D2"<<endl;
}
};
使用此方法略有不同,因为 Doer 与基类实例相同。 以下程序:
Doer<D1> *d1 = new Doer<D1>();
Doer<D2> *d2 = new Doer<D2>();
d1->DoIt();
d2->DoIt();
生成输出:
来自D1的你好
来自D2的你好
这有一个明显的缺点,即 D1 和 D2 不会强制实现"Func"方法。 如果你忘记了它,你会收到一个非常方便的C++模板实例化错误,而不是"找不到方法"。 如果您要经常使用模板,Clang 是一个不错的选择,因为与 g++ 相比,您会收到更有用的编译器错误。 另一个缺点是构造函数:Doer 定义默认构造函数,但不公开 D1 的构造函数。C++11 允许构造函数继承,因此可以使用编译器标志避免此问题。
不需要参数化整个Doer类。这将正常工作(接近ccurtsinger的建议):
class Base {
public:
void Func() {};
};
class B1 {
public:
void Func() { cout << "in B1::Func" << endl;}
};
class B2 {
public:
void Func() { cout << "in B2::Func" << endl;}
};
class Doer {
public:
template <class B> void Do(B *pb) {pb->Func();}
};
int main() {
B1 b1;
B2 b2;
Doer d;
d.Do<B1>(&b1);
d.Do<B2>(&b2);
return 0;
}
但实际上有一个更大的问题:从你说你最终使用的代码来看,似乎在编译时你确切地知道你正在处理哪些派生类对象,所以代码如下:
for(auto i = begin(B1_container); i != end(B1_container); ++i) {
i->Func();
}
for(auto j = begin(B2_container); j != end(B2_container); ++j) {
j->Func();
}
应该做这个伎俩。
我要说的是 - 你要么提前知道你在这里使用 B1-s,在那里使用 B2-s,并且 Func() 调用没有额外的成本,要么你不知道你接下来要处理哪一个,然后你需要检查它是某种类型的特征或其他任何东西的动态类型,这是一个"如果",因此分支,因此错误预测和开销。请注意,我没有添加函数调用的成本,无论如何,这两种情况都存在。
- 是否可以使用基类非虚拟方法中的派生类虚拟方法?
- 不实现父类的虚拟方法有什么风险
- 基类中的虚拟方法和子类中的非 Virtula 方法.仍然如何调用子类方法,即使它是非虚拟的
- 我将如何通过抽象类传递虚拟方法,但可以选择不重写
- 为什么从 DLL 调用类方法需要虚拟说明符?
- 在不实例化的情况下调用不同派生类的虚拟方法
- 派生类中虚拟方法的默认实现
- 如何使继承相同基类的类的虚拟方法弄清楚如何处理它们的参数?
- 从基类C++调用虚拟方法
- 使用模板生成纯虚拟基类方法
- 在单个指针数组中调用不同派生类的虚拟方法
- 类具有虚拟方法,但具有非虚拟析构函数C++
- 如何使用static_assert检查派生类是否覆盖非虚拟基类方法
- 限制指针类型的模板参数和重写模板化基类的虚拟方法
- 专业类的虚拟方法
- C++11:使用中央命令映射器调用虚拟基类方法
- 虚拟继承:当只有一个基类具有"虚拟"关键字时,为什么它有效?有没有更好的方法?
- 使用虚拟重写基类方法不起作用
- 使用模板调用正确的派生类方法而不使用虚拟?
- 调用actor中其他类的虚拟方法