1 拷贝构造函数
如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数。
class Test
{
public:
Test() = default;
TEst(int m_x): m_x(x) { }
Test(const Test &); //拷贝构造函数
private:
int m_x;
};
void runTest()
{
Test t1; //合成构造函数
Test t2(5); //直接初始化
Test t3(t2); //直接初始化,调用的也是拷贝构造函数
Test t4 = t3; //拷贝初始化
}
以下几种情况将会出现 拷贝初始化:
- 使用=定义变量时。
Test t1;
Test t2 = t1;
- 将一个对象作为实参传递给一个非引用类型的形参,即以值传递的方式。
void func(Test t);
Test t(5);
func(t); //值传递方式,调用了Test的拷贝构造函数
- 从一个返回类型为非引用类型的函数返回一个对象。
Test func()
{
Test t;
return t;
}
Test t1 = func(); //值传递方式,调用了Test的拷贝构造函数
- 用花括号列表初始化一个数组中的元素或一个聚合类中的成员。
2 拷贝赋值函数
当用一个类的对象为另一个对象赋值时,会调用拷贝赋值函数。
拷贝赋值函数需要重载 =运算符,该函数通常返回一个指向其左侧运算对象的引用。其原因是为了能够连续赋值。
如果类没有定义拷贝赋值函数,编译器会为它生成一个合成拷贝构造赋值运算符。
class Foo
{
public:
Foo &operator=(const Foo&); //赋值运算符
...
};
Foo f1;
Foo f2;
f2 = f1; //调用拷贝赋值函数
3 析构函数
构造函数:初始化对象的非static数据成员。
析构函数:释放对象使用的资源,并销毁对象的非static数据成员。
在一个析构函数中,首先执行函数体,然后销毁对象。成员按初始化顺序的逆序销毁。
何时调用析构函数:
无论何时一个对象被销毁,就会自动调用其析构函数:
- 变量离开其作用域是被销毁。
- 当一个对象被销毁时,其成员被销毁。
- 容器(无论是标准容器还是数组)被销毁时,其元素被销毁。
- 对动态分配的对象,当对指向它的指正应用delete运算符时被销毁。
- 对于临时对象,当创建它的完整表达式结束时被销毁。
下面是各种构造函数,拷贝构造函数,拷贝复制函数,析构函数调用时机的例子:
struct X{
X() {std::cout << "X()" << endl; }
X(const X& x) {cout << "X(const X&)" << endl;}
X& operator=(const X&){ cout << "X &operator=(const &x)" << endl;}
~X() {cout << "~X()" << endl;}
};
void func1(struct X x1, struct X &x2) //引用和非引用作为形参
{
}
X func2(X &x1) //对象值作为返回
{
X x(x1);
return x;
}
X &func3(X x) //引用作为返回
{
X x1(x);
return x1;
}
int main()
{
cout << "begin " << endl;
{
X x1;
X *px1 = new X();
X x2 = x1; //拷贝初始化
X x3;
x3 = x1; //拷贝赋值
X x4(x1); //直接初始化
delete px1;
}
cout << "end!!\n" << endl;
//作为容器元素
cout << "vector" << endl;
{
vector<X> vx; //竟然没有进行初始化
vx.push_back(X());
vx.push_back(X());
// vector<X> vx2(vx);
// vector<X> vx2(10);
}
cout << "vector end\n" << endl;
//函数调用
cout << "func begin" << endl;
{
X x1;
X *px1 = new X();
func1(x1, *px1);
X x2 = func2(x1); //直接接一个返回
X x3;
x3 = func2(x1);
X x4 = func3(x1);
X x5;
x5 = func3(x1);
}
cout << "func end!!\n" << endl;
return 0;
}
输出:
begin
X()
X()
X(const X&)
X()
X &operator=(const &x)
X(const X&)
~X()
~X()
~X()
~X()
~X()
end!!
vector
X()
X(const X&)
~X()
X()
X(const X&)
X(const X&)
~X()
~X()
~X()
~X()
vector end
func begin
X()
X()
X(const X&)
~X()
X(const X&)
X()
X(const X&)
X &operator=(const &x)
~X()
X(const X&)
X(const X&)
~X()
X(const X&)
~X()
X()
X(const X&)
X(const X&)
~X()
X &operator=(const &x)
~X()
~X()
~X()
~X()
~X()
~X()
func end!!