2010-10-27 42 views
2

我想重載森林類中的+運算符,森林是樹的集合,+運算符應該將兩個森林合併爲一個。我有以下的代碼爲我的類定義:在C++中泛型類的重載+運算符

template<typename NODETYPE> 
class Forest 
{ 


    public: 

     friend Forest& operator+<>(Forest&, Forest&); 
     friend ostream& operator<<<>(ostream&, const Forest&); 
     friend istream& operator>><>(istream&, Forest&); 
     Forest(); 
     Forest(const Forest& otherForest); 
     ~Forest(); 
     void nodes(int&) const; 

    private: 
     ForestNode<NODETYPE> *root; 

     ForestNode<NODETYPE> *getNewNode(const NODETYPE &); 
}; 

以下是我的執行操作+的:

template<typename NODETYPE> 
Forest& operator+<>(Forest& f1, Forest& f2) 
{ 
    f3 = new Forest(); 
    f3.root = *f1.*root; 
    f3.root.sibling = *f2.*root; 
    *f1.root = 0; 
    *f2.root = 0; 
    return f3; 
} 

我得到編譯如下錯誤:

         
 
|28|error: expected constructor, destructor, or type conversion before '&' token|

線28指到我的運營商+實施的簽名。

我想糾正我應該添加到返回類型,並提供:

template<typename NODETYPE> 
Forest<NODETYPE>& operator+<>(Forest& f1, Forest& f2) 
{ 
    f3 = new Forest(); 
    f3.root = *f1.*root; 
    f3.root.sibling = *f2.*root; 
    *f1.root = 0; 
    *f2.root = 0; 
    return f3; 
} 

但是,這使我有以下錯誤:

         
 
|28|error: declaration of 'operator+' as non-function| |28|error: missing template arguments before '&' token| |28|error: 'f1' was not declared in this scope| |28|error: missing template arguments before '&' token| |28|error: 'f2' was not declared in this scope|

誰能幫助我?我會非常感激。

+3

爲什麼你動態分配,然後試圖返回一個指向'Forest'而不是參考?而且該函數不應該返回任何引用,沒有什麼可引用的:當你添加兩個東西時,通常最終會得到一個新的*值*,所以按值返回。這是*壞*另外,你正在操縱參數。 ('2 + 2'肯定不會改變'2'!)也許你想要一個'combine'成員函數。 – GManNickG 2010-10-27 10:43:39

+0

在堆上分配新的森林並返回引用是一個非常糟糕的主意。只需創建一個本地對象並按值返回。 – 2010-10-27 10:45:22

+0

或者使用智能指針,如果複製是昂貴的。 – 2010-10-27 10:51:06

回答

5

關鍵寫作運營商+是不寫操作+。相反,寫一個副本構造函數和operator + =:

template<class NodeType> 
struct Forest { 
    //... 
    Forest(Forest const &other); 
    //... 
    Forest& operator+=(Forest const &other) { 
    // code here 
    return *this; 
    } 
    //... 
}; 

現在我們添加運營商+:

template<class NodeType> 
struct Forest { 
    //... 
    friend Forest operator+(Forest a, Forest const &b) { 
    a += b; 
    return a; 
    } 
    //... 
}; 

就是這樣!複製通常是直截了當的(有時被禁止),用+ = + +(你有兩個對象並改變一個,而不是從兩個中創建第三個對象)可能會更簡單。 op +的這種模式適用於任何類似的類型,甚至適用於類似的運算符,如 - ,*和/。

+0

取值爲第一個參數而不是const引用是有用的,因爲我們要複製它,但b應該被視爲常量引用。 – CashCow 2010-10-27 11:14:42

+0

@CashCow:你是對的,這就是我的意圖;這裏很晚,所以如果你發現更多的錯誤,你必須等待。 :) – 2010-10-27 11:17:35

+0

對於那些經過的人來說,可能很容易使'返回a + = b',但這足以欺騙編譯器將'a + = b'的結果視爲與'a'相同,所以沒有應用NRVO(並且在C++ 0x中,它不會被移動)。你當然可以'返回std :: move(a + = b);'來幫助它,但是你並沒有真正獲得任何東西。 – GManNickG 2010-10-28 09:17:30

2

您必須爲所有Forest參數提供模板參數。

template<typename NODETYPE> 
Forest<NODETYPE> operator+(Forest<NODETYPE>& f1, Forest<NODETYPE>& f2) 

另外,考慮使論點const引用,以確保您不會操作它們。

關於朋友功能模板,在stackoverflow上有severalquestionsC++ FAQ也有一個頁面,他們解釋了一些基本知識。

+2

並刪除'''''。但是他的代碼很糟糕,所以他不能讓它們成爲常量引用。 – GManNickG 2010-10-27 10:41:32

+0

啊,謝謝。我會那樣做,但是項目要求是因爲某些原因後面的參數被刪除。 – joedillian 2010-10-27 10:46:36

+0

@ joedillian:這很糟糕。運算符重載是一把雙刃劍,因爲它經常會導致代碼難以理解,如果運算符行爲不直觀。沒有人希望用'+'來刪除操作數。 – 2010-10-27 10:48:38

0

您可以如下定義operator+模板:

template< class NodeType > 
Forest<NodeType> operator+(Forest<NodeType> const& f1, Forest<NodeType> const& f2) 
{ 
    // Implementation. 
} 

乾杯&心連心,

3

運算符重載可能是好事或壞事。很好,當它導致更簡單的代碼。不好的時候,它會導致作家或者使用不正確的語義進行重載(而是一種編譯的解決方案),或者使用操作符的直觀方式會導致代碼效率非常低。

注意後面的語句也可以應用於std :: string,這可能會產生大量的副本,這就是爲什麼C++ 03標準規定一個字符串不必內部存儲在一個連續的(在過去,他們使用copy-on-write引用,並且可以將這些引用存儲在兩個字符串之間,直到需要時爲止。隨後,它被發現是非線程安全的,因此比僅僅複製緩衝區更加昂貴現在他們每次都複製並且再次效率低下)。 (請注意,識別線程和原子性問題的C++ 11標準可確保底層確實需要連續並以null結尾以使讀操作安全)。

操作的正確的簽名+(的情況下,所有的類型相同)如下:

T operator+(const T&, const T&); 

作爲一個成員函數那就是:

class T 
{ 
    // make public if necessary 
    T operator+(const T& rhs) const; 
}; 

可以自動實現operator +作爲模板,只要運營商+ =可用

template<typename T, typename R> 
T operator+(const T& lhs, const R& rhs) 
{ 
    T copy(lhs); 
    return copy += rhs; 
} 

如果要聲明作爲朋友的模板的重載運算符,這是執行此操作的正確方法。我將與運營商展示它< <

// first some forward declarations, assume ostream already declared with #include <iosfwd> minimum 
template< typename T > class Forest; 
template< typename T > std::ostream & operator<<(std::ostream & os, const Forest<T> & for); 

template< typename T> class Forest 
{ 
    friend std::ostream& operator<< <>(std::ostream&, const Forest<T> &); 
    //rest of class Forest 
}; 

template< typename T > 
std::ostream & operator<<(std::ostream& os, const Forest<T> & forest) 
{ 
    // implement 
    return os; 
} 

您將應用類似的技術要聲明作爲朋友你的類中的任何其他外部功能,即

  1. 向前聲明你的類作爲模板
  2. 正向聲明該方法爲模板函數
  3. 使用<>使功能成爲朋友>在表示參數的開括號之前>
  4. 在課後實現該功能。
+0

在類定義中定義的op <<的朋友函數要容易得多。 – 2010-10-28 00:04:22