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

undefined reference to protected static member. How do I solve it?

在robots.hpp我有一个classrobots。我希望每个机器人都有一个指向另一个机器人的指针,即最后声明的那个。我还希望每个人都有一个唯一的 ID。为此,我有一个变量来计算机器人的数量。

看来我无法在 class 定义中初始化我的静态变量。我查找了如何解决该问题,并在 robots.cpp 中找到了一些建议初始化它们的内容。但是,这给了我一个错误,说它们受到保护,所以我不能那样做。所以现在我有一个函数,它在开始时只被构造函数调用一次。

但是,这给了我一个错误,说我不能这样做,因为它们还没有被定义。

robots.hpp中的class定义:

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 成为指向 null 的指针,并且 NumofRobots 等于 0。

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

编辑:关于您在编辑中 post 编辑的代码,您似乎从未定义 robot::poiRobot 和 robot::NumRobots。你试过我在上面 post 编写的代码了吗?

基本上,你项目中的每一个cpp文件都要被编译器编译成一个翻译单元。然后 linker 通过并将所有翻译单元和 links 放在一起。任何看到你的机器人 class 的 cpp 文件都会看到你已经承诺这两个变量存在于某处,因此当你使用它们时它会允许它(就目前而言,它们存在并且有利于走)。当 linker 出现时,它会看到对这些变量的引用,并尝试找到它们在哪个翻译单元中定义,以便它可以完成它的工作(link 一切都在一起)。此时,它不会在任何翻译单元中看到定义,这就是它给您该错误的原因。

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

关于 "It seems that I can't initialise my static variables in the class definition." 的编辑 2:当您将该定义放入头文件中时,包含您的头文件的每个 cpp 文件都将定义它自己的该变量版本。当 linker 转到 link everything 时,它将在不同的翻译单元中看到同一变量的多个定义,这违反了 C++ (ODR) 中的 "One Definition Rule"。这就是为什么它会给你一个错误。将它放在 robots.cpp 中是正确的,因此只有 1 个翻译单元(在本例中为 robots.cpp)将具有定义。然后您必须确保 robots.cpp 正在您的项目中编译,以便翻译单元可用于 linker... 因为您可能错误地在源代码中包含 robots.h文件,但永远不要告诉编译器编译 robots.cpp.