【问题标题】:Illegal call to non-static member function (C++)?非法调用非静态成员函数(C++)?
【发布时间】:2009-12-04 13:45:13
【问题描述】:

我正在开发一款游戏,该游戏基于用户控制在屏幕区域之间移动的球。屏幕的“地图”在文件 ThreeDCubeGame.cpp 中定义:

char m_acMapData[MAP_WIDTH][MAP_HEIGHT];

ThreeDCubeGame.cpp 处理与地图有关的大部分内容,但玩家(和键盘输入)由 ThreeDCubePlayer.cpp 控制。当玩家移动到新的地图单元格时,游戏必须检查该单元格的内容并采取相应的行动。 ThreeDCubeGame.cpp 中的这个函数是我想要使用的:

inline char GetMapEntry( int iMapX, int iMapY ) { return m_acMapData[iMapX][iMapY]; }

所以,为了检查是否允许玩家移动到地图单元格中,我使用了 ThreeDCubePlayer.cpp 中的这个函数调用:

if (ThreeDCubeGame::GetMapEntry(m_iMapX+MAP_OFF_X, m_iMapY+MAP_OFF_Y) == ' ')
{
// do stuff
}

但是,当我编译它时,我收到警告“错误 C2352:'ThreeDCubeGame::GetMapEntry':非法调用非静态成员函数”。这与变量的范围有关吗?不重新设计所有代码就可以修复吗?

【问题讨论】:

    标签: c++ scope


    【解决方案1】:
    class A {
      int i;
    public:
      A(): i(0) {}
      int get() const { return i; }
    };
    
    int main() {
      A a;
      a.get();  // works
      A::get(); // error C2352
    }
    

    没有可以用来调用函数的对象。

    【讨论】:

      【解决方案2】:

      GetMapEntry 不是 static,因此如果没有 ThreeDCubeGame 类型的对象,您将无法调用它。

      替代方案:
      - 将 GetMapEntry 设为静态:static inline char GetMapEntry
      - 创建 ThreeDCubeGame 的实例并执行instance.GetMapEntry(

      【讨论】:

      • 感谢您的回答。在我的程序中,ThreeDCubePlayer 是 ThreeDCubeGame 中的一个实例 - 这是否意味着我可以在 ThreeDCubePlayer 中创建引用相同二维数组的 ThreeDCubeGame 实例?
      • 你可以使用 ThreeDCubePlayer.GetMapEntry( 或者 this->GetMapEntry( 从里面。
      【解决方案3】:

      ThreeDCubeGame是类,不是实例,所以只能用来访问静态成员(即带有关键字static的成员函数) 您必须实例化此类的对象才能使用非静态成员

      ThreeDCubeGame map;
      ...
      map.GetMapEntry(iMapX, iMapY).
      

      【讨论】:

        【解决方案4】:

        您正在尝试调用类方法。那是你的意图吗?或者你的意思是GetMapEntry 是一个实例方法?如果是类方法,则需要标记为静态。如果是实例方法,需要用ThreeDCubeGame的实例来调用。另外,GetMapEntry 甚至是一个班级的成员吗?

        【讨论】:

          【解决方案5】:

          该错误表明您将 GetMapEntry 函数作为静态函数调用,而您已将其声明为成员函数。您需要:

          • 通过 ThreeDCubeGame 的实例调用它:threedcubegameinstance.GetMapEntry()
          • 将 GetMapEntry 函数声明为静态(在 inline 之前添加一个静态并使 m_acMapData 也为静态)。

          【讨论】:

            【解决方案6】:

            您缺少“静态”关键字。

            // .h
            class Playfield
            {
            public: 
              static char GetTile( int x, int y ); 
              // static on a method means no 'this' is involved
            };
            
            // .cpp
            static char tiles[10][10] = {}; 
            // static on vars in .cpp prevents access from outside this .cpp
            
            char Playfield::GetTile( int x, int y )
            {
              // handle invalid args
            
              // return tile
              return tiles[x][y];
            }
            

            如果您只想要一个独特的运动场,还有其他选择: 您可以将 Playfield 设为单例,将其转换为命名空间或使用全局函数。 从调用者的角度来看,结果是相同的。

            附带说明: 由于所有这些都使用静态和/或全局变量,因此它本质上不是线程安全的。

            如果您需要多个 playfield 和/或想要安全地使用多线程和/或希望绝对以 OOP 方式执行此操作,您将需要一个 Playfield 实例来调用函数(“this”指针):

            class Playfield
            {
            public:
               char GetTile( int x, int y ) const { return this->tiles[x][y]; } 
               // you can omit 'this->', but it's inherently present because
               // the method is not marked as static 
            public:
               Playfield() 
               { /*you will have to initialize 'this->tiles' here because 
                   you cannot use the struct initializer '= {}' on member vars*/ }
            
            private:
               char tiles[10][10];
            };
            

            调用代码会像这样使用 Playfield:

            void main()
            {
              // static version 
              char tile11 = Playfield::GetTile( 1, 1 );
            
              // non-static version
              Playfield myPlayfield;
              char tile12 = myPlayfield.GetTile( 1, 2 );
            }
            

            【讨论】:

              【解决方案7】:

              如果您不想公开辅助函数,则拥有一个包含函数集合但没有任何数据成员的类会很有用。
              否则,使用命名空间来收集这些函数会更实用。
              示例:

              class Solvers
              {
              public:
                void solve_a(std::vector<int> data);
                void solve_b(std::vector<int> data, int value);
              private:
                int helper_a(int a, int b);
              }
              

              但是类需要在使用前进行初始化。
              使这些函数可用的最简单方法是在类中将它们标记为静态:
              static void solve_a(std::vector&lt;int&gt; data);
              那么成员函数可以用作:
              Solver::solve_a(my_vector);

              另一种方法是在使用之前初始化类:
              Solver solver;
              solver.solve_a(my_vector);

              第三种方法,之前没有提到,默认是在使用的时候初始化:
              Solver().solve_a(my_vector);

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2014-04-14
                • 1970-01-01
                • 1970-01-01
                • 2021-12-03
                • 1970-01-01
                相关资源
                最近更新 更多