一. 函數的原型以及函數建立的時機編程
C++中建立一個空類:函數
C++代碼學習
class Empty {}; spa
默認會生成4個函數,其函數的原型以下:視頻
C++代碼對象
public: blog
Empty() { ... } 教程
Empty(const Empty& rhs) { ... } get
~Empty() { ... } 原型
Empty& operator=(const Empty& rhs) { ... }
說明:1) 這些函數只有在須要調用的時候,編譯器纔會生成。2) 4個函數都是public的。
3) 4個函數都是inline的(即函數定義在類的定義中的函數)。4) 若是你顯式的聲明瞭這些函數中的任何一個函數,那麼編譯器將再也不生成默認的函數。
好比,當遇到下列語句時,函數會被編譯器生成:
C++代碼
Empty e1; //默認構造函數
//對象銷燬時,析構函數
Empty e2(e1);//拷貝構造函數
e2 = e1;//賦值運算符
另外,還存在兩種默認的函數:就是取地址運算符和取地址運算符的const版本,這兩個函數在《Effective C++》中沒有說起。
C++代碼
public:
Empty* operator&() { ... }
const Empty* operator&() const { ... }
這兩個函數是確實存在的,正以下面的代碼能夠正常工做:
C++代碼
#include <stdio.h>
class Empty {
};
int main(int argc, char** argv)
{
Empty a;
const Empty *b = &a;
printf("%p\n", &a); //調用取地址運算符
printf("%p\n", b); //調用const取地址運算符
}
一個容易被忽略的問題:自定義的拷貝構造函數不只會覆蓋默認的拷貝構造函數,也會覆蓋默認的構造函數。下面的代碼是編譯不過的,用戶必須再顯式的定義一個無參的構造函數。
C++代碼
class Empty
{
public:
Empty(const Empty& e) { } //拷貝構造函數
};
int main(int argc, char** argv)
{
Empty a;
}
二. 賦值操做符存在的問題
賦值操做符函數的行爲與拷貝構造函數的行爲基本是相同的,編譯器生成賦值操做符函數是有條件的,若是會產生沒法完成的操做,編譯器將拒絕產生這一函數。
那麼何時編譯器沒法完成賦值這一行爲呢?考慮以下情形(來源Effective C++):
C++代碼
template<class T>
class NameObject {
public:
NameObject(std::string& name,const T& value);
private:
std::string& nameValue;//引用成員變量
const T objectValue; //const成員變量
};
而後考慮下面的語句會發生什麼事:
C++代碼
std::string newDog("abc");
std::string oldDog("xxx");
NameObject
NameObject
p = s;//將會發生什麼?
賦值語句以前,p.nameValue指向newDog, s.nameValue指向oldDog。那麼賦值以後呢?p.nameValue應該指向s.nameValue指向的對象嗎?可是C++有一條規定:引用不能改指向另一個對象。
對於變量objectValue,C++規定:更改const成員是不合法的。
所以若是上面兩種情形中的任何一種發生了,C++編譯器給出的響應是:拒絕編譯這一行的賦值動做。若是你這麼作了,C++編譯器會報錯。
若是你執意要進行賦值操做,那麼能夠本身定義一個賦值操做符重載函數。
另外若是你想更好的提高你的編程能力,學好C語言C++編程!彎道超車,快人一步!筆者這裏或許能夠幫到你~
歡迎轉行和學習編程的夥伴,利用更多的資料學習成長比本身琢磨更快哦!
編程學習資料: