c++ primer plus第十二章-动态内存和类、复制构造函数

c++ primer plus第十二章-动态内存和类,复制构造函数

1)类声明没有为字符串本身分配存储空间,而是在构造函数中使用new来为字符串分配空间。这避免了在类声明中预先定义字符串的长度。


2)静态成员有一个特点,无论创建多少个对象,程序都是只创建一个静态变量副本。也就是说,类的所有对象共享一个静态成员,就像家中的电话可供全部人使用一样。

而且不能在类声明中初始化静态成员变量,这是因为声明描述了如何分配内存,但并不分配内存。对于静态成员,可以在类声明之外使用单独的语句来进行初始化,这是因为静态类成员是单独存储的,而不是对象的组成部分。而且要注意:初始化语句指出了类型,并使用了作用域运算符,但没有使用关键字static。


3)注意:静态数据成员在类声明中声明,在包含类方法的文件中初始化。初始化时使用作用域运算符来指出静态成员所属的类。但如果静态成员是const整数类型或枚举类型,则可以在类声明中初始化。


4)默认构造函数:编译器将提供一个不接受任何参数,也不执行任何操作的构造函数(默认的默认构造函数),这是因为创建对象时总会调用构造函数。

Klunk::Klunk(){ }

带参数的构造函数也可以是默认构造函数,只要所有参数都有默认值。

Klunk(int n=0 ){ klunk_ct = n; }

但是只能有一个默认构造函数。


5)复制构造函数:用于将一个对象复制到新创建的对象中。也就是说,它用于初始化过程中(包括按值传递参数),而不是常规的赋值过程中。类的复制构造函数的原型如下:

Class_name( const Class_name &);

它接受一个指向类对象的常量引用作为参数。

StringBad(const StringBad &);


6)对于复制构造函数,需要知道两点:何时调用和有何作用


7)新建一个对象并将其初始化为同类现有对象时,复制构造函数都将被调用。最常见的情况是将新对象显式地初始化为现有的对象。

StringBad motto;   //motto为StringBad对象

StringBad ditto(motto);   //新建对象,初始化为motto

StringBad metto = motto;   //新建对象,初始化为motto

StringBad also = StringBad(motto);  //新建对象,初始化为motto

StringBad *pStringBad = new StringBad(motto);  //新建指向对象的指针,指向motto内存的地址


上面4种声明都将调用复制构造函数StringBad(const StringBad &);


8)每当程序生成了对象副本时,编译器都将使用复制构造函数。具体地说,当函数按值传递对象或函数返回对象时,都将使用复制构造函数。按值传递意味着创建原始变量的一个副本。编译器生成临时对象时,也将使用复制构造函数。

由于按值传递对象将调用复制构造函数,因此应该按引用传递对象,这样可以节省调用构造函数的时间以及存储新对象的空间。


9)默认的复制构造函数的功能:逐个复制非静态成员(成员复制也称为浅复制),复制的是成员的值。如果成员本身就是类对象,则将使用这个类的复制构造函数来复制成员对象。静态函数不受影响,因为它是属于整个类,而不是各个对象。


10)解决类中这种尝试两次释放内存的问题的方法是进行深度复制。也就是说,复制构造函数应当复制字符串并将副本的地址赋给新new内存成员,而不仅仅是复制字符串地址。这样每个对象都有自己的字符串,而不是引用另一个对象的字符串。调用析构函数时都将释放不同的字符串,而不会试图去释放已经被释放的字符串。


11)警告:如果类中包含了使用new初始化的指针成员,应当定义一个复制构造函数,以复制指向的数据,而不是指针,这被称为深度复制。复制的另一种形式(成员复制或浅复制)只是复制指针值。浅复制只是浅浅地复制指针信息,而不会深入挖掘以复制指针引用的结构。


12)赋值运算符:类对象赋值,通过自动为类重载赋值运算符来实现的。

Class_name & Class_name :: operator=(const Class_name &);

它接受并返回一个指向类对象的引用。

将已有的对象赋给另一个对象时,将使用重载的赋值运算符。

StringBad headline1("Celery Stalks at Midnight");

StringBad knot;

knot = headline1;


13)解决赋值的问题:

由于目标对象可能引用了以前分配的数据,所以函数应使用delete[]来释放这些数据。

函数应当避免将对象赋给自身;否则,给对象重新赋值前,释放内存操作可能删除对象的内容。

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

StringBad & StringBad::operator=(const StringBad & st)

{

if(this==&st)  //避免对象赋给自身

return *this;

delete [] str;   //释放旧的内存数据

len = st.len;   //

str= new char [len+1];  //获得新的内存字符串

std::strcpy(str,st.str);   //复制字符串

return *this;

}


14)空指针:字面值0有两个含义:可以表示数字值零,也可以表示空指针。有些程序员使用(void *)0来标识空指针(空指针本身的内部表示可能不是零),也有人使用NULL,这是一个表示空指针的C语言宏。C++11引入了新关键字nullptr,用于表示空指针。

str=nullptr;


15)静态成员函数:可以将成员函数声明为静态的(函数声明必须包含关键字static,但如果函数定义是独立的,则其中不能包含关键字static)。

首先,不能通过对象调用静态成员函数,实际上,静态成员函数甚至不能使用this指针。如果静态成员函数是在公有部分声明的,则可以使用类名和作用域解析运算符来调用它。

其次,由于静态成员函数不与特定的对象相关联,因此只能使用静态数据成员。也可以使用静态成员函数设置类级标记,以控制某些类接口的行为。


16)

你可能感兴趣的:(C++,C语言)