16

I am learning C++ by making a small robot simulation and I'm having trouble with static member functions inside classes.

I have my Environment class defined like this:

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
};

Then in the constructor I initialize the robots and obstacles like this:

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

Here is example of static function that uses those variables:

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

When I try to compile, I get error messages like

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

I tried making numOfRobots, numOfObstacles, robots and obstacles static, but then I got errors like

error: undefined reference to 'Environment::numOfRobots'

I would greatly appreciate of someone could explain me what I am doing wrong. Thank you!

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 つの問題があります。実装しようとしているアルゴリズムと、それがコンパイルされない理由のメカニズムです。

コンパイルされない理由。

静的変数とインスタンス変数/メソッドを混在させています-これは問題ありません。ただし、静的メソッド内からインスタンス変数を参照することはできません。それが「無効な使用」エラーです。考えてみれば、それは理にかなっています。「static void display()」メソッドは 1 つだけです。非静的 (インスタンス) 変数「ロボット」を参照しようとすると、どの変数を参照しているのでしょうか? 10 ... または 0 になる可能性があります。

実装しようとしているロジック。

N 個のロボットを管理する単一の環境クラスが必要なようです。それは完全に論理的です。一般的なアプローチの 1 つは、Environment を「シングルトン」にすることです。これは、単一のインスタンスのみを許可するインスタンス変数です。次に、静的変数/メソッドがないため、必要な数のロボットを割り当てて自由に参照できます。

もう 1 つの方法は、Environment クラス全体を静的にすることです。次に、ロボットの (静的) リストを保持します。しかし、最近のほとんどの人は、オプション 1 が進むべき道だと言うと思います。

于 2012-11-02T22:53:54.280 に答える
2

staticメンバーは、それらを使用してインスタンス化を必要としないメンバーであるため、インスタンス化が必要なため、メンバーはありませthisthis

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 のアクションが必要な場合は、require中にthisこの関数を呼び出す理由を考える必要があります。staticthis

メンバー変数は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

最初のエラーは、静的メンバー関数で非静的メンバーを使用できないことを示しています。

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は変数numOfRobotsとを使用します。これらは両方ともクラスrobotsの特定のインスタンスに存在します。非静的にする(なぜ静的にしたいのですか?)か、ロボットを静的メンバーにしEnvironmentます。displayEnvironment

displayあなたの場合、またはを作成する理由がわからない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 に答える