2017-07-03 65 views
1

看看下面的代碼:只讀類變量(C++)和運算符重載

#include <string> 
#include <iostream> 

template <class T, class U> 
class readonly 
{ 
    friend U; 
    private: 
    T data; 
    T operator=(const T& arg) {data = arg; return data;} 
    T operator+=(const T& arg) {data = data + arg; return data;} 
    T operator-=(const T& arg) {data = data - arg; return data;} 
    T operator*=(const T& arg) {data = data * arg; return data;} 
    T operator/=(const T& arg) {data = data/arg; return data;} 
    public: 
    operator const T&() const {return data;} 
}; 

class myClass 
{ 
    private: 
    typedef readonly<int, myClass> RO_int; 
    typedef readonly<std::string, myClass> RO_string; 

    public: 
    RO_int x; 
    RO_string y; 

    void f() 
    { 
     x = 55; 
     y = "Howdy"; 
     std::cout << x << "\n\n"; // compiles fine 
     std::cout << y << "\n\n"; // compile error 
    } 
}; 

我使用這些模板類,以確保某些公共變量xy是「只讀」的外該類,但可以在類本身內進行修改。除了最後一行,我試圖顯示字符串類型的變量y,這段代碼中的所有東西都編譯得很好。我不明白爲什麼我能夠顯示x而不是y。如果我需要超載<<運營商,爲什麼我必須爲std::string而不是int

+0

這只是一個包含在main.cpp中的頭文件。我在main.cpp中做的所有事情是創建一個myClass類型的對象,然後調用函數f()。對不起,我應該更清楚一點。 – JohnTravolski

+0

int的輸出是0,所以我不認爲它使用正確的超載來顯示'x'。可能你需要重載'<<'使其適用於任何類型。 –

+0

似乎很直接的一些機制:'private:int x_; public:int x()const {return x_; }'。 –

回答

3

首先,但不是您的問題,您的運營商應返回readonly&T&而不是T。不要打破那樣的慣例。

現在爲一個實際的答案。

這是因爲operator<<string用途是一個模板和模板函數不考慮轉換時,模式匹配。需要int<<不是模板,因此它會考慮轉換。

我們可以通過創建一個operator<<不轉換一般解決這個問題:

只需添加

friend std::ostream& operator<<(std::ostream& os, readonly const& self) 
{ 
    return os<<self.data; 
} 

readonly類型,事情應該工作。這將通過ADL找到。

我們可以通過使用模板的第一個參數並檢查<<的工作原理以及第一個參數是從std::ostream或類似的第二個參數派生出來,使它更像SFINAE等。