c++ 基本語法:https://www.w3cschool.cn/cpp/html
c++初始化參數列表:https://blog.csdn.net/coder_xia/article/details/7447822ios
c++默認構造函數:http://www.javashuo.com/article/p-ejnnzlcl-my.htmlc++
c++ 複製構造函數:程序員
三 複製控制
1 複製構造函數
1.1 幾個要點
(1) 複製構造函數
複製構造函數是一種特殊構造函數,只有1個形參,該形參(經常使用 const &修飾)是對該類類型的引用。
class Peopel
{
public:
Peopel();//默認構造函數
Peopel(const Peopel&);//複製構造函數
~Peopel();//析構函數
};
當定義一個新對象並用一個同類型的對象對它進行初始化時,將顯式使用複製構造函數。
Peopel a1; Peopel a2 = a1;
當將該類型的對象傳遞給函數或函數返回該類型的對象時,將隱式使用複製構造函數。
Peopel Func(Peopel b){...}
(2)析構函數
析構函數是構造函數的互補:當對象超出做用域或動態分配的對象被刪除時,將自動應用析構函數。
析構函數可用於釋放構造對象時或在對象的生命期中所獲取的資源。
無論類是否認義了本身的析構函數,編譯器都自動執行類中非 static 數據成員的析構函數。
(3) 複製控制
複製構造函數、賦值操做符和析構函數總稱爲
複製控制。編譯器自動實現這些操做,但類也能夠定義本身的版本。
(4) 兩種初始化形式
C++ 支持兩種初始化形式:直接初始化和複製初始化。直接初始化將初始化式放在圓括號中,複製初始化使用 = 符號。
對於內置類型,例如int, double等,直接初始化和複製初始化沒有區別。
對於類類型:直接初始化直接調用與實參匹配的
構造函數;複製初始化先使用指定構造函數建立一個臨時對象,而後用
複製構造函數將那個臨時對象複製到正在建立的對象。直接初始化比複製初始化更快。
(5)形參和返回值
當形參或返回值爲類類型時,由該類的複製構造函數進行復制。
(6)初始化容器元素
複製構造函數可用於初始化順序容器中的元素。例如:
vector<string> svec(5);
編譯器首先使用 string 默認構造函數建立一個臨時值,而後使用複製構造函數將臨時值複製到 svec 的每一個元素。
(7)構造函數與數組元素
若是沒有爲類類型數組提供元素初始化式,則將用默認構造函數初始化每一個元素。
若是使用常規的花括號括住的數組初始化列表來提供顯式元素初始化式,則使用複製初始化來初始化每一個元素。根據指定值建立適當類型的元素,而後用複製構造函數將該值複製到相應元素:
Sales_item primer_eds[] = { string("0-201-16487-6"),
string("0-201-54848-8"),
string("0-201-82470-1"),
Sales_item()
};
1.2 合成的複製構造函數
(1)合成的複製構造函數
若是沒有定義複製構造函數,編譯器就會爲咱們合成一個。
合成複製構造函數的行爲是,執行逐個成員初始化,將新對象初始化爲原對象的副本。
逐個成員初始化:合成複製構造函數直接複製內置類型成員的值,類類型成員使用該類的複製構造函數進行復制。
例外:若是一個類具備數組成員,則合成複製構造函數將複製數組。複製數組時合成複製構造函數將複製數組的每個元素。
1.3 定義本身的複製構造函數
(1) 只包含類類型成員或內置類型(但不是指針類型)成員的類,無須顯式地定義複製構造函數,也能夠複製。
class Peopel
{
public:
std::string name;
unsigned int id;
unsigned int age;
std::string address;
};
(2) 有些類必須對複製對象時發生的事情加以控制。
例如,類有一個數據成員是指針,或者有成員表示在構造函數中分配的其餘資源。而另外一些類在建立新對象時必須作一些特定工做。這兩種狀況下,都必須
定義本身的複製構造函數。
最好顯式或隱式定義默認構造函數和複製構造函數。若是定義了複製構造函數,必須定義默認構造函數。
1.4 禁止複製
有些類須要徹底禁止複製。例如,iostream 類就不容許複製。延伸:容器內元素不能爲iostream
爲了防止複製,類必須顯式聲明其複製構造函數爲 private。
2 賦值操做符
與複製構造函數同樣,若是類沒有定義本身的賦值操做符,則編譯器會合成一個。
(1)重載賦值操做符
Sales_item&
operator=(const Sales_item &);
(2)合成賦值操做符
合成賦值操做符會逐個成員賦值:右操做數對象的每一個成員賦值給左操做數對象的對應成員。除數組以外,每一個成員用所屬類型的常規方式進行賦值。對於數組,給每一個數組元素賦值。
(3)複製和賦值常一塊兒使用
通常而言,若是類須要複製構造函數,它也會須要賦值操做符。
四 友元
友元機制容許一個類將對其非公有成員的訪問權授予指定的
函數或
類。
友元能夠出如今類定義的內部的任何地方。
友元不是授予友元關係的那個類的成員,因此它們不受聲明出現部分的訪問控制影響。
建議:將友元聲明成組地放在類定義的開始或結尾。
1 友元類
class Husband
{
public:
friend class Wife;
private:
double money;//錢是老公私有的,別人不能動,但老婆除外
};
class Wife
{
public:
void Consume(Husband& h)
{
h.money -= 10000;//老婆能夠花老公的錢
}
};
Husband h;
Wife w;
w.Consume(h);
2 使其餘類的成員函數成爲友元
class Husband; //1.聲明Husband
class Wife //2.定義Wife類
{
public:
void Consume(Husband& h);
};
class Husband //3.定義Husband類
{
public:
friend void Wife::Consume(Husband& h);//聲明Consume函數。
private:
double money;//錢是老公私有的,別人不能動,但老婆除外
};
void Wife::Consume(Husband& h) //4.定義Consume函數。
{
h.money -= 10000;//老婆能夠花老公的錢
}
注意類和函數的聲明和定義的順序:
(1)聲明類Husband
(2)定義類Wife,聲明Consume函數
(3)定義類Husband
(4)定義Consume函數。
五 static 類成員
static 成員,有全局對象的做用,但又不破壞封裝。
1 static 成員變量
static 數據成員是與類關聯的對象,並不與該類的對象相關聯。
static 成員遵循正常的公有/私有訪問規則。
2 使用 static 成員而不是全局對象有三個優勢。
(1) static 成員的名字是在類的做用域中,所以能夠避免與其餘類的成員或全局對象名字衝突。
(2) 能夠實施封裝。static 成員能夠是私有成員,而全局對象不能夠。
(3) 經過閱讀程序容易看出 static 成員是與特定類關聯的,這種可見性可清晰地顯示程序員的意圖。
3 static 成員函數
在類的內部聲明函數時須要添加static關鍵字,可是在類外部定義函數時就不須要了。
由於static 成員是類的組成部分但不是任何對象的組成部分,因此有如下幾個特色:
1) static 函數沒有 this 指針
2) static 成員函數不能被聲明爲 const (將成員函數聲明爲 const 就是承諾不會修改該函數所屬的對象)
3) static 成員函數也不能被聲明爲虛函數
4 static 數據成員
static 數據成員能夠聲明爲任意類型,能夠是常量、引用、數組、類類型,等等。
static 數據成員必須在類定義體的外部定義(正好一次),而且應該在定義時進行初始化。
建議:定義在類的源文件中名,即與類的非內聯函數的定義同一個文件中。注意,定義時也要帶上類類型+"::"
double Account::interestRate = 0.035;
5 特殊的靜態常量整型成員
靜態常量整型數據成員能夠直接在類的定義體中進行初始化,例如:
static const int period = 30;
固然char 能夠轉換成整形,也是能夠的, static const char bkground = '#';
6 其餘
(1)static 數據成員的類型能夠是該成員所屬的類類型。非 static 成員只能是自身類對象的指針或引用
class Screen
{
public:
// ...
private:
static Screen src1; // ok
Screen *src2; // ok
Screen src3; // error
};
(2)非 static 數據成員不能用做默認實參,static 數據成員可用做默認實參
class Screen
{
public:
Screen& clear(char =
bkground);
private:
static const char
bkground = '#';//static const整形變量能夠在類內部初始化。 };