类和动态内存分配

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

第12章类和动态内存分配

12.1 动态内存和类

C++使用new和delete运算符来动态控制内存。遗憾的是,在类中使用这些运算符导致许多编程问题。在这种情况下,析构函数将是必不可少的。

12.1.1 复习实例和静态成员

注意点:

●使用char指针来表示姓名。意味着类声明本身没有为字符串分配存储空间,而是在构

造函数中使用new来为字符串分配空间。避免了在类声明中预先定义字符串的长度。

●将num_strings成员声明为静态存储类。特点:无论创建了多少对象,程序只创建一个

静态变量副本。

注:

Stringbad sailor = sports; 等价于Stringbad sailor = Stringbad(sports);

Stringbad(constStringbad&);

当使用一个对象来初始化另外一个对象时,编译器将自动生成上述构造函数(复制构造函数即拷贝构造函数)

12.1.2 特殊成员函数C++提供了下面这些成员函数

●默认构造函数(如果没有定义构造函数)

●默认析构函数

●复制构造函数

●赋值运算符

●地址运算符

C++11移动构造函数与移动赋值运算符(第18章)

1 默认构造函数

Klunk::Klunk(){}不接受任何参数,也不执行任何操作。原因:创建对象时,总会调用构造函数。

Klunk::Klunk(){ klunk_ct = 0; } 不接受任何参数,但可以用来设定特定的值。

Klunk(int n = 10) {klunk_ct = 0;} 带参数的默认构造函数,只要所有的参数都有默认值。

2 复制构造函数

复制构造函数用于将一个对象复制到新创建的对象中。用于初始化过程中(包括按值传递参数)。类的复制构造函数原型如下:

Class_name(constClass_name&); Stringbad(constStringbad&);

何时调用复制构造函数?(每当程序生成对象副本的时候,复制构造函数将被调用)新建一个对象并将其初始化为同类现有对象时,复制构造函数将被调用。下面四种情况均会调用复制构造函数。

Stringbad ditto(motto);

Stringbadmetoo = motto;

Stringbad also = Stringbad(motto);

Stringbad* pStringbad = new Stringbad(motto);使用motto初始化一个匿名对象,并将新对象的地址赋值给pStringbad指针。

默认的复制构造函数有什么功能?

默认的复制构造函数租个复制非静态的成员(成员复制称为浅复制),复制的是成员的值。

12.1.3回到Stringbad: 复制构造函数哪里出了问题

默认的复制构造函数不说明其行为,也不指出创建过程,也不增加num_strings的值。

Callme2()和sailor初始化为对象sports的时候,默认构造函数被调用两次,但是num_strings没有计数,但是调用析构函数的时候,会对其进行计数。解决办法:StringBad::StringBad( const String & s)

{

Num_strings++;

}

字符串出现乱码,原因在于隐式复制构造函数是按值复制,sailor.str = sport.str; 复制的是地址(指针),并不是字符串,即两个指向同一个字符串的指针。在执行delete[] sailor.str 时候,析构函数释放的是这个指针指向的内存(内容),所以在之后执行delete[] sport.str 的时候,导致不确定有害的后果。内存管理不善的表现。

深拷贝

Stringbad::Stringbad(constStringbad&st)

{num_string++; len = st.len; str = new char[len+1];

Std::strcpy(str, st.str);

Cout<

}

12.1.4 Stringbad的其他问题:赋值运算符(解决办法)

Stringbad&Stringbad::operator=(constStringbad&);

默认的赋值运算符也是进行的浅复制,不同指针指向同一个数据,在调用第二个指针的析构函数的时候,原来的数据已经遭到破坏,所以会出现乱码,这时候就需要进行深度复制。解决办法是提供赋值运算符定义(进行深度复制),其实现与复制构造函数类似,但有一些差别。

注意以下三点:

●由于目标对象可能引用了以前分配的数据,所以函数应使用delete[]来解释这些数据●函数应避免将对象赋值给自身;否则,给对象重新赋值前,释放内存操作可能删除对象

的内容。

●函数返回一个指向调用对象的引用。

12.2改进后的新String 类 1.默认构造函数(定义为空指针) String:: String() { Len = 0;

Str = new char[1];为了与析构函数中的delete[] 配合使用。所以不是newchar Str[0] = …\0‟;

}

Str = 0;表示空指针 C++11中,str = nullptr; 2.比较成员函数(主要是字符串的比较使用strcmp()) { If (std::strcmp(st1.str , st2.str) < 0) Return true;

Else

Return false;

}

相关文档
最新文档