我最近在学校作业中遇到了装饰模式,想询问在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
问题是:
为什么不起作用?我在实现析构函数时做错了什么?
我通过删除virtual
中的~Decorator()
关键字并注释掉~Derived()
来改变代码,但考虑到我希望我的自定义析构函数Derived
,这不是一个好的解决方法1}} class
有没有更好的方法来实现装饰器模式?怎么样?
编辑:
除了我们的任务中提供的内容外,我没有真实的用例。 我们被要求实现一个具有以下功能的文本处理器(装饰器):
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
答案 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是第一个被创建的,但最后要被销毁。虚拟对象的破坏顺序与它们的创建方式相反。