C 拾趣 類建構函式的隱式轉換

2021-07-26 15:17:14 字數 1761 閱讀 1590

寫這個系列的博文,並不是我想對c++進行什麼批判,也不是想對其進行辯護。只是想羅列一些有意思的東西,故取名拾趣。

首先我們看下一種比較常見的技術——類建構函式的隱式轉換。這兒先說明下,之後的例子中,我會為了盡量突出主要內容,而忽略一些可以作為充分條件但非必要條件的東西,故設計的一些**存在「不完善」的嫌疑。因為為了堵住所有漏洞,往往會讓整個**讓人感覺其重心並非在我想介紹的技術上,而在「苦行僧」式的程式設計原則上。

我們知道c++是乙個型別嚴格的語言,比如下面乙個函式

void test_int_proxy(const int_proxy& v)
呼叫者對其傳參也應該是乙個int_proxy的物件,但是實際情況並非如此。那該如何表述,我個人覺得應該是:編譯器對其傳參應該是乙個int_proxy物件。這兩種表述的區別就是「呼叫者」和「編譯器」的區別。我們來看乙個實際例子,我們先假定int_proxy類這麼定義:

class int_proxy ;

public:

int value() const

private:

int _m;

};

該類非常簡單,它有乙個帶引數的建構函式,並使用引數列表形式初始化類的成員變數。

一般情況下我們都會這麼呼叫test_int_proxy方法:

test_int_proxy(int_proxy(100));
這種寫法我想沒人會有異議,但是如果出現下面這種寫法,就可能讓人感覺不可接受了:

test_int_proxy(100);
然而,這種寫法對上述類的定義來說是合法的!其效果和使用int_proxy控制住是一樣的。這是為什麼呢?這便是類建構函式的隱式轉換技術。c++編譯器認為test_int_proxy方法傳入的應該是乙個const型別的int_proxy物件,然而如果它發現引數不是該物件時,就會使用該類中可以使用該引數進行構造物件的方法構造出乙個臨時的物件。我們例子中傳參100是個int型資料,而int_proxy正好有乙個攜帶int引數的建構函式。稍微總結下類建構函式隱式轉換的必要條件:

找不到傳參型別嚴格對應的函式

找到傳參型別嚴格匹配的類的建構函式

因為隱式轉換構造出的是臨時物件,所以不可修改,故觸發隱式轉換的函式的傳參型別必須要使用const修飾

但是個人覺得這種「奇巧淫技」還是不用為好。比如我們**中還有如下函式:

void test_int_proxy(const int& v)
那麼c++編譯器會針對傳100的呼叫上面這個過程。這樣乙個函式呼叫有兩個匹配的呼叫方法就會產生不確定性——這兒指的不確定性並非是指編譯器呼叫哪個方法的不確定性,而是指維護這段**的人對上述**做調整時容易忽略一些問題而導致的「人禍」。

再比如,我們在**中加入下面類和方法

class int_proxy_2 ;

public:

int value() const

private:

int _m;

};void test_int_proxy(const int_proxy_2& v)

那麼編譯器不能確定隱式轉換是要轉換哪個類,更不知道是呼叫哪個test_int_proxy方法了。

限制類建構函式的隱式轉換的方法也很簡單,就是給對應的建構函式加上explict關鍵字

class int_proxy ;
這樣通過隱式轉換而構造臨時物件的圖謀將會被察覺並禁止。

類建構函式的隱式轉換

在程式設計中,型別轉換在所難免,在此我將介紹一下c 中常用的隱式轉換和強制型別轉換。關於隱式轉換 在c 中,某些型別之間存在相關的依賴關係,若兩種型別相關,則可以再需要某種型別的運算元位置上,使用該型別的相關型別物件或值。c 並不是吧兩個不同型別的值直接加在一起,而提供了一組轉換規則,一邊在執行算數...

explicit 類建構函式的隱式轉換

限制類編譯器呼叫建構函式的隱式轉換 單一入參建構函式 我們知道c 是乙個型別嚴格的語言,比如下面乙個函式 void test int proxy const int proxy v 呼叫者對其傳參也應該是乙個int proxy的物件,但是實際情況並非如此。那該如何表述,我個人覺得應該是 編譯器對其傳...

建構函式隱式轉換

建構函式會引起乙個不引人注意的問題 用單個實參來呼叫的建構函式定義了從從形參型別到類型別的乙個隱式轉換。舉個例子說 cpp view plain copy class sales item sales item add sales item other sales item const std st...