c ++ dynamic_cast over decorator instantiations失败

时间:2016-09-03 23:06:04

标签: c++ dynamic casting decorator

我试图了解装饰器模式是如何工作的,以及我可以“拉伸”它对我的需求。在this示例之后,我扩展了XYZ类。存在派生类“KLM”(来自XYZ)

具体来说,即使我有一个装饰器模式,派生的装饰器类“KLM”也有一些功能,它们不会出现在任何基类“XYZ”,“D”,“I”或“A”中。

因此,通常我会将对象实例化为

I * inKLM = new L( new M( new K( new A )));

这不允许我访问K::doVirtR(),L :: doVirtS()和M :: doVirtT()函数(参见下面的代码)。要访问这些,我需要使用dynamic_cast将inKLM指针向下转发到每个类“KLM”。

问题是我只能在上面的表达式中为最左边的new设置这个。我已经读过需要维护多态,以便动态转换工作,所以我试图在所有函数中都有一个虚拟析构函数。除了“外部”new操作(在本例中为“L”类的对象)之外,我仍然无法使动态转换工作。

请参阅此代码。我怎样才能使“LinKLM”,还有“MinKLM”和“KinKLM”在dynamic_casting中取得成功?

#include <iostream>
#include <list>

using namespace std;

class D; //decorator base

struct I { //interface (for both Base and DecoratorBase
    I(){
        cout << "\n| I::ctor ";
    }
    virtual ~I(){
        cout << "I::dtor |" ;
    }
    virtual void do_it() = 0;
    virtual void regDecorator(D* decorator) = 0;
    virtual void train() = 0;

    virtual void et() = 0;

};

class D: public I { //DecoratorBase : has same-named fns as Base (must be exported on I) and calls upon them.
  public:
    D(I * inner) : m_wrappee(inner) {
        cout << "D::ctor ";
        regDecorator(this);
    }
    virtual ~D() {
        cout << "D::dtor ";
        delete m_wrappee;
    }
    void do_it() {
        m_wrappee->do_it();
    }
    virtual void et() { 
        cout << "filling in for lack of et() in derived class\n"; 
    } //almost pure virtual, just not implemented in all derived classes

    void train(){ 
        m_wrappee->train(); 
    }

  private:
    void regDecorator(D* decorator){
        m_wrappee->regDecorator(decorator);
    }

    I * m_wrappee;
};

class A: public I { //Base has all the basic functionality
  public:
    A() {
        cout << "A::ctor " ;
        decList.clear(); 
    }
    ~A() {
        cout << "A::dtor |" ;
    }
    void do_it() {
        cout << 'A';
    }
    void train(){ 
        et(); 
    }
    void regDecorator(D* decorator)
    {
        if (decorator) {
            cout << "reg=" << decorator << " ";
            decList.push_back(decorator);
        }
        else
            cout << "dec is null!" <<endl;
    }
  private:

    void et()
    {
        //size_t counter=0;
        list<D*>::iterator it;
        for( it=decList.begin(); it != decList.end(); it++ )
        {
            //if ( (*it)->et() )
                (*it)->et();
            //else
            //  cout << "couldnt et cnt=" << counter << endl;
            //counter++;
        }
    }

    std::list<D*> decList;
};



class X: public D { //DerivedDecoratorX ..
  public:
    X(I *core): D(core){
        cout << "X::ctor ";
    }
    virtual ~X() {
        cout << "X::dtor ";
    }
    void do_it() {
        D::do_it();
        cout << 'X';
    }
    void doX() {
        cout << "doX" << endl;
    }

  protected:
    virtual void doVirtR() = 0;

  private:

    void et(){
        cout << "X::et" <<endl;
    }
};

class K: public X {
  public:
    K(I * core):X(core) {
      cout << "K::ctor " ;
    }
    virtual ~K() {
      cout << "K::dtor ";
    }
    void doVirtR(){
      cout << "doVirtK" <<endl;
    }

};

