OOP笔记 —— 拷贝构造函数(Copy Constructor)

使用Copy Constructor的目的:

用一个已经存在的对象去初始化一个新创建的对象

eg: Book book3(book1);

也等同于:Book book3 = book1;

关于Copy Constructor很重要的一点:

和默认构造函数、默认析构函数一样,拷贝构造函数也有C++自动创建的 默认拷贝构造函数(Default copy constructor)。但是,只要涉及到指针、动态内存分配,就必须要自己定义copy constructor了【这个注意点和析构函数一样】,否则会报错

比如下面这个class:

class Book {
public:
    string title;
    float * rates;
    int ratesCount;

    Book(string inputTitle) {
        title = inputTitle;
        ratesCount = 2;
        rates = new float[ratesCount];
        rates[0] = 4; //hard code the array just for examples
        rates[1] = 5;
    }

    ~Book(){
        delete[] rates;
        rates = nullptr;
    }
};


//main中定义了一个对象,并通过拷贝构造函数给另一个对象初始化
Book book1("Millionaire Fastlane");
Book book3(book1);

创建Copy Constructor需要注意的几点:

  1. 是class中的public member function
  2. 无返回值
  3. 和class名一样
  4. 只接受一个参数,并且参数也是该class类型的
  5. 参数是通过call-by-reference传递的,并且是const的

关于第5点的详细解释:

需要call-by-reference的原因:值传递会产生逻辑错误。如果是通过值传递(call-by-value)的,那么意味着是将原来的对象拷贝了一份给拷贝构造函数,这里就发生了一个逻辑错误,因为如果通过值传递拷贝对象给函数,那么首先就先得有一个拷贝构造函数了,而我们现在就是在自行创建copy constructor。因此需要通过call-by-reference(&)来给copy constructor传参。

需要加const的原因:由于是call-by-reference了,所以函数就可能会改变原对象的成员属性值,因此要加上const,确保传过来的对象在函数中是一个constant,函数不会改变它的属性。

根据以上的注意事项,写出了下面的copy constructor,但还是会报错:

Book(const Book& original) {

        title = original.title;

        rates = original.rates; // 这里有Error

        ratesCount = original.ratesCount;

}

报错原因:由指针引起,在调用析构函数时产生错误。

rates是一个指针,它指向的动态内存(rates[0]和rates[1]所占的内存),在book1调用析构函数时,被释放了。而上面错误写法的拷贝构造函数中,是把book1的指针变量直接赋给book3,所以book3的rates指针也指向同一块内存(rates[0]和rates[1]在被释放之前所占的内存)。在book3调用析构函数时,delete的是一块已经被释放的内存,因此报错。

涉及到拷贝动态内存的解决方法:

在拷贝构造函数中,分配一块新的动态内存,将需要拷贝的数组的值通过遍历循环,拷贝给新的内存。

Book(const Book& original) {

        title = original.title;
        ratesCount = original.ratesCount;
        
        rates = new float[ratesCount];
        for (int i = 0; i < ratesCount; i++) {
            rates[i] = original.rates[i];
        }
}

需要调用Copy Constructor的情况:

1.  用一个已经存在的对象去初始化一个新创建的对象

eg: Book book3(book1);

或者:Book book3 = book1; // 【注意与assignment operator的区分】

copy constructor与assignment operator的区分

用已存在对象初始化一个新创建的对象,是调用了拷贝构造函数。

用已存在对象去给另一个已被初始化过的值重新赋值,才是assignment operator,比如:book3 = book2;

2.  当编译器创建临时对象时

①  函数通过对象的值传参(call-by-value),此时compiler会创建一个对象的副本,调用拷贝构造函数

② 函数返回值为对象(且返回的也是对象的value,而不是address),此时compiler也会创建一个临时对象(即对象的副本),调用拷贝构造函数。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值