场景:我有以下定义的类。
class Baseclass { };
class DerivedTypeA : public Baseclass { };
class DerivedTypeB : public Baseclass { };
// ... and so on ...
class Container
{
list<Baseclass*> stuff;
list<DerivedTypeA*> specific_stuff;
// ... initializing constructors and so on ...
public:
void add(Baseclass * b)
{
stuff.add(b);
}
void add(DerivedTypeA * a)
{
stuff.add(a);
specific_stuff.add(a);
}
};
class ContainerOperator
{
Container c;
// ... initializing constructors and so on ...
public:
void operateOnStuff(Baseclass * b)
{
// This will always use "void add(Baseclass * b)" no matter what object b really is.
c.add(b);
}
};
// ...
containerOperator.operateOnStuff(new DerivedTypeA());
所以,我想做的是在Container
中以某种特殊方式处理某个派生类。
问题: void add(DerivedTypeA * a)
永远不会被调用。我显然做错了什么。 在这里尝试实现目标的正确方法是什么?
答案 0 :(得分:5)
C ++中的重载分辨率发生在编译时,而不是运行时。解决此类问题的“通常”方法是使用Visitor pattern。
您可以通过使用CRTP实施访问者来减少样板复制粘贴的数量。 如果使用CRTP for Base :: accept,则无需在派生类中再定义它。
这是一个与你类似的程序,但有点简单:
#include <iostream>
class Base; class Derived;
struct Operation {
void add(Base *b) {
std::cout << "Base\n";
}
void add(Derived *b) {
std::cout << "Derived\n";
}
void visit(Base *b); // need to define this after Base class
};
struct Base {
virtual ~Base() {}
virtual void accept(Operation &o)
{
o.add(this);
}
};
void Operation::visit(Base *b) {
b->accept(*this);
}
struct Derived : public Base {
void accept(Operation &o)
{
o.add(this);
}
};
int main() {
Operation o;
Base b;
Derived d;
Base *ptrb = &b;
Base *ptrd = &d;
o.add(ptrb); // These two print "Base"
o.add(ptrd);
o.visit(ptrb); // "Base"
o.visit(ptrd); // "Derived"
}
答案 1 :(得分:2)
您可以使用RTTI来确定提供的对象是否属于派生类型,如果是,则调用第二个add()函数。
void add(Baseclass * b)
{
stuff.add(b);
DerivedTypeA * a = dynamic_cast<DerivedTypeA *>(b);
if ( a != 0 )
specific_stuff.add(a);
}
与访问者模式不同,此解决方案违反了Open-Closed Principle,但是当派生类的数量不随时间变化或变化缓慢时,它会更加简单易懂。