条约5:了解C++默认编写并调用哪些函数
条款5:了解C++默认编写并调用哪些函数
条款5:了解C++默认编写并调用哪些函数
1、空类
空类本来是没有存储空间,但为了能在内存中找到该类,编译器为该类添加一个char类型的成员,用来唯一标识该类在内存的位置
编译器为空类自定义哪些函数,这些函数都是public并且inline
①默认构造函数
②默认析构函数
③默认拷贝构造函数
④默认拷贝赋值函数
2、默认构造函数
当我们自定义构造函数,编译器就不会为我们定义一个缺省构造函数
3、默认析构函数
只有当基类定义virtual析构函数,继承的derive class才默认具有虚属性,条款7会详细介绍。
4、默认拷贝构造函数
C++中对象的复制就如同“克隆”,用一个已有的对象快速地复制出多个完全相同的对象。一般而言,以下三种情况都会使用到对象的复制:
①建立一个新对象,并用另一个同类的已有对象对新对象进行初始化
②当函数的参数为类的对象时,这时调用此函数时使用的是值传递,也会产生对象的复制;
③函数的返回值是类的对象时,在函数调用结束时,需要将函数中的对象复制一个临时对象并传给改函数的调用处。
①建立一个新对象,并用另一个同类的已有对象对新对象进行初始化
②当函数的参数为类的对象时,这时调用此函数时使用的是值传递,也会产生对象的复制;
③函数的返回值是类的对象时,在函数调用结束时,需要将函数中的对象复制一个临时对象并传给改函数的调用处。
默认拷贝构造函数仅仅使用“老对象”的数据成员的值对“新对象”的数据成员一一进行赋值
class Book { private: std::string m_name; int m_id; }; Book s1; Book s2 = s1; //调用编译器的拷贝构造函数,复制一本书 //编译器为我们生成的拷贝构造函数 Book(const Book &r) { this->m_name = r.m_name; //调用string类的拷贝构造函数完成 this->m_id = r.m_id; }
类中有静态成员
如果让一个静态成员统计该种书的数量会是什么情况呢?
class Book { public: <span style="white-space:pre"> </span>Book() {++m_iCount;} <span style="white-space:pre"> </span>~Book() {--m_iCount;} private: <span style="white-space:pre"> </span>std::string m_name; <span style="white-space:pre"> </span>int m_id; <span style="white-space:pre"> </span>static int m_iCount; };那么不管我们复制多少本书,最终计数还是1,而且析构书时,计数变成负数
类中有动态数据成员
浅拷贝
所谓浅拷贝,指的是在对象复制时,只是对对象中的数据成员进行简单的赋值,上面的例子都是属于浅拷贝的情况,默认拷贝构造函数执行的也是浅拷贝。但是一旦对象存在了动态成员,那么浅拷贝就会出问题。
class Book { public: Book(const char *name, const int id) :m_id(id) { m_name = new char[strlen(name) + 1]; strcpy(this->m_name, name); } ~Book() { if (m_name != NULL) delete[] m_name; m_name = NULL; //可防止同一个对象内存被释放两次 } private: char *m_name; const int m_id; };
Book s1("match", 1); Book s2 = s1;s2调用默认拷贝构造函数,s2.m_name与s1.m_name指向同一个内存区域,即任意一个对值m_name的操作都会影响到另一个,而且还可能导致同一块内存被释放两次.这种情况,需要“深拷贝”来解决。
深拷贝
深拷贝就不是简单的赋值,而且重新分配一块空间,这就需要我们自定义拷贝构造函数和拷贝赋值函数。
在Book类中定义拷贝构造函数:
Book(const Book & book):m_id(book.m_id) { this->m_name = new char[strlen(book.m_name) + 1]; strcpy(this->m_name, book.m_name); }
5、默认拷贝赋值函数
class Book { public: Book(std::string &name, const int id) :m_name(name), m_id(id) { } ~Book() {} private: std::string &m_name; const int m_id; };调用
std::string str1 = "match"; std::string str2 = "telno"; Book s1(str1, 1); Book s2(str2, 2); s2 = s1;s2调用默认拷贝赋值函数,但赋值函数是对每一个成员赋值,类中有const和引用成员,在C++中是不允许重新赋值的,编译器会报错,因此在类中有引用成员和常量成员,需要自定义赋值函数,或者禁用它,下个条款说明。
- 1楼u011585341昨天 17:11
- 博主不错,总结得很好,比较容易理解
- Re: hualicuan昨天 20:34
- 谢谢