16

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

我的环境类定义如下:

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 和障碍物static,但后来我遇到了类似的错误

error: undefined reference to 'Environment::numOfRobots'

我将不胜感激有人可以解释我做错了什么。谢谢!

4

7 回答 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;
于 2012-11-02T22:49:11.927 回答
3

这里有 2 个问题 - 您尝试实现的算法以及它无法编译的机制。

为什么它不编译。

您正在混合静态和实例变量/方法 - 这很好。但是您不能从静态方法中引用实例变量。那就是“无效使用”错误。如果你仔细想想,这是有道理的。只有一种“静态无效显示()”方法。因此,如果它试图引用非静态(实例)变量“robots”,它指的是哪一个?可能有 10 个……或者没有。

您尝试实现的逻辑。

看起来您想要一个管理 N 个机器人的环境类。这是完全合乎逻辑的。一种常见的方法是使 Environment 成为“单例” - 一个仅允许单个实例的实例变量。然后它可以根据需要分配尽可能多的机器人并自由引用它们,因为没有静态变量/方法。

另一种方法是直接将整个 Environment 类设为静态。然后保留一个(静态)机器人列表。但我认为现在大多数人会说选项#1是要走的路。

于 2012-11-02T22:53:54.280 回答
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函数内使用实例成员。所以一个函数应该是静态的,如果它的操作不依赖于实例,并且如果你在你的函数中需要一个操作 require this,你必须想为什么我static在它 require的时候调用这个函数this

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

// 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
于 2012-11-02T22:53:17.073 回答
2

第一个错误说您不能在静态成员函数中使用非静态成员。

第二个说除了声明它们之外,您还需要定义静态成员您必须在类之外定义静态成员变量,在源文件中(而不是在头文件中),如下所示:

int Environment::numOfRobots = 0;

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

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

static Environment env;
extern "C" void display () { env.display(); }
于 2012-11-02T23:03:50.017 回答
1

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

在您的情况下,我看不出制作displayor的理由processKeySpecialUp static,因此只需将它们设为正常的成员函数即可。如果您想知道何时应该使用成员函数static,请考虑如果没有创建该类的对象(即没有调用构造函数),该函数是否有意义。如果函数在这种情况下没有意义,那么它不应该是static.

于 2012-11-02T22:48:38.503 回答
0

静态方法不能访问实例变量。如果要访问实例变量,请从方法中删除 static。如果这些值在所有机器人实例中都可以相同,则将它们设为静态变量,并且该方法可以保持静态。

于 2012-11-02T22:50:23.337 回答
0

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

于 2021-02-22T12:47:05.483 回答