1. 复制构造函数
(1)复制构造函数具有单个形参,该形参是对该类类型的引用。当定义一个新对象并用一个同类型的对象对它进行初始化时,将显式地调用赋值构造函数。当将该类型的对象传递给函数,或从函数返回该类型的对象时,将隐式使用复制构造函数,得到对象的副本。
(2)复制构造函数可用于
-
根据另一个同类型的对象显式或隐式初始化一个对象
-
复制一个对象,将它作为实参传递给一个函数
-
从函数返回时复制一个对象
-
初始化顺序容器中的元素
-
根据元素初始化式列表初始化数组元素。
(3)对于类类型对象的初始化:直接初始化( A a(...); )直接调用与实参匹配的构造函数,而复制初始化( B b = B(...) ;)总是先使用指定构造函数创建一个临时对象,然后用复制构造函数将那个临时对象复制到正在创建的对象。(注意,b1 = b2 称为赋值,与初始化不同)
(4)当使用表示容量的单个形参n来初始化容器container时,编译器首先调用T类型的默认构造函数创建一个临时值来初始化容器,然后使用复制构造函数将临时值复制到container的每个元素。
(5)当我们没有定义复制构造函数时,编译器会为我们合成一个复制构造函数。它对每个非static数据成员调用复制构造函数进行复制,将新对象初始化为原来的副本。与合成的默认构造函数不同,即使我们定义其他构造函数,编译器也会合成复制构造函数。
(6)类类型成员函数使用该类复制构造函数进行复制。数组成员的复制是个例外,虽然不能复制数组,但一个类如果有数组成员,则合成复制构造函数将复制数组——对数组的每个元素使用复制构造函数进行复制。
(7)只包含类类型成员或内置类型(不包含指针)成员的类,无需显式地定义复制构造函数。拥有指针数据成员的类可能需要显式定义复制构造函数。
(8)为了禁止复制,必须显式地声明复制构造函数为private,如iostream类
2.赋值操作符
(1)重载操作符是一些函数,名字以operator开头,后面跟着操作符号。操作符函数有一个返回值和一个形参表。
(2)赋值是二元操作符,同时它又必须是类的成员函数,因此它有一个形参,对应右操作数,this绑定到指向左操作数的指针。赋值操作符返回对同一类类型的引用。
(3)合成赋值操作符与合成复制构造函数类似:它按声明的顺序逐个给成员赋值,右操作数对象的每个成员赋值给左操作数的每个相应成员。对于数组,给数组每个元素赋值。
(4)一般而言,如果一个类需要赋值构造函数,它也会需要赋值操作符。
3.析构函数
(1)何时调用析构函数? 撤销类对象时自动调用析构函数:a.自动变量在超出作用域时自动撤销 ;b. 动态分配的对象在delete指向它的指针时撤销。
撤销一个容器时(标准库容器或者内置数组),会按逆序逐个运行容器内对象的析构函数,
(2)三法则:如果一个类需要析构函数,则它也需要复制构造函数和赋值操作符
(3)与复制构造函数和赋值操作符 不同 ! 编译器总是会为类合成一个析构函数,它按所有成员创建顺序的逆序调用各成员的析构函数。即使我们编写了自己的析构函数,合成析构函数仍然会在自己编写的析构函数执行完后执行(总会执行一次)!!!
(4)析构函数不能指定任何形参,也不能重载。
(5)继承结构中析构的次序:按照与构造函数相反的次序析构
【TIPS】
ClassA a1 = ClassA("hehe",1); //复制初始化(先调用相应构造函数生成临时对象,再调用复制构造函数将临时对象复制到要生成的对象)
ClassA a2 = "hehe"; //复制初始化(先调用相应构造函数生成临时对象,再调用复制构造函数将临时对象复制到要生成的对象)
ClassA a3 = a2; //复制初始化(调用复制构造函数将a2复制到要生成的对象)
ClassA a4("hehe"); //直接初始化(调用相应构造函数)
ClassA a5; //直接初始化(调用默认构造函数);
a4 = a1; //赋值,调用ClassA的赋值操作函数
a4 = "hehe"; //赋值,先调用相应构造函数生成临时对象,再调用赋值操作函数将临时对象的各成员赋值给要生成的对象
test.cc :
#include
#include
#include
#include "ctest.h"
using namespace std;
void func0(){
list l;
for(int i=0;i<10;i++){
ctest ct(i);
l.push_back(ct);
}
}
void func1(){
vector v;
for(int i=0;i<10;i++){
ctest ct(i);
v.push_back(ct);
}
}
void func2(){
ctest c1(1);
ctest c1_;
c1_ = c1;
}
void func3(){
ctest c1(1);
ctest c1_ = c1;
}
int main(int argc, char **argv) {
}
ctest.h :
#ifndef CTEST_H_
#define CTEST_H_
class ctest {
private :
int i;
public:
ctest();
ctest(int i);
ctest(const ctest &c);
ctest & operator=(const ctest &rv);
virtual ~ctest();
};
#endif /* CTEST_H_ */
ctest.cc
#include "ctest.h"
#include
using namespace std;
ctest::ctest() {
cout<<"construct"<
}
ctest::ctest(int i):i(i){
cout<<"construct ["<
}
ctest::~ctest() {
cout<<"destruct ["<
}
ctest::ctest(const ctest &c):i(c.i){
cout<<"copy-constructor ["<
}
ctest & ctest::operator=(const ctest &rv){
cout<<"assign operator ["<
i = rv.i;
return *this;
}
阅读(424) | 评论(0) | 转发(0) |