C ++: проблема при перегрузке одного и того же оператора в 2 разных классах - PullRequest
0 голосов
/ 30 января 2011

Прежде всего большое спасибо за ваши подсказки.

У меня возникла особая проблема при попытке выполнить задание. Я почти уверен, что что-то не так с пространствами имен, включениями, заголовочными файлами и всем этим, но на самом деле не знаю, что происходит не так.

Дело в том, что мне нужны два разных класса (скажем, Car и CarShop), каждый из которых должен перегружать оператор +.

  • Car -> Car &operator+(const Car &c) (следует «добавить» две машины)
  • CarShop -> CarShop &operator+(const Car &c) (следует «добавить» автомобиль в существующий CarShop)

В файле CarShop.h мне нужно #include "car.h", так как он много работает с различными "автомобильными" объектами. Более того, в моем основном тестовом классе, скажем, main.cpp, мне также нужно #include "car.h" и #include "carshop.h".

Здесь я получаю сообщение об ошибке . Visual Studio (мы работаем с ней как с нашей IDE) выдает мне ошибки «LNK1169 & LNK2005», объясняя, что «один или несколько символов определены одновременно».

Кто-нибудь может мне помочь, пожалуйста? Что я должен сделать, чтобы избежать конфликта между двумя перегруженными операторами?

PS. Оба из них (2 перегруженных оператора) объявлены как функции-друзья для соответствующих классов (в файлах .h) и реализованы в соответствующем файле .cpp.

Ответы [ 3 ]

2 голосов
/ 30 января 2011

Как уже отмечали другие, вы не можете просто объявить их друзьями:

Car &operator+(const Car &c);
CarShop &operator+(const Car &c);

Даже если бы вы могли скомпилировать и связать его, это просто не сработало бы. И вы не можете связать, потому что они имеют одинаковые подписи (возвращаемый тип не включен в подпись). У вас есть два варианта: либо иметь друзей, не являющихся членами, либо иметь функции-члены (объявление друзей не требуется). Если вы хотите, чтобы у вас не было друзей, вы должны были объявить их так, указав оба операнда:

Car operator+(const Car &c1, const Car &c2);
CarShop operator+(const CarShop &cs, const Car &c);

Обратите внимание, что, как указал Джеймс, эти операторы не должны возвращать ссылки. Они возвращают новые экземпляры по определению.

Однако операторы друзей необходимы, только если первый параметр имеет тип, отличный от любого класса, который находится под вашим контролем. Например, было бы необходимо объявить оператор друга, если первый параметр имеет тип std :: string или int. Однако, поскольку это ваши классы, вам лучше объявить операторы как члены:

Car operator+(const Car &c2); // this is declared inside the Car class
CarShop operator+(const Car &c); // this is declared inside the CarShop class

Нет необходимости в друзьях здесь, поскольку они являются членами. Ну, строго говоря, вы можете объявить CarShop::operator+(const Car&) своим другом в классе Car, если вы хотите получить доступ к личным членам Car. Но для Car::operator+(const Car&) это абсолютно не нужно.

1 голос
/ 30 января 2011

Краткий ответ: не объявляйте этих операторов друзьями.

Длинный ответ: Когда функция объявляется как друг, это означает, что она не принадлежит классу, где она «объявлена» (на самом деле, вы не объявляете функцию там), вы просто говорите, что функция (обратите внимание, что она будет функция C, а не функция-член) является другом этого класса и может обращаться к личным данным.

Вы, вероятно, используете друга, потому что вы видели код, использующий его для оператора << (с std :: ostream), но он не может быть членом, потому что вам нужно быть функцией-членом std :: ostream. Убрав друга, вы сделаете «этого» первым оператором. </p>

1 голос
/ 30 января 2011

Вы многократно объявляете тип автомобиля. В вашем main.cpp вы включаете car.h и carshop.h, в то время как carshop.h уже включает car.h. Без включения защиты это приводит к ошибкам компоновщика.

У вас есть две возможности:

  • удалить #include "Car.h" из вашего main.cpp
  • используйте, например, охранников:

anyfile.h

#pragma once

/* ... the rest of your code ... */

В случайном случае ваш компилятор не поддерживает директиву #pragma once, вы всегда можете использовать стандартные, хотя и немного громоздкие, макросохранители в заголовках:

myheader.h

#ifndef MYHEADER_H
#define MYHEADER_H

/* ... your code here ... */

#endif
...