Неверный вызов нестатической функции-члена (C ++)? - PullRequest
5 голосов
/ 04 декабря 2009

Я разрабатываю игру, в которой пользователь управляет мячом, который перемещается между областями на экране. «Карта» для экрана определяется в файле 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 ]

10 голосов
/ 04 декабря 2009
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 голосов
/ 04 декабря 2009

GetMapEntry не static, поэтому вы не можете вызвать его без объекта типа ThreeDCubeGame.

Альтернативы:
-Сделать GetMapEntry статическим: static inline char GetMapEntry
Создайте экземпляр ThreeDCubeGame и выполните instance.GetMapEntry(

1 голос
/ 04 декабря 2009

ThreeDCubeGame - это класс, а не экземпляр, поэтому вы можете использовать его только для доступа к статическим членам (то есть функция-член с ключевым словом static) Вы должны создать экземпляр объекта этого класса, чтобы использовать нестатические члены

ThreeDCubeGame map;
...
map.GetMapEntry(iMapX, iMapY).
0 голосов
/ 10 октября 2016

Может быть полезно иметь класс, содержащий набор функций, без каких-либо элементов данных, если вы не хотите предоставлять вспомогательные функции.
В противном случае было бы более практично использовать пространство имен для сбора этих функций.
Пример:

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 голосов
/ 04 декабря 2009

Вам не хватает ключевого слова "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 одиночным, превратить его в пространство имен или использовать глобальные функции. Результат тот же с точки зрения звонящего.

На примечании стороны: Поскольку все они используют статическую и / или глобальную переменную, она по своей природе не является поточно-ориентированной.

Если вам требуется несколько игровых полей и / или вы хотите играть безопасно с многопоточностью и / или хотите сделать это абсолютно ООП, вам понадобится экземпляр 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 голосов
/ 04 декабря 2009

Ошибка указывает, что вы вызываете функцию GetMapEntry как статическую, тогда как вы объявили ее как функцию-член. Вам необходимо:

  • вызовите его через экземпляр ThreeDCubeGame: threedcubegameinstance.GetMapEntry(),
  • объявите функцию GetMapEntry как статическую (добавьте статическую перед встроенным и сделайте также статическую m_acMapData).
0 голосов
/ 04 декабря 2009

Вы пытаетесь вызвать метод класса. Это то, что вы намерены? Или вы хотите, чтобы GetMapEntry был методом экземпляра? Если это метод класса, он должен быть помечен как статический. Если это метод экземпляра, вам нужно вызвать его с экземпляром ThreeDCubeGame. Кроме того, GetMapEntry даже член класса?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...