c ++ перегруженный метод в производном классе - PullRequest
3 голосов
/ 24 января 2010

У меня следующий вопрос:

Предположим, базовый класс A с методом:

A& operator+(A& a) {...}

У меня также есть производный класс B, который перегружает (или, по крайней мере, так) этот метод:

A& operator+(B& b) {...}

Проблема в том, что если я хочу вызвать что-то вроде: b + a (где b типа B и a типа A) я получаю ошибку компиляции. (ошибка C2679: двоичный «+»: не найден оператор, который принимает правый операнд типа «A» (или нет приемлемого преобразования)).

Разве это не должно вызывать метод базового класса? (похоже, он переопределяет метод ..) Если нет, то почему? Есть ли способ исправить это (не говорите мне перегрузить метод в B с A &)

Извините, я не даю примеров в форматированном тексте, но я не знаю, как его отформатировать.

Заранее спасибо!

PS Я использую Visual Studio 2010 бета.

Ответы [ 4 ]

3 голосов
/ 24 января 2010

Проблема называется скрытие - функция-член в производном классе скрывает функции с одинаковыми именами в базовом классе. В этом случае вы не можете получить доступ к A :: operator + (A &), потому что он скрыт B :: operator +. Способ исправить это состоит в том, чтобы определить B :: operator + (A &) и, возможно, заставить его вызывать функцию базового класса.

Редактировать: В C ++ FAQ Lite есть раздел , который более подробно описывает эту проблему и предлагает другое возможное решение, а именно ключевое слово using.

2 голосов
/ 24 января 2010

Нет, это не вызовет функцию базового класса. Класс B имеет operator+, он не принимает правильный параметр, конец истории.

Вы можете определить operator+ как свободную функцию, но не в любом классе. Возможно, друг, если ему нужен доступ к личным данным:

A operator+(const A &lhs, const A &rhs) { ... }
B operator+(const B &lhs, const B &rhs) { ... }

Тогда b + a вызовет первый оператор, как и a + b. b + b назовет второго.

В качестве альтернативы, вы можете «убрать» реализацию базового класса, поместив это в класс B:

using A::operator+;

хотя, вероятно, лучше этого не делать. Большинство операторов работают лучше как свободные функции, потому что тогда вы получаете автоматические преобразования для обоих операндов. C ++ никогда не выполняет преобразования на LHS вызова функции-члена.

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

2 голосов
/ 24 января 2010

Проблема в том, что вы определяете оператор member , поэтому при вызове b + a это приводит к b.operator+( a ), которого не существует.

Принятая практика заключается в определении свободных операторов , которые сами будут вызывать [виртуальные] члены в аргументах.

Редактировать:

Стандартный пример того, о чем я говорю, - это адаптация иерархии классов для потоковой передачи:
class base
{
public:

  virtual ~base();
  virtual void print( std::ostream& ) const;
};

std::ostream& operator<<( std::ostream& out, const base& b )
{
  b.print( out ); return out;
}

Это на самом деле не работает для математических операций, так как вы хотите возвращать значение [const], а не ссылку, то есть избегать глупостей, подобных a + b = c;.

Например, добавление действительных и комплексных чисел определено, но в результате получается комплексное число, поэтому вы не можете получить complex из real. Другой способ - возможно. Но все же вы хотите определить точный интерфейс операций:

const real operator+( const real&, const real& );
const complex operator+( const complex&, const complex& );

Надеюсь, это даст вам достаточно для переосмысления вашего дизайна:)

0 голосов
/ 24 января 2010

Несколько вещей приходят на ум. Во-первых, вы, как правило, захотите сделать оператор + «виртуальным». Тогда производный оператор, принимающий ссылку на B, будет переопределен из-за ковариации, вместо того, чтобы скрывать реализацию базового класса, что здесь и происходит.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...