拷贝 赋值 析构
拷贝构造函数
\(如果一个构造函数的第一个参数是自身类类型的引用,且任何额外参数都有默认值,则为拷贝构造函数.\)
class Foo {
public:
Foo(); // 默认构造函数
Foo(const Foo &); // 拷贝构造函数
}
\(拷贝构造在几种情况下都会被隐式使用,因此不应该用explicit.\)
\(拷贝构造的第一个参数必须是一个引用类型:\\如果不是引用类型,调用永远不会成功-为了调用拷贝构造函数,必须拷贝实参,为了拷贝实参,又得调拷贝构造,无限循环.\)
合成拷贝构造函数
\(编译器默认定义,即使定义了其他构造函数,编译器也会为我们合成一个拷贝构造函数.\)
拷贝初始化
string dots(10, '.'); // 直接初始化
string s(dots); // 直接初始化
sring s2 = dots; // 拷贝初始化
string null_book = "99-99-88" // 拷贝初始化
string nines = string(100, '9') // 拷贝初始化
\(选择直接初始化时,实际上是要求编译器使用普通得函数匹配来选择与提供参数匹配得构造函数.\\使用拷贝初始化,要求编译器将右侧运算对象拷贝到正在创建的对象中,如果需要的还要进行类型替换.\)
\(拷贝初始化不仅在用=定义变量时发生,在下列情况也会发生:\)
- \(将一个对象作为实参传递给一个非引用类型的形参.\)
- \(从一个返回类型为非引用类型的函数返回一个对象.\)
- \(用花括号列表初始化一个数组中的元素或哟个聚合类中的成员.\)
拷贝赋值运算符
\(与类控制其对象如何初始化一样,类也可以控制其对象如何赋值:\)
Sales_date trans, accum;
tnas = accum; // 使用拷贝赋值运算符
\(如果类未定义自已的拷贝赋值运算符,编译器会为它合成一个.\)
重载赋值运算符
\(重载运算符的参数表示运算符的运算对象.如果运算符是一个成员函数,\\其左侧运算对象就绑定到隐式的this参数.\)
class Foo {
public:
Foo& operator = (const Foo &); // 赋值运算符
}
\(赋值运算符通常应该返回一个指向其左侧运算对象的引用.\)
合成拷贝赋值运算符
\(如果一个类未定义自已的拷贝赋值运算符,编译器会为它生成一个合成拷贝赋值运算符\)
\(它会将右侧运算对象的每个非static成员赋予左侧运算成员的对应成员,\\这一工作通过拷贝赋值符完成,对于数值类型成员,逐个赋值数组元素.合成拷贝赋值运算符返回一个指向其左侧运算对象的引用.\)
析构函数
\(析构函数释放对象使用的资源,并销毁对象的非static数据成员.\)
\(析构函数是类的一个成员函数,名字由波浪号加类名组成,无返回值,不接受参数\)
\(由于不接受参数,析构函数一个类只有一个,无法重载.\)
\(析构部分是隐式的.成员销毁时发生完全依赖于成员的类型.\\销毁类类型的成员需要执行成员自已的析构函数.\\内置类型没有析构函数,因此销毁内置类型成员什么也不需要做.\)
\(隐式销毁一个内置指针类型的成员不会delete它所指的对象.\)
\(智能指针具有析构函数,与普通指针不同,智能指针成员在析构阶段会被自动销毁.\)
什么时候会调用析构函数
\(无论何时一个对象被销毁,就会自动调用其析构函数:\)
- \(变量在离开其作用域时.\)
- \(当一个对象被销毁时,其成员被销毁.\)
- \(容器(无论是标准库还是数组)被销毁时,其元素被销毁.\)
- \(对于动态分配的对象,当对指向它的指针应用delete运算符时被销毁.\)
- \(对于临时变量,创建它的完整表达式结束时被销毁.\)
\(当一个对象的引用或指针离开作用域时,析构函数不会执行.\)
合成析构函数
\(一个类未定义自已的析构函数时,编译器会为它定义一个合成析构函数.\)
\(析构函数体自身并不直接销毁成员.成员在析构函数体之后隐含的析构阶段被销毁.\\在整个对象销毁过程中,析构函数体是作为成员销毁步骤之外的另一部分进行.\)