2015-11-03 92 views
0

我試圖爲類模板重載< <運算符,但編譯器給我一個鏈接器錯誤。目標是能夠向std :: cout發送一個取消引用的基類指針,以便派生的運算符< <被調用。模板和overloadering操作符<<

這可能嗎?

class IBase 
{ 
public: 
    IBase() {}; 
    virtual ~IBase() {}; 
}; 

template <typename T> 
class Derived 
    : public IBase 
{ 
public: 
    Derived(T data); 
    friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 
private: 
    T data_; 
}; 

template <typename T> 
Derived<T>::Derived(T data) 
    : IBase(), 
     data_(data) 
{ 
} 

template <typename T> 
std::ostream& operator<<(std::ostream& os, const Derived<T>& dt) 
{ 
    os << dt.data_; 
    return os; 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 


    // Question 1 
    Derived<int> der(234); 
    std::cout << der; 

    // Question 2 
    //IBase* base = new Derived<int>(5); 
    // std::cout << *base 
} 

下面是錯誤:

錯誤LNK2001:解析外部符號「類 的std :: basic_ostream> & __cdecl 操作者< <(類的std :: basic_ostream

「(?? 6 @ YAAAV?$ basic_ostream @ DU?$ char_traits @ D @ std @@@ st(&,class Derived const &) ?d @@ AAV01 @ $ ABV派生3 H @@@ Z)

致命錯誤LNK1120:1周無法解析的外部

回答

2

你需要declarate朋友操作作爲模板

template<typename T1> 
friend std::ostream& operator<<(std::ostream& os, const Derived<T1>& dt); 
+0

謝謝!這就是訣竅 –

0

替換

friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

template<typename D> 
friend std::ostream& operator<<(std::ostream& os, const Derived<D>& dt); 
0

你眼前的問題是,運營商需要作爲模板。

但是,您的最終目標無法通過模板單獨獲得,因爲取消引用IBase*會讓您產生IBase& - 模板實例化在編譯時發生,且編譯器無法訪問運行時類型。

因此,如果您將取消引用的IBase*傳遞給operator <<,那麼您的模板化運算符將永遠不會使用。

相反,添加虛擬輸出功能的基礎和覆蓋它:

class IBase 
{ 
public: 
    IBase() {}; 
    virtual ~IBase() {}; 
    virtual std::ostream& output(std::ostream&) const = 0; 
}; 

template <typename T> 
class Derived 
    : public IBase 
{ 
public: 
    Derived(T data); 
    virtual std::ostream& output(std::ostream& os) const 
    { 
     os << data; 
     return os; 
    } 
private: 
    T data_; 
}; 

std::ostream& operator<<(std::ostream& os, const IBase& dt) 
{ 
    return dt.output(os); 
} 
+0

謝謝你!我幾分鐘前將其作爲一個單獨的問題提出,請在那裏發佈您的答案,以便我可以接受。 http://stackoverflow.com/questions/33496137/virtual-operator-and-templates –

0

你並不需要讓你的friend模板:

friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

這需要改變,以:

friend std::ostream& operator<< <>(std::ostream& os, const Derived<T>& dt); 

operator<<函數將需要在此窗體的friend聲明之前可見。

您應該更喜歡此表單,因爲您不需要將所有操作員的實例化爲friend s,只是其中的一個。

2

friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt);

聲明非模板版本friend,所以你必須實行

std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

爲每次使用T

std::ostream& operator<<(std::ostream& os, const Derived<int>& dt) { 
    return os << dt.data_; 
} 

等。 A到做沒有重複代碼的方法是與類中定義:

template <typename T> 
class Derived : public IBase 
{ 
public: 
    explicit Derived(T data); 
    friend std::ostream& operator<<(std::ostream& os, const Derived<T>& dt) 
    { 
     return os << dt.data_; 
    } 
private: 
    T data_; 
}; 

Demo

的另一種方法是使函數模板。

// Forward declarations 
template <typename T> class Derived; 
template <typename T> std::ostream& operator<<(std::ostream& os, const Derived<T>& dt); 

然後在Derived,你有2種選擇:

  • 聲明每個模板方法的朋友:

    template <typename T2> 
    friend std::ostream& operator<<(std::ostream& os, const Derived<T2>& dt); 
    

    所以std::ostream& operator<<(std::ostream& os, const Derived<int>& dt)訪問的Derived<int>私有成員,但也到Derived<char>

    Demo

  • 只聲明瞭該參數匹配模板:

    friend std::ostream& operator<< <>(std::ostream& os, const Derived& dt); 
    

    std::ostream& operator<<(std::ostream& os, const Derived<int>& dt)沒有訪問的Derived<char>私有成員。

    Demo