[C++] 类的设计(2)——拷贝控制(1)

1、一个类通过定义五种特殊的成员函数来控制此类型对象的拷贝、移动、赋值和销毁:拷贝构造函数、拷贝赋值运算符、移动构造函数、移动赋值运算符和析构函数。(拷贝、移动、析构)
 
2、拷贝和移动构造函数定义了当用同类型的另一个对象初始化本对象时做什么;拷贝和移动赋值运算符定义了讲一个对象赋予同类型的另一个对象时做什么;析构函数定义了当此类型对象销毁时做什么。这些操作统称为拷贝控制操作。
 
3、如果一个类没有定义所有这些拷贝控制成员,编译器会自动为它定义缺失的操作。
 
4、拷贝构造函数:构造函数的第一个参数是自身类类型的引用,并且任何额外参数都有默认值。
例子:
class Foo{
          public:
              Foo();//默认构造函数
              Foo(const Foo&);//拷贝构造函数
         }
5、类对象的拷贝初始化和直接初始化:前者使用拷贝构造函数,后者使用普通的函数匹配来选择与提供的参数最匹配的构造函数。除了使用“=”之外,非引用类型参数传递,返回非引用类型的对象等都会使用拷贝初始化。
 
6、拷贝赋值运算符重载了赋值(=)运算符,它的返回类型应该是一个指向其左侧运算对象的引用。
 Foo& operator=(const Foo&);
7、合成拷贝运算符由编译器合成,作用有两个:一是对于某些类用来禁止该类型对象的赋值;而是其他类将右侧运算对象的每个非static成员赋予作则运算对象的成员。下面代码等价于Sales_data的合成拷贝运算符:
   
Sales_data& //返回值
    Sales_data::operator=(const Sales_data &rhs){//参数也是当前对象的引用类型
        bookNo=rhs.bookNo;//调用string::operator=
        units_sold=rhs.units_sold;//使用内置的int赋值
        revenue=rhs.revenue;//使用内置的double赋值
        return *this;//返回一个此对象的引用
    }
 
6、拷贝函数和拷贝赋值运算符:如果一个对象已经定义了,然后给对象赋值,那么就会调用拷贝赋值运算符;如果是用于对象的初始化、非引用类型实参,非引用类型类返回值,那么就调用拷贝构造函数,参见下面的代码:
    1)类定义:
     
class Sales_data {
public:
    Sales_data() = default;
    Sales_data(const string &s, unsigned n, double p):bookNo(s),units_sold(n),revenue(p*n) {
    }
    Sales_data(const string &s):bookNo(s){}

    Sales_data(const Sales_data&);//拷贝构造函数,第一个参数为自身类类型的引用
    Sales_data& operator=(const Sales_data &rhs);//拷贝赋值运算符,返回当前对象的引用,参数为另一个对象的引用
    
    string isbn()const { return bookNo; }
    Sales_data &combine(const Sales_data&);
private:
    double avg_price()const {
        return units_sold ? revenue / units_sold : 0;
    }
    string bookNo;
    unsigned units_sold = 0;
    double revenue = 0.0;
};
Sales_data& Sales_data::combine(const Sales_data &rhs) {
    units_sold += rhs.units_sold;
    revenue += rhs.revenue;
    return *this;
}
/* 拷贝构造函数的定义
** 拷贝构造函数应用于对象的拷贝初始化,函数的非引用参数传递和返回值
** 合成拷贝构造函数作用是阻止某些类的拷贝,或者将参数的成员逐个拷贝到正在创建的对象中
** 要记住它仍然是一个构造函数,是用来构造对象的
*/

Sales_data::Sales_data(const Sales_data &orig):bookNo(orig.bookNo),units_sold(orig.units_sold),revenue(orig.revenue) {
    cout << "这是Sales_data的拷贝构造函数" << endl;
}

/* 拷贝赋值运算符的定义
** 拷贝赋值运算符重载了赋值(=)运算符,在对象发生赋值操作的时候调用
** 合成的拷贝赋值运算符的作用是阻止某些类的赋值,或者将参数的成员赋予左侧运算对象的相应成员
** 返回值是当前对象的引用
*/
Sales_data& Sales_data::operator=(const Sales_data &rhs) {
    cout << "这是Sales_data的拷贝赋值运算符" << endl;
    bookNo = rhs.bookNo;
    units_sold = rhs.units_sold;
    revenue = rhs.revenue;
    return *this;
}
   
    2)main函数
int main() {
    
    Sales_data sales_data_1{ "",0,0 };//直接初始化,花括号
    Sales_data sales_data_2("", 0, 1);//直接初始化,参数匹配
    Sales_data sales_data_3 = sales_data_1;//拷贝初始化
    Sales_data sales_data_4;
    sales_data_4 = sales_data_1;//拷贝赋值运算符

    //如果一个对象已经定义了,然后给对象赋值,那么就会调用拷贝赋值运算符;
    //如果是用于对象的初始化、非引用类型实参,非引用类型类返回值,那么就调用拷贝构造函数。
    return 0;
}

 

posted @ 2018-12-18 16:50  zhizhiyu  阅读(187)  评论(0编辑  收藏  举报