当类包括复制构造函数和赋值运算符时继承的行为

Behaviour of Inheritance when class includes copy constructor and assignment operator

本文关键字:继承 赋值运算符 包括 复制 构造函数      更新时间:2023-10-16

我无法理解这种行为。我有一个a级,

class A
{
public:
int ch;
char *s;
A()
{}
A(char *st):ch(0)
{
    s = new char[10];
    strcpy(s,st);
}
A(const A& rhs):ch(rhs.ch)
{
    s = new char[strlen(rhs.s)+1];
    strcpy(s,rhs.s);
}
const A& operator=(const A& rhs)
{
    char *temp = new char[strlen(rhs.s)+1];
    strcpy(temp,rhs.s);
    delete[] s;
    s=temp;
    ch = rhs.ch;
    return *this;
}
~A()
{
    delete []s;
}
};

在这之前,一切都按预期进行,我能够测试我的复制构造函数和赋值运算符,它们工作正常。

现在我创建了一个子类B,并且我得到了堆损坏错误。我不明白,这是与A类析构函数有关的问题吗?下面是我的B级

class B:public A
{
public:
int a;
B():a(0){}
};

A的默认构造函数不会初始化成员s(指针(:

A()
{}

因此,当使用此构造函数构造元素时,当析构函数删除未初始化的元素时,会发生崩溃:

~A()
{
  delete []s;
}

B使用A的默认构造函数,因此会触发此问题。通过正确初始化默认构造函数中的所有成员来避免它:

A() : ch(), s(0)
{ }

要解决您的问题,您所需要做的就是替换:

char *s;

带有

std::string s;

只需通过char *摆脱手动内存管理,这正是C++为您提供std::string的原因。

可能是什么问题

您的默认构造函数不接受任何参数,不进行动态分配
如果您通过此构造函数创建类对象,那么您的析构函数最终会delete返回一个未分配给new的指针,从而导致Undefined Behavior。

在析构函数中,您delete[] s;,但在默认构造函数中,您没有new[] ed s。事实上,您甚至还没有初始化s

实例化派生类时会调用基类的默认构造函数,因为您没有初始化基类(: A(...)(。因此,你不知道你要删除什么,甚至不知道你明天早餐要吃什么,因为这是未定义的行为。

为了保持一致,new[]在默认构造函数中。为了避免头痛,我建议使用类似std::string的内容,而不是字符指针。