c++ dynamic_cast 装饰器实例化失败

标签 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;
}

最佳答案

如果您需要访问某些内部类中独有的功能,您最好(取决于特定问题)尝试混合类。基本思想是让一个模板类继承它的模板参数。我简化了下面的类,但原理很清楚:

#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 的接口(interface)。对于 mixin 类,不再有包装,因为它已被继承取代,因此不需要 D 类。

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

关于c++ dynamic_cast 装饰器实例化失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39312070/

相关文章:

c# - 将类型转换为通用约束 T

c++ - 在 luabind::object 中存储一个带有父类的 lua 类

c# - 带有对象初始化器 NEST 5.x 的 Elasticsearch 嵌套动态查询

c++ - 转换到不同的基类会产生不同的结果。 C++

PostgreSQL:错误:运算符不存在:整数 = 字符变化

javascript - 想要从 javascript 提示创建动态数组

c++ - 如何使用QT/C++显示网页

c++ - cmake install "noconfig"脚本有什么用? IE。 "XXXTarget-noconfig.cmake"

c++ - 设备内存空间中的cuda程序内核代码

c - 如何为动态二维数组的整行赋值?