Перегрузка + оператор универсального класса в C ++ - PullRequest
3 голосов
/ 27 октября 2010

Я пытаюсь перегрузить оператор + в классе леса, лес представляет собой набор деревьев, а оператор + должен объединять два леса в один. У меня есть следующий код в качестве определения моего класса:

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

Я получаю следующую ошибку при компиляции:

<blockquote>|28|error: expected constructor, destructor, or type conversion before '&' token|</blockquote>

строка 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;
}

Но это дает мне следующие ошибки:

<blockquote>|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|</blockquote>

Может ли кто-нибудь помочь мне с этим? Я был бы очень, очень благодарен.

Ответы [ 4 ]

6 голосов
/ 27 октября 2010

Ключом к написанию оператора + является не пишите оператор +. Вместо этого пишите ctor и оператор + =:

.
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 + работает с любым подобным типом, и даже для похожих операторов, таких как -, * и /.

3 голосов
/ 27 октября 2010

Перегрузка оператора может быть хорошей или плохой вещью.Хорошо, когда это приводит к более простому виду кода.Плохо, когда это приводит к тому, что авторы перезагружаются с неверной семантикой (но это решение компилируется) или когда интуитивный способ использования оператора приводит к крайне неэффективному коду.

Обратите внимание, что последнее утверждение может применяться к std :: stringКроме того, что может потенциально сделать большое количество копий, и именно поэтому стандарт C ++ 03 гласит, что строка не должна храниться внутри в непрерывном буфере (в старые времена они использовали ссылки «копировать при записи»)и может хранить такие ссылки на обе строки, соединяемые до тех пор, пока они не потребуются. Впоследствии было установлено, что он не является потокобезопасным, и его создание было более затратным, чем простое копирование буфера, поэтому теперь они копируются каждый раз и снова неэффективны).

(Обратите внимание, что стандарт C ++ 11, который распознает многопоточность и атомарные проблемы, гарантирует, что базовый элемент должен быть непрерывным и завершаться нулем, чтобы сделать операции чтения безопасными).

Правильная сигнатура оператора + (вдела все одинаковыtype) выглядит следующим образом:

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

В качестве функции-члена это будет:

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

Вы можете автоматически реализовывать оператор + как шаблон всякий раз, когда оператор + = доступен с

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

Если вы хотите объявить перегруженный оператор вашего шаблона другом, это правильный способ сделать это.Я покажу это с помощью оператора << </p>

// 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. Forwardобъявить ваш класс как шаблон
  2. Заблаговременно объявить метод как функцию шаблона
  3. Сделать функцию другом с помощью <> перед открывающими скобками, обозначающими параметры
  4. Реализовать функциюпосле вашего класса.
2 голосов
/ 27 октября 2010

Вы должны предоставить аргументы шаблона для всех Forest параметров.

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

Также рассмотрите возможность создания ссылок на аргументы const , чтобы убедиться, что вы не манипулируете ими.1007 *

Есть несколько вопросов о стеке потока относительно шаблонов функций друзей. C ++ FAQ также содержит страницу, которая объясняет некоторые основы.

0 голосов
/ 27 октября 2010

Вы можете определить шаблон operator+ следующим образом:

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

Cheers & hth.,

...