在C ++中对泛型类重载+运算符

时间:2010-10-27 10:35:33

标签: c++ templates overloading operator-keyword

我正在尝试重载林类中的+运算符,林是树的集合,+运算符应该将两个林合并为一个。我有以下代码作为我的类定义:

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 &);
};

以下是我对operator +的实现:

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|

任何人都可以帮我吗?我会非常感激。

4 个答案:

答案 0 :(得分:6)

编写operator +的关键是不要编写operator +。而是写一个复制ctor和operator + =:

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

现在我们添加operator +:

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

就是这样!复制通常是直截了当的(有时候是被禁止的),用+ =比+来思考可能更简单(你有两个对象并且改变一个,而不是从两个中创建第三个对象)。 op +的这种模式适用于任何类似的类型,甚至适用于类似的运算符,如 - ,*和/.

答案 1 :(得分:3)

运营商超载可能是好事还是坏事。很好,当它导致更简单的代码。当它导致编写者使用不正确的语义重载(但是编译的解决方案)或者使用运算符的直观方式导致代码效率极低时,会出现问题。

注意后面的语句也可以应用于std :: string,这可能会产生大量的副本,这就是C ++ 03标准规定字符串不必在内部存储在连续缓冲区中的原因(在过去,他们使用了写入时复制引用,并且可以将这些引用存储到两个字符串中,直到需要连接。随后发现它是非线程安全的并且使得它比仅仅复制缓冲区更昂贵他们每次都复制而且再次效率低下。)

(请注意,识别线程和原子问题的C ++ 11标准确保底层确实需要连续且以空值终止以使读取操作安全。)

operator +的正确签名(在所有类型相同的情况下)如下:

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

作为成员函数,它将是:

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

只要operator + =可用

,您就可以自动将operator +作为模板实现
template<typename T, typename R>
T operator+( const T& lhs, const R& rhs )
{
    T copy(lhs);
    return copy += rhs;
}

如果要将模板的重载运算符声明为朋友,这是正确的方法。我将使用运算符&lt;&lt;

显示它
// 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. 使用&lt;&gt;使该功能成为朋友在表示参数的开括号之前
  4. 在课后实施该功能。

答案 2 :(得分:2)

您必须为所有Forest参数提供模板参数。

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

另外,请考虑使用参数const引用,以确保不会操纵它们。

有关友元函数模板的stackoverflow上有several questionsC++ FAQ还有一个页面,介绍了一些基础知识。

答案 3 :(得分:0)

您可以按如下方式定义operator+模板:

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

干杯&amp;第h。,