1. 程式人生 > >C++ 類的隱式轉換與explicit

C++ 類的隱式轉換與explicit

我們都知道C/C++中的基本資料型別可以發生轉換,類也一樣可以。類的轉換可以分為兩種型別: 1. 類的定義與基本資料型別相關,基本資料型別與類相互轉換 2. 類的定義與其他類相關,類與類之間相互轉換 第二種稍微複雜一點,本文只討論第一種。

class Person {
public:
    Person() {
        cout << "no param constructor!" << endl;
        mAge = 0;
    }
    Person(int age) {
        cout << "1 param constructor!"
<< endl; mAge = age; } /* Person(int age,int b =100) { cout << "2 param constructor!" << endl; mAge = age; } */ Person(int age,int b) { cout << "2 param constructor!" << endl; mAge = age; } ~Person() { cout
<< "解構函式已呼叫" << endl; } operator int() { return mAge; } private: int mAge; };

1,隱式轉換

之前在研究建構函式與匿名物件的時候,就提到過隱式轉換的概念, 下邊我們就來測試一下:

Person p1 = 100//等號法有參構造,發生隱式轉換
Person p2 =(100,100);//這個不會呼叫兩個引數的建構函式,不存在這種用法

也就是說,類的隱式轉換依賴於只接收一個引數的建構函式。換句話說:隱式轉換本質上就是呼叫了類的有參構造,只接受一個引數的有參構造才能作為轉換函式

,在一開始給出的測試程式碼中,大家可以看到這一段被註釋的程式碼:

    Person(int age) {
        cout << "1 param constructor!" << endl;
        mAge = age;
    }
    /*
    Person(int age,int b =100) {
        cout << "2 param constructor!" << endl;
        mAge = age;
    }
    */

這個建構函式同樣是只接受一個引數,我們他提供了一個有初始值的引數b,當我們只給一個引數的時候,b可取預設值100,同樣會發生隱式轉換。 但是請注意我們為什麼要把這段程式碼註釋掉?因為如果一個類中如果存在上述兩種構造方法,就會引發二義性錯誤:當用一個引數取呼叫有參構造的時候編譯器不知道呼叫的時候選擇哪一個。這個選擇機制稱為模板與過載的解析策略,涉及到過載,模板,模板的過載,我們隨後會單獨討論這個問題。

易錯點: 同時存在多個隱式轉換:

    Person(int age) {
        cout << "1 param constructor!" << endl;
        mAge = age;
    }
    Person(double age) {
        cout << "1 param constructor!" << endl;
        mAge = age;
    }
    Person p1 = (int)100;
    Person p1 = (double)100//此時可以指定呼叫哪種型別的隱式轉換,避免出現二義性。

2,explicit關鍵字 網易雲單詞解釋: explicit: adj. 明確的;清楚的;直率的;詳述的 當我們需要關閉這種隱式轉換的時候,可以在建構函式前邊新增explicit關鍵字。這樣的結果是我們只能用顯式呼叫的方法來呼叫建構函式。

    explicit Person(int age) {
        cout << "1 param constructor!" << endl;
        mAge = age;
    }
    Person p1 = 100;//error 不存在從int 到 Person適當的建構函式
    //顯式呼叫依舊有效,此處double值100.00被轉換為int型別
    Person p2 = Person(100.00);

3,反向轉換(轉換函式) 既然,基本資料型別通過隱式轉換為類,那麼可以做相反的轉換嗎?答案是可以的!轉換函式語法:operator type();

  1. 轉換函式必須是類方法
  2. 不能制定返回值
  3. 不能有引數 如果不提供轉換函式,我們可以嘗試一下能不能強轉
    Person p1 = Person(100.00);
    int a = (int )p1;//error
    //直接標紅,不存在int 到 Person適當的建構函式

下邊我們給他一個建構函式:

    operator int() {return mAge;}

    Person p1 = Person(100);
    int a = p2;//成功轉換

然後我們嘗試一下類與類之間的轉換:

    operator Per() {
        return mAge;
    }

    Person p1 = Person(100.00);
    Per p2 = p1;//成功轉換

但是類與類之間轉換,需要注意的點有很多,此處需要Per類中存在 int 到 Per類的建構函式。 猜想: 轉換函式依賴於隱式轉換,我們只能完成類中一個屬性的轉換。 現在看來這個用法有點雞肋,所以未求證。

PS:過載中的轉換函式與友元 +號過載成員函式版

Person p1
p1 + 1 //可以實現,先呼叫轉換函式,然後呼叫p1呼叫過載
1 + p1 //不可實現

+號過載友員函式版

Person p1
p1 + 1      //可以實現,先呼叫轉換函式,然後呼叫p1呼叫過載+
1 + p1      //可以實現,先呼叫轉換函式,1轉換為物件後呼叫過載+
1 + 1 = 2//呼叫個屁的過載
注意:呼叫成員過載函式時,第一個運算元必須是物件。