您的位置:首页 > 编程语言 > C语言/C++

C++: 拷贝管理

2015-11-08 04:03 337 查看
《C++ Primer》看到这一章我都惊呆了,C++竟然还能有这种功能:类可以控制该类型对象拷贝、赋值、移动和销毁时做什么。

以上操作通过:拷贝构造函数、移动构造函数、拷贝赋值运算符、移动赋值运算符、以及析构函数构成

拷贝构造函数:

定义: 如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则此构造函数是拷贝构造函数。

本质上是个构造函数,所以它出现就会构造新对象,没有新对象它就没出现。

拷贝构造函数的第一个参数必须是一个引用类型,因为如果是值传递方式穿参的话,会立即再次调用拷贝构造函数,这样就形成无限递归了!危险!

如果我们没有自定义一个拷贝构造函数,编译器会自动帮我们合成一个。默认拷贝构造函数会将其参数成员逐个拷贝到正在创建的对象中。

以下情况会发生拷贝初始化:

1. 用=定义变量。

2. 将一个对象作为实参传递给一个非引用类型的形参。

3. 从一个返回类型为非引用类型的函数返回一个对象。

4. 列表初始化一个数组中的元素或一个聚合类中的成员。

有个小坑是,
A aa = a;
像这样定义并初始化一个A类型的变量aa,只会调用拷贝构造函数,不会调用拷贝赋值运算符。

#include <iostream>
using namespace std;

class A{
public:
A(int i=0):n(i){}

A(A &a, int i=0):n(i){
cout<< a.getI() <<endl;
cout<< getI() <<endl;
cout<<"hello"<<endl;
}

const int getI(){
return n;
}

private:
int n = 0;
};

int main(){
A a(998);
A b = a;//调用拷贝构造函数
//输出结果为:
//998
//0
//hello
//证明 a 被当成了拷贝构造函数的第一个参数
return 0;
}


拷贝赋值运算符

这其实就是个操作符重载。本质上是个名为
operator=
的函数,所有有形参有返回值,有函数体,都有。

当然要成为一个伟大的赋值运算符,当然要付出一点代价:

1. 名字必须是
operator=


2. 必须定义为成员函数

3. 左侧运算对象就绑定到隐式的this参数上

4. 接受一个与其所在类相同类型的参数

5. 为了与内置类型的赋值保持一致,返回指向左侧对象的引用。

如果类没有定义自己的拷贝赋值操作符,编译器会自动生成一个。它会将右侧运算对象的每个非static成员赋予左侧运算对象的对应成员。

#include <iostream>
using namespace std;

class A{
public:
A(int i=0):n(i){}

A(A &a, int i=0):n(i){
cout<< a.getI() <<endl;
cout<< getI() <<endl;
cout<<"hello"<<endl;
}

A &operator=(const A &r){
n = r.n;
cout<<"copying..."<<endl;
return *this;
}

const int getI(){
return n;
}

private:
int n = 0;
};

int main(){
A a(998);
A b(333);
b = a;
cout<< b.getI()<<endl;
//copying...
//998
return 0;
}


析构函数:

析构函数释放对象使用的资源,并销毁对象的非static数据成员。

跟构造函数一样的是:没有返回类型,如果没自定义,编译器就会生成一个默认的。

跟构造函数不一样的是:没有构造函数初始化列表,名字是类名前加一个波浪号~,析构函数不接受参数,所以不能被重载,不能定义为delete。

note:析构函数先执行函数体,然后销毁成员,顺序按初始化的逆序。销毁一个内置类型的指针不会delete它指向的对象。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: