2017-01-03 3 views
1

В robots.hpp у меня есть class, robots. Я хочу, чтобы каждый робот имел указатель на другой робот, тот, который был объявлен последним. Я также хочу, чтобы у каждого был уникальный идентификатор. Для этого у меня есть переменная, которая подсчитывает количество роботов.Неопределенная ссылка на защищенный статический член. Как это решить?

Кажется, что я не могу инициализировать свои статические переменные в определении класса. Я посмотрел, как это решить, и нашел что-то, рекомендующее инициализировать их в robots.cpp. Тем не менее, это дает мне ошибку, говоря, что они защищены, и поэтому я не могу этого сделать. Итак, теперь у меня есть функция, вызываемая конструктором только один раз, в начале.

Однако, что дает мне ошибку, говоря, что я не могу этого сделать, потому что они еще не определены.

Определение класса в robots.hpp:

class robot 
{ 
    public: 
     ///initialiser. 
     robot(); 
     [...] 
     ///initialises all robots 
     void initrobots(); 
     ///id of robot 
     const uint_least8_t id=NumOfRobots++; 
     static bool hasBeenInitialised; 
    protected: 
     ///number of robots. 
     static uint_least8_t NumOfRobots; 
     ///pointer to the next robot that needs pointing to. 
     static robot* poiRobot; 
     [...] 
     ///pointer to next robot 
     robot* nextRobot; 
}; 

robots.cpp:

bool robot::hasBeenInitialised=false; 

void robot::initrobots(){ 
    poiRobot=NULL; 
    NumOfRobots=0; 
} 
robot::robot(){ 
    if(!hasBeenInitialised){ 
     initrobots(); 
     hasBeenInitialised=true; 
    } 
[...] 
} 

код, который генерирует эту ошибку заключается в следующем:

#include <cstdint> 
#include <cstdlib> 

class robot 
{ 
    public: 
     ///initialiser. 
     robot(); 
     //[...] 
     ///initialises all robots 
     void initrobots(); 
     ///id of robot 
     const uint_least8_t id=NumOfRobots++; 
     static bool hasBeenInitialised; 
    protected: 
     ///number of robots. 
     static uint_least8_t NumOfRobots; 
     ///pointer to the next robot that needs pointing to. 
     static robot* poiRobot; 
     //[...] 
     ///pointer to next robot 
     robot* nextRobot; 
}; 

bool robot::hasBeenInitialised=false; 

void robot::initrobots(){ 
    poiRobot=NULL; 
    NumOfRobots=0; 
} 
robot::robot(){ 
    if(!hasBeenInitialised){ 
     initrobots(); 
     hasBeenInitialised=true; 
    } 
} 

int main(){ 
    return 0; 
} 

Если я скомпилировать его он не жалуется, но он жалуется, если я его построю (используя geany, чтобы делать вещи отдельно, C++ 11 standard (в противном случае cstdint жалуется))

Я хотел бы код, чтобы сделать poiRobot указатель null и NumofRobots равен 0.

+3

Можете ли вы создать [mcve], где вы показываете, как вы пытались инициализировать элемент? – NathanOliver

+0

Я просто попытался скомпилировать 'class Test {protected: static int x; }; int Test :: x = 2; 'в GCC и работает отлично. – Frank

+1

Защищенность не должна иметь значения; 'robot * robot :: poiRobot;' должен работать так же хорошо, как определение 'hasBeenInitialised'. Если это не так, отправьте код, создающий ошибку, вместе с копией сообщения об ошибке (не перефразируйте, используйте «Копировать» и «Вставить»). – molbdnilo

ответ

0

Вы должны быть в состоянии избавиться от static bool hasBeenInitialised; и bool robot::hasBeenInitialised=false;, а также ваших функций инициализации и просто объявите uint_least8_t robot::NumOfRobots = 0; и robot* robot::poiRobot = nullptr непосредственно в файл cpp. Таким образом, они автоматически инициализируются до 0 и нулевыми значениями автоматически. Как уже упоминалось в комментариях, это верно, поэтому защищенные статические переменные должны быть определены в исходном файле таким образом.

Редактировать: Что касается кода, который вы опубликовали в своем редактировании, похоже, что вы никогда не определяете робота :: poiRobot и robot :: NumRobots. Вы попробовали код, который я разместил выше?

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

uint_least8_t robot::NumOfRobots = 0; и robot* robot::poiRobot = nullptr - это определения, которые вы ищете, и должны находиться в вашем файле cpp. Если после использования вы получите еще одну ошибку о том, что они защищены, как вы намекали ранее, отправьте этот код, чтобы мы могли понять, почему это происходит.

Редактировать 2 в отношении «Кажется, что я не могу инициализировать свои статические переменные в определении класса». Когда вы вставляете это определение в заголовочный файл, каждый файл cpp, содержащий ваш заголовок, будет определять его собственную версию этой переменной.Когда компоновщик идет по ссылке, он увидит несколько определений в разных единицах перевода для одной и той же переменной и нарушает «правило определения» в C++ (ODR). Вот почему это даст вам ошибку. Правильно положить его в robots.cpp, так что только 1 единица перевода (robots.cpp в этом случае) будет иметь определение. Затем вы должны убедиться, что robots.cpp скомпилирован в вашем проекте, чтобы модуль перевода был доступен для компоновщика ... поскольку вы могли ошибочно включить robots.h в исходные файлы, но никогда не говорите компилятору компилировать robots.cpp.

+1

ОП сказал, что они сделали это, но получили сообщение об ошибке. Нам нужно, чтобы OP обеспечивал mcve, включая ошибку, прежде чем мы узнаем, что происходит на самом деле. – NathanOliver

+0

@MarkGardner обновлен в отношении вашего редактирования – RyanP

+0

Мне нужно, чтобы они были статическими и непостоянными. И я рассказываю, что он компилирует robots.cpp. –