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

时间:2013-01-04 08:02:38

标签: c++ inheritance copy-constructor assignment-operator

我无法理解这种行为。我有一个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){}
};

3 个答案:

答案 0 :(得分:3)

要解决您的问题,您只需要替换:

char *s;

std::string s;

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

  

可能是什么问题?

不带任何参数的默认构造函数不进行动态分配 如果您通过此构造函数创建了类对象,则析构函数最终delete指向未使用new分配的指针,从而导致未定义的行为。

答案 1 :(得分:3)

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

实例化派生类时会调用基类的默认构造函数,因为您尚未初始化基类(: A(...))。因此,您不知道自己要删除的内容,甚至是明天的早餐,因为它未定义的行为。

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

答案 2 :(得分:3)

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

A()
{}

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

~A()
{
  delete []s;
}

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

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