Перегрузка оператора-друга приводит к ошибкам компоновщика, уже определенным в - PullRequest
2 голосов
/ 14 февраля 2012

Я наткнулся на проблему, которую смог обойти, но я не уверен, почему она не работает.

Это код, который я пытался использовать. Поля были раздеты для краткости. Дайте мне знать, если они нужны, и я верну их обратно:

#pragma once
#ifndef __PageStyle__
#define __PageStyle__
class PageStyle
{
public:
    friend bool operator<(const PageStyle& lhs, const PageStyle& rhs);
};

bool operator<(const PageStyle& lhs, const PageStyle& rhs)
{
    return (lhs.name < rhs.name);
}
#endif

И в моих исходных файлах я делаю что-то вроде этого:

#include "PageStyle.h"

...
void PageStyleManager::loadPageStyles() {
    std::set<PageStyle> pageStyles;
    ...
}

Код скомпилирован нормально, но компоновщик выплюнул это:

1>PageStyleManager.obj : error LNK2005: "bool __cdecl operator<(class PageStyle const &,class PageStyle const &)" (??M@YA_NABVPageStyle@@0@Z) already defined in BaseContentFiller.obj

BaseContentFiller является базовым классом для PageStyleManager, а также для других классов, которые также используют PageStyle аналогичным образом.

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

Почему возникла эта проблема? Я убедился, что использовал защиту от жатки, это мой первый реальный опыт с перегрузкой операторов, и я хотел бы знать, что я сделал неправильно.

Ответы [ 2 ]

10 голосов
/ 14 февраля 2012

Если вы включите определение функции в файл заголовка, она будет определена в каждом Единице перевода , где включен файл заголовка.
Это нарушает Одно правило определения и, следовательно, ошибка компоновщика.

Обратите внимание, что средства защиты заголовков или #pragma once просто предотвращают включение одного и того же файла заголовков в один и тот же исходный файл несколько раз, но не определяют его в разных TU.

Возможны два решения проблемы:

  1. Просто добавьте объявление в заголовочный файл и определение только в один файл cpp или
  2. makeфункция, определенная в заголовке как inline.
6 голосов
/ 14 февраля 2012

Не определять operator< в заголовочном файле;просто объявите это там и определите в .cpp файле.#pragma once просто предотвращает включение файла заголовка несколько раз в один и тот же файл .cpp, но он вполне может быть включен в разные файлы .cpp, и в этом случае компоновщик увидит несколько определений operator<.

...