C 基礎教程物件導向(學習筆記(31))

2021-08-29 13:59:29 字數 3276 閱讀 3953

預設情況下,c ++會將任何建構函式視為隱式轉換運算子。考慮以下情況:

#include #include class fraction

// 拷貝建構函式

fraction(const fraction ©) :

m_numerator(copy.m_numerator), m_denominator(copy.m_denominator)

friend std::ostream& operator<<(std::ostream& out, const fraction &f1);

int getnumerator()

void setnumerator(int numerator) };

std::ostream& operator<<(std::ostream& out, const fraction &f1)

fraction makenegative(fraction f)

int main()

雖然函式makenegative()期望乙個fraction,但我們已經給它整數字6。因為fraction有乙個願意接受單個整數的建構函式,所以編譯器會隱式地將文字6轉換為fraction物件。它通過使用fraction(int,int)建構函式初始化makenegative()引數f來完成此操作。

由於f已經是乙個fraction,makenegative()的返回值被拷貝構造回main,然後將其傳遞給過載的operator <<。

因此,上面的程式列印:

copy constructor called

-6/1

這種隱式轉換適用於所有型別的初始化(直接,統一和拷貝)。

適用於隱式轉換的建構函式稱為轉換建構函式。在c ++ 11之前,只有採用乙個引數的建構函式才能轉換建構函式。但是,使用c ++ 11中新的統一初始化語法,這個限制被取消了,並且採用多個引數的建構函式現在可以轉換建構函式。

explicit關鍵字

雖然在fraction案例中進行隱式轉換是有意義的,但在其他情況下,這可能是不合需要的,或導致意外行為:

#include #include class mystring

mystring(const char *string) //分配字串來儲存字串值

friend std::ostream& operator<<(std::ostream& out, const mystring &s); };

std::ostream& operator<<(std::ostream& out, const mystring &s)

int main()

在上面的示例中,使用者嘗試使用char初始化字串。因為chars是整數族的一部分,所以編譯器將使用轉換建構函式mystring(int)建構函式將char隱式轉換為mystring。然後程式將列印此mystring,以獲得意外結果。

解決此問題的一種方法是通過顯式關鍵字使建構函式(和轉換函式)顯式化,該關鍵字放在建構函式名稱的前面。顯式建構函式和轉換函式不會用於隱式轉換或拷貝初始化:

#include #include class mystring

mystring(const char *string) // 分配字串來儲存字串值

friend std::ostream& operator<<(std::ostream& out, const mystring &s); };

std::ostream& operator<<(std::ostream& out, const mystring &s)

int main()

上面的程式不會編譯,因為mystring(int)是顯式的,並且找不到合適的轉換建構函式來隱式地將』x』轉換為mystring。

但請注意,僅使建構函式顯式可以防止隱式轉換。仍然允許顯式轉換(通過轉換):

std::cout << static_cast(5); // 允許:explicit 轉換為5到mystring(int)
直接或統一初始化仍然會將引數轉換為匹配(統一初始化不會縮小轉換範圍,但它會很樂意進行其他型別的轉換)。

mystring str('x'); // 允許:初始化引數仍可以隱式轉換為匹配
規則:考慮使建構函式和使用者定義的轉換成員函式顯式化以防止隱式轉換錯誤

在c ++ 11中,explicit關鍵字也可以與轉換運算子一起使用。

delete關鍵字

在我們的mystring情況下,我們真的想完全禁止將』x』轉換為mystring(無論是隱式還是顯式,因為結果不是直觀的)。部分執行此操作的一種方法是新增mystring(char)建構函式,並將其設為私有:

#include #include class mystring

public:

// explicit使得此建構函式不符合隱式轉換的條件

explicit mystring(int x) //分配大小為x 的字串

mystring(const char *string) // 分配字串來儲存字串值

friend std::ostream& operator<<(std::ostream& out, const mystring &s); };

std::ostream& operator<<(std::ostream& out, const mystring &s)

int main()

但是,仍然可以在類內部使用此建構函式(私有訪問僅阻止非成員呼叫此函式)。

解決此問題的更好方法是使用「delete」關鍵字(在c ++ 11中引入)來刪除該函式:

#include #include class mystring

mystring(const char *string) // 分配字串來儲存字串值

friend std::ostream& operator<<(std::ostream& out, const mystring &s); };

std::ostream& operator<<(std::ostream& out, const mystring &s)

int main()

delete函式後,任何對該函式的使用都被視為編譯錯誤。

請注意,也可以刪除拷貝建構函式和過載運算子,以防止使用這些函式。

C 基礎教程物件導向(學習筆記5(2))

在編寫具有多個建構函式的類 大多數建構函式 時,必須為每個建構函式中的所有成員指定預設值會導致冗餘 如果更新成員的預設值,則需要觸控每個建構函式。從c 11開始,可以直接為普通類成員變數 不使用static關鍵字的變數 提供預設初始化值 class rectangle void print int ...

C 基礎教程物件導向(學習筆記(23))

過載一元運算子 與您目前看到的運算子不同,正 負 和邏輯非 運算子都是一元運算子,這意味著它們只能在乙個運算元上執行。因為它們僅對它們所應用的物件進行操作,所以通常將一元運算子過載實現為成員函式。所有三個運算元都以相同的方式實現。讓我們看一下我們如何在前面的例子中使用的cents類上實現operat...

C 基礎教程物件導向(學習筆記(24))

過載比較運算子相對簡單,因為它們遵循我們在過載其他運算子時看到的相同模式。因為比較運算子都是不修改左運算元的二元運算子,所以我們將使過載的比較運算子宣告為友元函式。這是乙個帶有過載運算子 和operator!的car類的示例。include include class car friend bool...