C++静态成员函数和变量

16

我正在通过制作一个小型机器人模拟来学习C ++,但是我在类内使用静态成员函数时遇到了问题。

我的Environment类的定义如下:

class Environment {
    private:
        int numOfRobots;
        int numOfObstacles;

        static void display(); // Displays all initialized objects on the screen

    public:
        Robot *robots;
        Obstacle *obstacles;

        // constructor
        Environment();

        static void processKeySpecialUp(int, int, int); // Processes the keyboard events
};

然后在构造函数中,我像这样初始化机器人和障碍物:

numOfRobots = 1; // How many robots to draw
numOfObstacles = 1;
robots = new Robot[numOfRobots];
obstacles = new Obstacle[numOfObstacles];

这是一个使用这些变量的静态函数示例:

void Environment::display(void) {
    // Draw all robots
    for (int i=0; i<numOfRobots; i++) {
        robots[i].draw();
    }
}

当我尝试编译时,我会收到像这样的错误消息

error: invalid use of member ‘Environment::robots’ in static member function

我尝试将 numOfRobots、numOfObstacles、robots 和 obstacles 声明为 static 变量,但是出现了以下错误:

error: undefined reference to 'Environment::numOfRobots'

如果有人能够解释我做错了什么,我将非常感激。 谢谢!


在您的代码的静态版本中,您未能定义 Environment::numOfRobots,而只是声明了它。请在其中一个源文件中添加 int Environment::numOfRobots = 1;。一本关于C++的书籍将会解释如何声明和定义变量以及其他重要信息。 - john
1
既然你说你正在学习C ++,我可以建议使用标准库吗?具体来说,使用std :: vector而不是原始数组。 - bitmask
7个回答

19

静态方法无法使用其类中的非静态变量。

这是因为静态方法可以像Environment::display()这样被调用,而不需要类实例,这使得任何在其中使用的非静态变量都是不规则的,也就是说,它们没有父对象。

您应该考虑为什么要尝试使用静态成员来达到此目的。基本上,静态方法的一种用法示例如下:

class Environment
{
private:
    static int maxRobots;
public:
    static void setMaxRobots(int max)
    {
        maxRobots = max;
    }
    void printMaxRobots();
};

void Environment::printMaxRobots()
{
    std::cout << maxRobots;
}

你需要在全局范围内初始化变量,例如:

int Environment::maxRobots = 0;

例如,在main内部,您可以使用:

Environment::setMaxRobots(5);

Environment *env = new Environment;
env->printMaxRobots();
delete env;

你有什么想法可以解决这个问题吗?我尝试将那些变量设为静态的,但是我一直在收到错误信息(请参见我的问题的第二部分)... - Maxim Neaga
1
你必须初始化静态变量,请参阅静态成员函数 - Toribio

3
这里有两个问题——你想要实现的算法和它无法编译的原因。
为什么它不能编译。
你在混合使用静态变量和实例变量/方法,这是可以的。但是你不能在静态方法中引用实例变量。这就是“无效使用”的错误。如果你思考一下,这是有道理的。只有一个“static void display()”方法。所以如果它试图引用非静态(实例)变量“robots”,它是指哪一个?可能有10个……或没有一个。
你想要实现的逻辑。
看起来你想要一个管理N个机器人的单一环境类。这是完全合理的。一种常见的方法是使环境成为“单例”——一个只允许一个实例变量的变量。然后它可以分配任意数量的机器人,并自由地引用它们,因为没有静态变量/方法。
另一种方法是直接将整个环境类设置为静态。然后保持机器人的(静态)列表。但我认为大多数人现在会说选项#1是正确的方式。

@user1739770,这个简单的答案是你有一个返回指向你的类的指针的静态方法;如果没有,则创建并返回它,否则返回指向现有对象的指针。这样你就有了一个“实例”类,但永远不会得到多份副本。实际上,这种方法在实践中有点难以处理:请参见https://dev59.com/Q3NA5IYBdhLWcg3wVcJx。 - Mark Stevens

2

static成员是指使用它们时不需要实例化的成员,因此它们没有this,因为this需要实例化:

class foo {
public
    void test() {
        n = 10; // this is actually this->n = 10
    }
    static void static_test() {
        n = 10; // error, since we don't have a this in static function
    }
private:
    int n;
};

正如您所见,您无法在static函数中调用实例函数或使用实例成员。因此,如果函数的操作不依赖于实例,并且如果您需要在函数中执行需要this的操作,则函数应该是静态的。如果您要调用这个需要this的函数,您必须考虑为什么我称这个函数为static

如果一个成员变量应该在class的所有实例之间共享,并且它不属于任何特定的class实例,则该变量是static的。例如,我可能想要拥有一个计数器来记录我类的已创建实例数量:

// with_counter.h
class with_counter {
private:
    static int counter; // This is just declaration of my variable
public:
    with_counter() {++counter;}
    ~with_counter() {--counter;}

    static int alive_instances() {
        // this action require no instance, so it can be static
        return counter;
    }
};

// with_counter.cpp
int with_counter::counter = 0; // instantiate static member and initialize it here

2
第一个错误指出不能在静态成员函数中使用非静态成员。
第二个错误指出你需要定义静态成员,除了声明它们。必须在源文件(而不是头文件)中定义静态成员变量,像这样:
```cpp class MyClass { static int myStaticMember; };
int MyClass::myStaticMember = 0; // define myStaticMember outside class ```
int Environment::numOfRobots = 0;

您不需要任何静态成员。为了拥有绝对正确和可移植的GLUT接口,需要一个类型为Environment的文件级对象和一个声明了C链接的文件级(非成员)函数。为方便起见,还需要一个名为display的成员函数。

class Environment 
{
 public:
   void display() { ... }
   ... 
};

static Environment env;
extern "C" void display () { env.display(); }

1
静态成员函数是一种可以在没有实际对象的情况下调用的函数。然而,您的函数Environment::display使用变量numOfRobotsrobots,它们都存在于Environment类的特定实例中。要么使display非静态(为什么要使它成为静态的?),要么将机器人也作为Environment的静态成员。

在您的情况下,我不认为有理由使displayprocessKeySpecialUp成为static,所以只需将它们设置为普通成员函数即可。如果您想知道何时应该使用成员函数static,请考虑如果没有创建该类的任何对象(即没有调用构造函数),那么该函数是否有意义。如果该函数在此上下文中没有意义,则不应将其设置为static


我正在使用Glut库来处理图形,并且我需要保持显示静态。正如我之前所说,我尝试将这些变量设置为静态,但是我一直收到错误消息:undefined reference to 'Environment::numOfRobots'。 - Maxim Neaga

0
一个静态方法无法访问实例变量。如果你想要访问实例变量,需要从该方法中移除 static 关键字。如果这些值在所有机器人实例中都相同,则将它们设置为静态变量,该方法可以保持静态。

0
如果你想在静态成员函数中访问成员变量,只需创建成员变量的静态指针并在函数中使用它即可!

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接