非静态成员函数的非法调用(C++)?

5

我正在开发一个基于用户控制屏幕上移动的球的游戏。屏幕的“地图”在文件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':非静态成员函数的非法调用"。这与变量的作用域有关吗?能否在不重新设计所有代码的情况下修复它?

7个回答

11
class A {
  int i;
public:
  A(): i(0) {}
  int get() const { return i; }
};

int main() {
  A a;
  a.get();  // works
  A::get(); // error C2352
}

没有对象来调用该函数。


5

GetMapEntry不是静态的,因此您无法在没有ThreeDCubeGame类型对象的情况下调用它。

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


感谢您的回答。在我的程序中,ThreeDCubePlayer是ThreeDCubeGame中的一个实例 - 这是否意味着我可以在ThreeDCubePlayer中创建一个ThreeDCubeGame的实例,该实例引用相同的二维数组? - benwad
你可以从内部使用 ThreeDCubePlayer.GetMapEntry( 或 this->GetMapEntry(。 - Arkaitz Jimenez

1

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

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

0

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

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<int> data);
然后可以使用成员函数:
Solver::solve_a(my_vector);

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

第三种方法是默认在使用时初始化:
Solver().solve_a(my_vector);


0
你漏掉了 "static" 关键字。
// .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制作为单例,将其变成命名空间或使用全局函数。 从调用者的角度来看,结果是相同的。

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

如果您需要多个游戏场地和/或希望通过多线程保持安全和/或绝对按照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 );
}

0

您正在尝试调用一个类方法。这是您想要的吗?还是您希望GetMapEntry成为实例方法?如果它是一个类方法,那么它需要被标记为静态的。如果它是一个实例方法,您需要使用ThreeDCubeGame的实例来调用它。此外,GetMapEntry是否是一个类的成员?


0
错误提示表明您正在调用GetMapEntry函数作为静态函数,而您将其声明为成员函数。您需要执行以下操作:
  • 通过ThreeDCubeGame的实例来调用它:threedcubegameinstance.GetMapEntry()
  • 将GetMapEntry函数声明为静态函数(在inline前添加static,并使m_acMapData也变成static)。

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