c ++ dynamic_cast在装饰器实例化失败 [英] c++ dynamic_cast over decorator instantiations fails

查看:165
本文介绍了c ++ dynamic_cast在装饰器实例化失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想了解装饰器模式是如何工作的,以及我可以伸展到我需要多少。遵循示例,我扩展了类XYZ。存在派生类KLM(来自XYZ)

I am trying to understand how decorator pattern works and how much I can "stretch" it to me needs. Following this example, I have extended classes XYZ. There exist derived classes "KLM" (from XYZ)

具体来说,即使我有一个装饰器模式,派生装饰器类KLM

Specifically, even though I have a decorator pattern, the derived decorator classes "KLM" have some functionality that does not show up in any of their base classes "XYZ", "D", "I" or "A".

因此,虽然通常我将实例化一个对象作为

So while normally I would instantiate an object as

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

这不允许我访问 K :: doVirtR / code>,L :: doVirtS()和M :: doVirtT()函数(见下面的代码)。要访问这些,我需要使用 dynamic_cast 向每个类KLM下调inKLM指针。

This would not allow me to access the K::doVirtR() , L::doVirtS() and M::doVirtT() functions (see code below). To access these I would need to downcast the inKLM pointer using dynamic_cast to each of classes "KLM".

问题是我只能在上面的表达式中为最左边的 new 执行此操作。我已经读到多态性需要维护为了动态转换工作,所以我试图有一个虚拟析构函数在所有的函数。仍然我不能得到动态转换工作除了外操作(在这种情况下类L的对象)。

The problem is that I only manage to do this for the leftmost new in the expression above. I have read that polymorphism needs to be maintained in order for the dynamic casting to work, so I have tried to have a virtual destructor in all functions. Still I cannot get the dynamic cast to work for anything other than the "outer" new operation (in this case object of class "L").

请参阅此代码。如何在dynamic_casting中不仅可以创建LinKLM,还可以创建MinKLM和KinKLM?

Please see this code. How can I make not only "LinKLM" , but also "MinKLM" and "KinKLM" success in 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;
}


推荐答案

如果您需要访问功能在一些内部类中是唯一的,你可能会更好(取决于特定的问题)尝试mixin类。基本思想是使一个模板类继承其模板参数。我已经简化了下面的类,但原则是清楚的:

If you need access to functionality that is unique in some of the inner classes, you may be better off (depending on the particular problem) trying mixin classes. The basic idea is to have a template class inherit its template parameter. I have simplified the classes below but the principle is clear:

#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 类。

Your class D is not needed anymore. The main purpose of that class is to wrap the object that actually does the job while maintaining the interface of I. With mixin classes there is no wrapping anymore as it has been replaced by inheritance, hence there is no need for the D class.

这里是阅读更多内容的链接。

Here is a link to read more.

这篇关于c ++ dynamic_cast在装饰器实例化失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