class Y: public D {
  public:
    Y(I *core): D(core){
        cout << "Y::ctor ";
        }
    virtual ~Y() {
        cout << "Y::dtor ";
    }
    /*void et(){
        cout << "Y::et" <<endl;
    }*/
    void do_it() {
        D::do_it();
        cout << 'Y';
    }
    void doY() {
        cout << "doY" << endl;
    }

  protected:
    virtual void doVirtS() = 0;

};

class L: public Y{
  public:
    L(I * core):Y(core) {
      cout << "L::ctor ";
    }
    virtual ~L() {
      cout << "L::dtor ";
    }
    void doVirtS(){
      cout << "doVirtL" <<endl;
    }
};

class Z: public D {
  public:
    Z(I *core): D(core){
        cout << "Z::ctor ";
        }
    virtual ~Z() {
        cout << "Z::dtor ";
    }
    void et(){
        cout << "Z::et" <<endl;
    }
    void do_it() {
        D::do_it();
        cout << 'Z';
    }
    void doZ() {
        cout << "doZ" << endl;
    }

    virtual void doVirtT() = 0;

};

class M: public Z{
  public:
    M(I * core):Z(core) { //must add D(core) here explicitly because of virtual inheritance in M's base class (Z).
      cout << "M::ctor " ;
    }
    virtual ~M() {
      cout << "M::dtor ";
    }
    void doVirtT(){
      cout << "doVirtM" <<endl;
    }
};

int main(void) //testing dynamic casting
{
  I * inKLM = new L( new M( new K( new A )));
  L * LinKLM = dynamic_cast<L *>( inKLM);
  M * MinKLM = dynamic_cast<M *>( inKLM);
  K * KinKLM = dynamic_cast<K *>( inKLM);
  cout << endl;

  if ( ! MinKLM ) cout << "null MinKLM!" << endl; 
  if ( ! LinKLM ) cout << "null LinKLM!" << endl; 
  if ( ! KinKLM ) cout << "null KinKLM!" << endl; 
  //KinKLM->doVirtR();
  //LinKLM->doVirtS();
  //MinKLM->doVirtT();
  //LinKLM->D::train();
  //KinKLM->do_it();
  //MinKLM->doZ();
  delete inKLM;
  cout << endl;
  return 0;
}

1 个答案:

答案 0 :(得分:1)

如果您需要访问某些内部类中唯一的功能,那么尝试使用mixin类可能会更好(取决于特定问题)。基本思想是让模板类继承其模板参数。我简化了下面的课程,但原则很明确:

#include <iostream>

// your base class
class I {
public:
    virtual void do_it() {}
};

// a decorator
template <class Base>
class T1 : public Base {

public:
    void do_it() {
        std::cout << "T1" << std::endl;
        Base::do_it();
    }

    void unique_in_T1() {
        std::cout << "Unique in T1" << std::endl;
    }
};

// another decorator
template <class Base>
class T2 : public Base {

public:
    void do_it() {
        std::cout << "T2" << std::endl;
        Base::do_it();
    }

    void unique_in_T2() {
        std::cout << "Unique in T2" << std::endl;
    }
};

// yet another decorator
template <class Base>
class T3 : public Base {

public:
    void do_it() {
        std::cout << "T3" << std::endl;
        Base::do_it();
    }

    void unique_in_T3() {
        std::cout << "Unique in T3" << std::endl;
    }
};

int main(int argc, const char * argv[]) {
    T3<T2<T1<I>>> my_object1;
    my_object1.do_it();
    my_object1.unique_in_T2();

    T1<T3<I>> my_object2;
    my_object2.do_it();
    my_object2.unique_in_T3();
    return 0;
}

不再需要您的课程D了。该类的主要目的是在保持I的接口的同时包装实际执行作业的对象。对于mixin类,由于它已被继承替换,因此不再包装,因此不需要D类。

Here是一个阅读更多内容的链接。