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

c++ virtual destructor in decorator pattern

我最近在作业中遇到装饰器模式,想问一下在装饰器中实现析构函数的细节class。

考虑下面的装饰器class

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

在我的派生 class 中 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. 我通过删除 ~Decorator() 中的 virtual 关键字并注释掉 ~Derived() 来更改代码,但考虑到我想要我的自定义,这不是一个好的修复Derived 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

您正在删除 Base &base 两次:首先,Derived 的析构函数删除了 this->base,然后 Decorator(父)的析构函数再次删除了 this->base。解决办法就是Decorator应该是唯一删除this->base.

析构函数和构造函数应该始终联姻。在总是(99.99999%)的情况下,如果你在构造函数中 newed,你只能在析构函数中 delete 某些东西。因为你没有,所以你的代码有问题。采用这个简单的逻辑规则,你的生活会变得更加轻松。

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

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,则为三个),一个基础和一种亚型。简而言之,这两个对象仍然是不同的,尽管您可能另有想法。

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

编辑:我忘了补充:注意基类型是第一个被创建,但最后被销毁的。虚拟对象的销毁顺序与创建顺序相反。