传递基类指针

时间:2009-11-19 15:40:41

标签: c++ design-patterns inheritance class-design

场景:我有以下定义的类。

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)永远不会被调用。我显然做错了什么。 在这里尝试实现目标的正确方法是什么?

2 个答案:

答案 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,但是当派生类的数量不随时间变化或变化缓慢时,它会更加简单易懂。