C++ 将基类的状态升级为继承类的全新实例
我想获取一个使用基类构造函数创建的C++ 将基类的状态升级为继承类的全新实例,c++,inheritance,memory-management,C++,Inheritance,Memory Management,我想获取一个使用基类构造函数创建的BaseClass实例,并将其升级为Inherited实例。我知道继承的类需要为其分配单独的内存块,并且应该释放原始基类实例 这是一个(似乎)有效的例子 class BaseClass{ public: BaseClass(int mem1, int mem2){ this->mem1 = mem1; this->mem2 = mem2; } BaseClass(BaseClass* base
BaseClass
实例,并将其升级为Inherited
实例。我知道继承的类需要为其分配单独的内存块,并且应该释放原始基类实例
这是一个(似乎)有效的例子
class BaseClass{
public:
BaseClass(int mem1, int mem2){
this->mem1 = mem1;
this->mem2 = mem2;
}
BaseClass(BaseClass* base){
this->mem1 = base->mem1;
this->mem2 = base->mem2;
}
virtual ~BaseClass(){
printf("Deconstruct Base\n");
}
private:
int mem1;
int mem2;
};
class Inherited: public BaseClass{
public:
Inherited(int mem1, int mem2, int mem3): BaseClass(mem1, mem2){
this->mem3 = mem3;
}
Inherited(BaseClass* base, int mem3): BaseClass(base){
this->mem3 = mem3;
free(base); // this doesn't print 'Deconstruct Base'
}
~Inherited(){
printf("Deconstruct Inherited\n");
}
int mem3;
};
int main(){
BaseClass* p = new BaseClass(1, 2);
p = new Inherited(p, 3);
// this prints 'Deconstruct Inherited' then 'Deconstruct Base'
delete p;
}
因此,在继承类的构造函数中,我使用free
释放BaseClass
的原始实例的内存
这样做的目的是,如果BaseClass
有一个指向一大块动态分配内存的指针,我希望继承的类拾取该指针,而不是让基类释放它
我的问题是:
这会因为任何原因泄漏内存吗
有没有更干净的方法?(例如:调用
操作符delete
会比免费的更好吗?或者完全有更好的解决方案吗?您无法更改对象的类型,因此很难知道“升级对象”的含义。但从代码来看,它或多或少是“将原始对象中的数据复制到新对象中,并除去原始对象”。这很简单:
class base {
public:
base(int m) : mem1(m) {}
base(const base&) = default;
private:
int mem1;
};
class derived : public base {
public:
derived(int m1, int m2) : base(m1), mem2(m2) {}
derived(const base* b, int m2) : base(*b), mem2(m2) {}
private:
int m2;
};
base* bp = new base(3);
base* temp = bp;
bp = new derived(temp, 4);
delete temp;
如果太冗长,可以使用描述性名称编写函数:
void replace_object(base*& bp, int m2) {
base* temp = bp;
bp = new derived(temp, m2);
delete temp;
}
现在你可以写作了
base* bp = new base(3);
replace_object(bp, 4);
base* bp = new base(3);
bp = new derived(bp, 4);
如果您真的非常想隐藏所有这些东西(维护人员会讨厌您),您可以在派生的的构造函数中执行删除操作:
derived(const base* b, int m2) : base(*b), mem2(m2) {
delete b;
}
现在你可以写作了
base* bp = new base(3);
replace_object(bp, 4);
base* bp = new base(3);
bp = new derived(bp, 4);
你的代码有很多问题
我建议您阅读Sutter中有关编写优秀代码的书籍,如Exception C++
第1期:在适当的时候使用初始化列表
BaseClass(int mem1, int mem2)
: mem1(mem1)
, mem2(mem2)
{
}
Inherited(int mem1, int mem2, int mem3)
: BaseClass(mem1, mem2)
, mem3(mem3)
{
}
这对于用户定义的类型和
不支持赋值(常量和引用)的类型
成员等)
始终在其他声明中初始化这些成员
第2期:定义标准副本构造函数(而不是您自己的变体)
甚至更好。在这种情况下,可以使用默认的复制构造函数
BaseClass(const BaseClass &other) = default;
Inherited(const BaseClass &b, int m3)
: BaseClass(b)
, mem3(m3)
{
}
问题3:如果定义复制构造函数,还应定义赋值运算符
BaseClass& operator=(const BaseClass &other) = default;
您还可以根据需要定义移动构造函数和赋值
第4期:您不应该对分配了new
的对象调用free
问题5:在大多数情况下,您应该避免通过构造函数转移所有权
BaseClass(const BaseClass &other) = default;
Inherited(const BaseClass &b, int m3)
: BaseClass(b)
, mem3(m3)
{
}
这很容易出错,因为这不是用户所期望的。这使得代码更难维护,如果您不小心,如果构造函数抛出异常,这可能是内存泄漏的来源
BaseClass(const BaseClass &other) = default;
Inherited(const BaseClass &b, int m3)
: BaseClass(b)
, mem3(m3)
{
}
第6期:如果您真的想转移所有权,那么您应该使用std::unique\u ptr
来明确您正在转移所有权
Inherited(std::uniquer_ptr<BaseClass> b, int m3)
: BaseClass(*b)
, mem3(m3)
{
}
如果以后不再需要b
,您也可以编写如下内容:
std::unique_ptr<BaseClass> p = std::make_unique<BaseClass>(1, 2);
std::unique_ptr<Inherited> q = std::make_unique<Inherited>(std::move(p), 3);
// at this point, p is null since ownership has been moved
p = q;
Inherited i2(Base(1, 2), 3);
在这一点上,为什么不写:
Inherited i3(1, 2, 3);
第8期:在升级对象类型时不存在此类问题。您只需将新值分配给基于旧对象的指针
实际上替换一个对象会导致对象切片。调用free
而不是delete
是未定义的行为,但您应该使用智能指针。每个新的都需要delete
@Quentin有关free
调用的良好信息,但我不认为我在寻找聪明的指针。我修改了问题,详细说明了我不希望解构器在升级时调用基类
。这里最重要的问题是为什么要使用原始指针和新建
/删除
?没有任何东西可以升级对象。您可以做的是您已经尝试过的,从基类
构造一个继承的
。试图在构造函数中混合内存清理看起来非常糟糕。使用智能指针。这里有很多设计问题。首先,构造表单BaseClass常量&
和BaseClass&
而不是BaseClass*
。另外,我想知道为什么BaseClass
甚至有任何公共构造函数。感谢您深思熟虑的回答。我真的不喜欢从派生的构造函数中删除b
的建议。这很容易出错。如果你想转移所有权,就应该使用std::unique_ptr
。@Phil1970——这就是为什么我在介绍时说“如果你真的,真的想隐藏所有这些东西(维护者会讨厌你)…”。