我有类似附件的东西。我基本上有一个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;
}
答案 0 :(得分:3)
好吧,你可以Doer
模仿:
template<class T>
class Doer
{
public:
Doer(T* b) : base(b) { }
void DoIt()
{
base->Func();
}
private:
T* base;
};
但为此,我只需将virtual void Func()
添加到Base
。
请注意,您可能希望在任何一种情况下公开Func
: - )
答案 1 :(得分:0)
这种方法怎么样:
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吗?
任何人都可以澄清吗?
由于
答案 2 :(得分:0)
你可以使用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与您的Base类实例相同。以下程序:
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允许构造函数继承,因此可以使用编译器标志来避免此问题。
答案 3 :(得分:0)
实际上你不需要参数化整个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()调用没有额外的费用,或者你不知道你是哪一个是要处理下一个,然后你需要检查它的某种类型的特征或其他什么的动态类型,这是一个'如果'因此分支,从而错误预测和开销。请注意,我没有添加函数调用的成本,无论如何都存在。