装饰模式中的c ++虚拟析构函数

时间:2015-11-09 18:07:14

标签: c++ virtual decorator destructor

我最近在学校作业中遇到了装饰模式,想询问在decorator类中实现析构函数的细节。

考虑以下Decorator类

class Decorator:public Base{
    protected: 
        Base &base;
        Decorator(Base &b):base(b){}
        virtual ~Decorator(){delete &(this->base)}
        //other methods here
};

Decorator

的派生类中
class Derived:public Decorator{
    public:
        Derived(Base& b):Decorator(b){};
        ~Derived(){delete &(this->base)}; //want a custom destructor here       
};

但是下面的代码不起作用,请考虑

Base* b1 = new Base;
b1 = new Derived(*b1);
//do stuff with b1
delete b1; //segmentation fault

问题是:

  1. 为什么不起作用?我在实现析构函数时做错了什么?

  2. 我通过删除virtual中的~Decorator()关键字并注释掉~Derived()来改变代码,但考虑到我希望我的自定义析构函数Derived,这不是一个好的解决方法1}} class

  3. 有没有更好的方法来实现装饰器模式?怎么样?

  4. 编辑:

    除了我们的任务中提供的内容外,我没有真实的用例。 我们被要求实现一个具有以下功能的文本处理器(装饰器):

    DropFirst n删除每个单词的前n个字符。如果n大于某个单词的长度,则删除整个单词(尽管后面的单词不受影响)。 要创建的文件:dropfirst.h和dropfirst.cc

    •DoubleWords将字符串中的所有单词加倍。要创建的文件:doublewords.h和droublewords.cc

    •AllCaps字符串中的所有字母均以大写字母显示。其他字符保持不变。要创建的文件:allcaps.h和allcaps.cc

    •计数c字符串中第一次出现的字符c被替换为1.第二次被替换为2,...第十次被替换为10,依此类推。要创建的文件:count.h和count.cc

    假设文本处理器被赋予“hello world”并由doublewords dropfirst 2 count l

    修饰

    输出

    12o
    34o
    r5d
    r6d
    sample.txt allcaps
    HELLO
    WORLD
    

3 个答案:

答案 0 :(得分:2)

您要删除Base& base两次:首先,Derived的析构函数删除this-> base,然后Decorator(parent)的析构函数再次删除this-> base。解决方案是,Decorator应该是唯一删除this-> base的人。

答案 1 :(得分:0)

析构函数和构造函数应该总是结合在一起。总是(在99.99999%)情况下,如果在构造函数中delete,则只能在析构函数中new。既然你没有你的代码是错误的。采用这个简单的逻辑规则,你的生活将变得更加容易。

答案 2 :(得分:0)

我不确定你要做什么,但这肯定不是做多态的方法。试试这个代码,特别注意事情的执行顺序。

class base
{

    int* heapint;
public:

    base()
    {
        cout<<"creating base object, including a heap allocated int"<<endl;
        heapint = new int(25);
    }


    virtual ~base()
    {
        cout<<"Now destroying base object, including the heapint"<<endl;
        delete heapint;
    }

    virtual int getHeapint()
    {
        return *heapint;
    }

    virtual void overRideTest()
    {
        cout<<"This function is to be overrided in the subtype"<<endl;
    }


};

class subtype : public base
{
public:
    subtype()
    {
        cout<<"creating subtype"<<endl;
    }

    ~subtype()
    {
        cout<<"destroying subtype"<<endl;
    }

    void overRideTest() override
    {
        cout<<"This function was invoced, despite the ptr being of type base*"<<endl;
    }

};


int main()
{

    base* ptr = new subtype();
    cout<<"getting value of heapint: "<<ptr->getHeapint()<<endl;//notice how I need to create a virtual get function in base.
    ptr->overRideTest();
    delete ptr;
}

我怀疑你在尝试计算多态性时犯了同样的误解:当你实例化子类型时,实际上是在创建一个由两个对象组成的复杂数据结构(如果计算vtable,则为三个),一个base和一个子类型。简而言之,尽管您可能会想到这两个对象,但这两个对象仍然是截然不同的。

此外,请注意,我从不尝试处理basetype之外的basetype的内存。你不应该在你的子类型中有一个指向基类型的指针,这意味着你做了一些奇怪的事情,而且可能是错误的。在堆上分配的对象(即使用new)也应该是释放所述对象的对象。

编辑:我忘了添加:注意basetype是第一个被创建的,但最后要被销毁。虚拟对象的破坏顺序与它们的创建方式相反。