对受保护静态成员的未定义引用。我该如何解决?

时间:2017-01-03 15:38:34

标签: c++ class g++ linker-errors

在robots.hpp中,我有classrobots。我希望每个机器人都有一个指向另一个机器人的指针,最后一个机器人。我也希望每个人都有一个独特的身份。为此,我有一个计算机器人数量的变量。

似乎我无法在类定义中初始化我的静态变量。我查找了如何解决这个问题,并找到了一些建议在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标准(否则cstdint抱怨))

我希望代码能够使poiRobot指向nullNumofRobots等于0。

1 个答案:

答案 0 :(得分:0)

您应该能够摆脱static bool hasBeenInitialised;bool robot::hasBeenInitialised=false;以及初始化函数,只需在cpp文件中直接声明uint_least8_t robot::NumOfRobots = 0;robot* robot::poiRobot = nullptr即可。这样他们自己初始化为0并自动为空。正如评论中所提到的,这是有效的,应该能够以这种方式在源文件中定义受保护的静态变量。

编辑:关于您在编辑中发布的代码,看起来您永远不会定义robot :: poiRobot和robot :: NumRobots。您是否尝试过我上面发布的代码?

基本上,项目中的每个cpp文件都必须由编译器编译成翻译单元。然后链接器通过并获取所有翻译单元并将它们链接在一起。任何看到你的机器人类的cpp文件都会看到你已经承诺这两个变量存在于某个地方,因此当你使用它们时它会允许它(就目前而言,它们存在并且很好用) 。当链接器出现时,它将看到对这些变量的引用,并尝试找到它们被定义的转换单元,以便它可以完成其工作(将所有内容链接在一起)。此时,它不会在任何翻译单元中看到定义,这就是它为您提供错误的原因。

uint_least8_t robot::NumOfRobots = 0;robot* robot::poiRobot = nullptr是您要查找的定义,应该放在您的cpp文件中。如果在使用这些之后你会得到另一个关于它们受到保护的错误,就像你之前暗示的那样,发布该代码以便我们可以看到为什么会发生这种情况。

编辑2关于&#34;似乎我无法在类定义中初始化我的静态变量。&#34;:当您将该定义放在头文件中时,包含的每个cpp文件您的标题将定义它自己的变量版本。当链接器链接所有内容时,它将在不同的转换单元中看到同一变量的多个定义,并且违反了&#34;一个定义规则&#34;在C ++(ODR)中。这就是为什么它会给你一个错误。将它放在robots.cpp中是正确的,因此只有1个翻译单元(在本例中为robots.cpp)将具有该定义。然后你必须确保你的项目中正在编译robots.cpp,以便链接器可以使用转换单元...因为你可能错误地只在源文件中包含robots.h,但是从不告诉编译器编译robots.cpp。