C++筆記(5)拷貝構造函數


拷貝構造函數是一種特殊的構造函數,它在創建對象時,是使用同一類中之前創建的對象來初始化新創建的對象。

如果在類中沒有定義拷貝構造函數,編譯器會自行定義一個。如果類帶有指針變量,並有動態內存分配,則它必須有一個拷貝構造函數。拷貝構造函數的最常見形式如下:

classname (const classname &obj) {
   // 構造函數的主體
}

在這里,obj 是一個對象引用,該對象是用於初始化另一個對象的。

1.拷貝構造函數被調用的三種情況

拷貝構造函數通常用於:

  • 通過使用另一個同類型的對象來初始化新創建的對象。

  • 復制對象把它作為參數傳遞給函數。

  • 復制對象,並從函數返回這個對象。

1)當用一個對象去初始化同類的另一個對象時,會引發復制構造函數被調用。

Point p1 = Point();
//下面的兩條語句都會引發復制構造函數的調用。
Point p2 = Point(p1);
Point p3 = p1;

注意,第二條語句是初始化語句,不是賦值語句。賦值語句的等號左邊是一個早已有定義的變量,賦值語句不會引發復制構造函數的調用。例如:

Point p1 = Point();
Point p3;
p3 = p1;// 賦值語句不會引發復制構造函數的調用

這條語句不會引發拷貝構造函數的調用,因為p3早已生成,已經初始化過了。

2)如果函數Fun的參數是類Point的對象,那么當Fun被調用時,類Point的復制構造函數將被調用。換句話說,作為形參的對象,是用復制構造函數初始化的,而且調用復制構造函數時的參數,就是調用函數時所給的實參。

#include "Point.h"
#include <iostream>
using namespace std;
void Fun(Point p);
int main() {
    Point p1 = Point();
    Fun(p1);
    return 0;
}
void Fun(Point p) {
    cout << "Fun run!\n";
}

運行結果

Copy constructor called!
Fun run!

這是因為Fun函數的形參p在初始化時調用了拷貝構造函數。

從這里也可以看出,函數的形參的值不一定等於實參,這取決於該對象所屬的拷貝構造函數是如何實現的。

以對象作為函數的形參,在函數被調用時,生成的形參要用拷貝構造函數初始化,會帶來時間上的開銷。如果用對象的引用而不是對象作為形參,就沒有這個問題了。但是以引用作為形參有一定的風險,因為這種情況下如果形參的值發生改變,實參的值也會跟着改變。

如果要確保實參的值不會改變,又希望避免復制構造函數帶來的開銷,解決辦法就是將形參聲明為對象的 const 引用。

void Fun(const Point& p);

3) 如果函數的返冋值是類Point的對象,則函數返冋時,類Point的復制構造函數被調用。換言之,作為函數返回值的對象是用復制構造函數初始化的,而調用復制構造函數時的實參,就是 return 語句所返回的對象。

#include "Point.h"
#include <iostream>
using namespace std;
Point Fun();
int main() {
    Fun();
    return 0;
}
Point Fun() {
    cout << "Fun run!\n";
    Point p1 = Point();
    return p1;
}

運行結果:

Fun run!
Copy constructor called!

 

整理自:http://c.biancheng.net/view/151.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM