Know what functions C++ silently and calls
今天繼續學習一個條款,看到了本條款,讓我更加瞭解了C++的一些內部運行機理,思考了一番,覺得C++在這方面設計真的十分嚴密,不虧是一個很優秀的語言,讓C++一直是很受歡迎的語言。閑話少說。 每一個class都會有一個或多個建構函式、一個解構函式、一個copy assignment操作符。這些控制著基礎操作,像是產出新對象並確保它被初始化、擺脫舊對象並確保它被適當清理、以及賦予對象新值。 那麼當你當你編寫了一個empty class的時候,當你利用編譯器的對代碼進行處理的時候,它其實已經並非是一個empty class 了。編譯器會悄悄的給你產生了
default 建構函式、一個解構函式、一個copy建構函式和一個copy assignment操作符,並且它們都是inline的。如下程式碼範例
一個自定類: class empty{};
其實等於以下代碼:
class Empty { public:Empty() { }//default 建構函式~Empty() { }//解構函式Empty(const Empty& rhs) { }//copy建構函式Empty& operator=(const Empty& rhs) { }//copy assignment操作符};
那麼這四個名詞的概念分別是:default 建構函式:在你不提供任何建構函式的情況下,系統給出的一個不帶參數,不包含函數代碼的建構函式;解構函式:與建構函式相反,當對象脫離其範圍時(例如對象所在的函數已調用完畢),系統自動執行解構函式。解構函式往往用來做“清理善後” 的工作(例如在建立對象時用new開闢了一片記憶體空間,應在退出前在解構函式中用delete釋放)。copy建構函式:只有單個形參,而且該形參是對本類類型對象的引用(常用const修飾),這樣的建構函式成為建構函式(C++ pirmer定義)。經常被稱作X(const X&),而且也是由編譯自動調用。copy assignment操作符:自動合成的一種賦值操作符 什麼時候會調用copy建構函式
以下三種情況出現時,會調用一個類的拷貝建構函式:
1) 用一個已經執行個體化了的該類對象,去執行個體化該類的另外一個對象;
2) 用該類的對象傳值的方式作為一個函數的參數;
3) 一個函數傳回值為該類的一個對象。如下代碼進行了樣本:
// five.cpp : 定義控制台應用程式的進入點。//#include "stdafx.h"#include <iostream>using namespace std;class myClass{public: myClass():a(1),b(1){} myClass(int m, int n) { a = m; b = n;} myClass(myClass& x) { a = x.a; b = x.b; cout << "copy constructor is called." << endl; } friend int someFun1(myClass x); friend myClass someFun2(int a, int b);private: int a; int b;};int fun1(myClass x){ return x.a + x.b;}myClass fun2(int a, int b){ myClass ca(a, b); return ca; }int _tmain(int argc, _TCHAR* argv[]){ myClass a;//調用已經聲明的建構函式 myClass c(10, 10); myClass d(c); // 情況1) int anInt = fun1(c); // 情況2 myClass e = fun2(11, 11); // 情況3 return 0;}
什麼時候必須要顯式聲明拷貝建構函式?
拷貝建構函式的作用就是用一個已經執行個體化了的該類對象,去執行個體化該類的另外一個對象。下面的代碼並沒有顯式聲明一個建構函式,編譯器會自動為類BaseClass產生一個預設的隱式拷貝建構函式:
// five.cpp : 定義控制台應用程式的進入點。//#include "stdafx.h"#include <iostream>using namespace std;class BaseClass {private: int a;public: BaseClass(int b){a = b;} void SetValue(int a){this->a = a;} void Show(){cout << a << endl;}};int _tmain(int argc, _TCHAR* argv[]) { BaseClass base(100); BaseClass dev = base; // 調用了預設的隱式拷貝建構函式 BaseClass bc(dev); // 調用了預設的隱式拷貝建構函式 dev.Show(); // 輸出應該是100 dev.SetValue(90); dev.Show(); // 輸出應該是90 base.Show(); // 輸出應該是100 bc.Show(); // 輸出應該是100 return 0;}
注意,編譯器產出的解構函式是個non-virtual(見條款7),除非這個class的base class自身聲明有virtual解構函式(這種情況下這個函數的虛屬性。什麼時候不會自動調用copy assignment操作符? 至於copy建構函式和copy assignment操作符,編譯器建立的版本只是單純地將來來源物件的每一個non-static成員變數拷貝到目標對象。但在某些情況下編譯器拒絕產生copy assignment操作符函數。比如存在引用成員和const成員。對於引用的改變,也就是說引用自身可被改動嗎?如果是,那麼就違背了C++的原則:引用不能修改指向對象。所以必須自己定義copy
assignment操作符。比如如下代碼:
// five.cpp : 定義控制台應用程式的進入點。//#include "stdafx.h"#include <iostream>using namespace std;class Person {public: Person(string& a, const int& b) : name(a), id(b) { }private: const int id; string& name;};int _tmain(int argc, _TCHAR* argv[]) { Person p1(string("chu"), 1); Person p2(string("jun"), 2); p1 = p2;/////// error C2582: 'operator =' function is unavailable in 'Person' system("pause"); return 0;}
還有一種情況編譯器不會產生copy assignment函數,就是基底類型將copy assignment聲明為private,衍生類別型就無法獲得編譯器的協助。因為衍生類別型無法調用基底類型的copy assignment函數(不具備存取權限)。
#include "stdafx.h"#include <iostream>using namespace std;class BaseClass {private: BaseClass& operator=(const BaseClass& rhs) { }};class derived : public BaseClass { };int _tmain(int argc, _TCHAR* argv[]) { BaseClass px1, px2; px1 = px2; ///// 'BaseClass::operator =' : cannot access private member declared in class 'BaseClass' system("pause"); return 0;}
經過以上講解,想必大家已經對這四個default建構函式,copy建構函式,copy assignment操作符,以及解構函式的概念已經有足夠的清晰了~所以
請記住
編譯器可以暗自為class建立default建構函式,copy建構函式,copy assignment操作符,以及解構函式。