装饰器模式中的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
问题是:
为什么不起作用?我在实现析构函数时做错了什么?
我通过删除 ~Decorator()
中的 virtual
关键字并注释掉 ~Derived()
来更改代码,但考虑到我想要我的自定义,这不是一个好的修复Derived
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
您正在删除 Base &base 两次:首先,Derived 的析构函数删除了 this->base,然后 Decorator(父)的析构函数再次删除了 this->base。解决办法就是Decorator应该是唯一删除this->base.
析构函数和构造函数应该始终联姻。在总是(99.99999%)的情况下,如果你在构造函数中 new
ed,你只能在析构函数中 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),也应该是释放该对象的对象。
编辑:我忘了补充:注意基类型是第一个被创建,但最后被销毁的。虚拟对象的销毁顺序与创建顺序相反。
我最近在作业中遇到装饰器模式,想问一下在装饰器中实现析构函数的细节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
问题是:
为什么不起作用?我在实现析构函数时做错了什么?
我通过删除
~Decorator()
中的virtual
关键字并注释掉~Derived()
来更改代码,但考虑到我想要我的自定义,这不是一个好的修复Derived
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
您正在删除 Base &base 两次:首先,Derived 的析构函数删除了 this->base,然后 Decorator(父)的析构函数再次删除了 this->base。解决办法就是Decorator应该是唯一删除this->base.
析构函数和构造函数应该始终联姻。在总是(99.99999%)的情况下,如果你在构造函数中 new
ed,你只能在析构函数中 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),也应该是释放该对象的对象。
编辑:我忘了补充:注意基类型是第一个被创建,但最后被销毁的。虚拟对象的销毁顺序与创建顺序相反。