Определение функции-члена C++ вне класса | повторяющиеся символы

В одном из заголовочных файлов моих классов Lfo.h у меня есть определение класса, в котором я помещаю определение функции-члена из класса (может быть, лучше иметь отдельный файл .cpp, но его можно разместить здесь?):

// Lfo.h
class CLfo
{
public:
    static int create (CLfo*& pCLfo);
};

int CLfo::create(CLfo *&pCLfo)
{
    pCLfo = new CLfo;
    return 0;
}

Затем у меня есть еще один класс под названием CVibrato:

// Vibrato.h
class CVibrato
{
public:
    static int create (CVibrato*& pCVibrato);
private:
    CVibrato();
};

и файл .cpp (в файл cpp я включаю Lfo.h, потому что позже класс вибрато будет иметь член lfo, но я не реализовал его прямо сейчас):

// Vibrato.cpp
#include "Lfo.h"
#include "Vibrato.h"
int CVibrato::create(CVibrato *&pCVibrato)
{
    pCVibrato = new CVibrato();
    return 0;

}

CVibrato::CVibrato()
{
}

Затем я хочу создать экземпляр класса вибрато в main()

#include "Vibrato.h"
#include "Lfo.h"   // if comment this line out there will be no error, why is that?

int main()
{
    CVibrato *vibrato = 0;
    CVibrato::create(vibrato);
    return 0;
}

Однако я получаю ошибку 1 duplicate symbol for architecture x86_64. Что дублируется? Похоже причина в Lfo.h, определение функции-члена я выношу за пределы класса, если выношу внутрь, то программа работает корректно. Но я не могу понять. В С++ разве нам не разрешено это делать? Кстати, если один из моих классов (в моем случае вибрато) будет иметь член класса другого класса (в данном случае lfo), я должен включить заголовочный файл класса-члена в файл .h (vibrato.h). или файл .cpp (vibrato.cpp)?


person Yongliang He    schedule 04.03.2018    source источник
comment
Пожалуйста, разделите свой код на MCVE, минимальный, полный, проверяемый пример.   -  person Ulrich Eckhardt    schedule 05.03.2018
comment
См. одно правило определения.   -  person Raymond Chen    schedule 05.03.2018
comment
Ваш заголовочный файл определяет int CLfo::create(CLfo *&pCLfo);. Посмотри на это. Это прямо там, на виду. Таким образом, любая единица перевода, включающая этот заголовочный файл, будет определять этот член класса. Если его включает более одной единицы перевода, это ошибка повторяющегося символа во время компоновки. Каждый член класса, функция и т.д. al., должен быть определен ровно один раз. Ни больше ни меньше. Кажется довольно очевидным, что именно в этой проблеме вам не совсем понятно?   -  person Sam Varshavchik    schedule 05.03.2018
comment
@SamVarshavchik, почему простое размещение определения внутри области класса решает проблему?   -  person Yongliang He    schedule 05.03.2018
comment
Потому что он становится так называемым встроенным определением. Обратите внимание на второй абзац в начале этой цитируемой статьи и абзац № 1 в разделе описания.   -  person Sam Varshavchik    schedule 05.03.2018


Ответы (2)


Классы являются объявлениями. Код не создается из объявления. Даже если у вас есть функция-член в классе, она обрабатывается компилятором как inline. Тела функций можно поместить в заголовок, но они всегда должны быть объявлены как inline. Компилятор может на самом деле не встраивать его, но он будет рассматривать его как единственный экземпляр для создания кода.

В любое время вы:

void function( ) { }

Код создается для этой функции. Если заголовок включен более одного раза, компилятору предлагается создать код более одного раза. Но все функции должны иметь уникальные имена! Таким образом, вы получаете повторяющуюся ошибку. Вот почему строки генерации кода принадлежат файлам .cpp.

«inline» указывает компилятору не создавать немедленный код, а создавать код в точке использования.

person lakeweb    schedule 04.03.2018

Вы не можете поместить определение метода класса непосредственно в заголовочный файл, если только вы явно не пометите его как встроенный. Как следующее:

// Lfo.h
class CLfo
{
public:
    inline static int create (CLfo*& pCLfo);
};

int CLfo::create(CLfo *&pCLfo)
{
    pCLfo = new CLfo;
    return 0;
}

Or,

// Lfo.h
class CLfo
{
public:
    static int create (CLfo*& pCLfo);
};

inline int CLfo::create(CLfo *&pCLfo)
{
    pCLfo = new CLfo;
    return 0;
}
person llllllllll    schedule 04.03.2018