Странная множественная ошибка определения

vio@!@#$:~/cpp/OOP/6$ g++ -o main main.o NormalAccount.o HighCreditAccount.o Account.o AccountHandler.o
AccountHandler.o:(.bss+0x0): multiple definition of `AccountHandler::account_number'
main.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status

Я получил сообщение об ошибке выше. Но я не смог найти код, где он определен многократно, поэтому я изменил все account_number на number_of_account в «account.h» и «AccountHandler.cpp» и

vio@!@#$:~/cpp/OOP/6$ vi AccountHandler.cpp 
vio@!@#$:~/cpp/OOP/6$ g++ -c AccountHandler.cpp 
vio@!@#$:~/cpp/OOP/6$ g++ -o main main.o NormalAccount.o HighCreditAccount.o Account.o AccountHandler.o
vio@!@#$:~/cpp/OOP/6$

он хорошо скомпилирован.

После этого я немного изменил main.cpp

vio@!@#$:~/cpp/OOP/6$ g++ -c main.cpp
vio@!@#$:~/cpp/OOP/6$ g++ -o main main.o NormalAccount.o HighCreditAccount.o Account.o AccountHandler.o
AccountHandler.o:(.bss+0x0): multiple definition of `AccountHandler::number_of_account'
main.o:(.bss+0x0): first defined here
collect2: ld returned 1 exit status

и снова появилось сообщение об ошибке.

Я использовал #ifndef #define #define во всем заголовочном файле, и когда я изменил переменную в AccountHandler.cpp и accounthandler.h, он снова хорошо скомпилировался, поэтому мне интересно, почему это происходит.

Вот код:

#ifndef __ACCOUNTHANDLER_H__
#define __ACCOUNTHANDLER_H__

#include "account.h"

class AccountHandler
{
private:
    Account* account[100];
    static int number_of_account;
public:
    AccountHandler(){}

    void show_menu();
    void make_account();
    void deposit_money();
    void withdraw_money();
    void show_all_account_info();

    ~AccountHandler();
};

int AccountHandler::number_of_account=0;

#endif

person user2323357    schedule 26.04.2013    source источник
comment
Что такое AccountHandler::account_number (или AccountHandler::number_of_account)? Как вы это декларируете? Как вы это определяете? И самое главное, где вы это определяете? Вам нужно показать нам какой-то код, иначе ответить на этот вопрос, не угадывая, будет практически невозможно.   -  person Some programmer dude    schedule 26.04.2013
comment
Защита заголовков только предотвращает многократное включение (и, следовательно, несколько определений) внутри одной единицы перевода. Если вы определяете глобальный объект в заголовке, вы получите его определение в каждой единице перевода (cpp), куда вы включаете этот заголовок (нарушая с ним одно правило определения). Вы можете либо определить объект с внутренней связью (static), либо просто объявить его как extern и определить ровно в одной единице перевода.   -  person jrok    schedule 26.04.2013
comment
@jrok: поскольку он выглядит как статический член класса, вы не можете присвоить ему внутреннюю связь или использовать extern в объявлении. Если бы это было в пространстве имен, то давать ему внутреннюю компоновку почти наверняка было бы неправильно, поскольку вы получите отдельную копию в каждой единице перевода; это, мягко говоря, сбивает с толку.   -  person Mike Seymour    schedule 26.04.2013
comment
Возможно, вы могли бы показать нам, где и как объявляется и определяется переменная. Без этой информации ответ на вопрос предполагает определенное количество догадок.   -  person Mike Seymour    schedule 26.04.2013
comment
@MikeSeymour Ах да, я проигнорировал тот факт, что это член класса. Ну, у них по умолчанию есть внешняя связь. Я согласен с тем, что внутренняя связь, скорее всего, не то, чего хочет ОП.   -  person jrok    schedule 26.04.2013
comment
Хорошо, я переформатировал код, чтобы мы могли его прочитать. Как видите, переменная определена в конце заголовка. Переместите это определение в исходный файл.   -  person Mike Seymour    schedule 26.04.2013
comment
Я очень ценю это. Я впервые в stackoverflow, и мне это очень нравится. Еще раз спасибо за ответ на мой вопрос   -  person user2323357    schedule 26.04.2013
comment
@ user2323357: Не беспокойтесь. Когда вы публикуете код в вопросе, он должен иметь отступ в 4 пробела для правильного форматирования; вы можете сделать это автоматически, выбрав код и нажав кнопку {}.   -  person Mike Seymour    schedule 26.04.2013
comment
Это не проблема, но имена, содержащие два символа подчеркивания (__ACCOUNTHANDLER_H__), и имена, начинающиеся с символа подчеркивания, за которым следует заглавная буква, зарезервированы для реализации. Не используйте их.   -  person Pete Becker    schedule 26.04.2013


Ответы (1)


Если вы определяете что-то в заголовке, то это будет определено в каждой единице перевода, которая включает этот заголовок — в вашем случае и AccountHandler, и main. Вы должны объявить его в заголовке (если к нему нужно получить доступ из нескольких модулей) и определить только в одном исходном файле.

Предполагая, что это статический член класса (я должен догадаться, поскольку вы забыли показать нам код), вы хотите что-то вроде:

// header
class AccountHandler 
{
public:
    static size_t number_of_account; // declaration

    // other members...
};

// source file
size_t AccountHandler::number_of_account; // definition

Предположительно, в вашем коде это определение находится в заголовке.

Это предполагает, что он вообще должен быть статичным; что он не зависит от какой-либо конкретной учетной записи (например, представляет количество существующих учетных записей), а не связан с каждой учетной записью (например, представляет номер учетной записи). Если он не должен быть статичным, убедитесь, что он не объявлен static.

Включение охранников в этом не поможет; они предотвращают включение заголовка более одного раза в каждую единицу перевода, но все же позволяют включать их из нескольких единиц.

person Mike Seymour    schedule 26.04.2013
comment
я могу понять, но как я могу решить это? Мне нужно использовать класс AccountHandler в main, он объявлен в accounthandler.h и определен в AccountHandler.cpp. Должен ли я комбинировать accounthandler.h и AccountHandler.cpp? И почему он хорошо скомпилирован сразу после редактирования AccountHandler.cpp и accounthandler.h? - person user2323357; 26.04.2013
comment
@user2323357: user2323357: Похоже, что это определено в заголовке. Но не видя вашего кода, я не могу быть уверен; это просто ваше слово против компилятора. Внимательно просмотрите все заголовки, чтобы убедиться, что он действительно не определен ни в одном из них. - person Mike Seymour; 26.04.2013
comment
@ user2323357: Должен ли я объединить accounthandler.h и AccountHandler.cpp? Почти наверняка нет. Просто убедитесь, что ваши заголовки содержат только объявления, а не определения переменных. - person Mike Seymour; 26.04.2013
comment
@ user2323357: Спасибо за публикацию кода. Мое предположение было верным - переменная определена в конце заголовка, и вместо этого это определение должно быть в одном исходном файле. - person Mike Seymour; 26.04.2013
comment
Я думаю, что определение должно быть похоже на size_t AccountHandler::number_of_account; исключить «статический», если я прав, пожалуйста, отредактируйте код выше - person user2323357; 26.04.2013
comment
@ user2323357: Да, вы совершенно правы; static идет только в объявлении. - person Mike Seymour; 26.04.2013