【问题标题】:Pointer of class to void*指向 void* 的类指针
【发布时间】:2016-05-17 14:01:27
【问题描述】:

我正在开发一款带班级的 rpg 游戏 我用 ActionList* 创建了一个结构调用 Character 来存储实例。 GeneralPlayer 是一个类,仍然有许多其他玩家类继承了它。 这是我的头文件:

class Battle
{
public:
       struct Character
      {
        char type;//monster or player?
        bool alive;
        void*instance;//pointer to instance
      };
      Battle(GeneralPlayer*,AbstractMonster*,int,int,int);     
      Battle(GeneralPlayer*, AbstractMonster*, int, int);
private:
       Character *ActionList;
};

我试图将 GeneralPlayer* 转换为 void*。但是似乎代码不像我想的那样工作。 P 和 M 是这些玩家类的指针数组。

 Battle::Battle(GeneralPlayer*P, AbstractMonster*M, int a, int b, int c)
{
   a = numP;
   b = numM;
   c = turn_limit;
   ActionList = new Character[numP + numM];
   P = new GeneralPlayer[numP];
   for (int i = 0; i < numP; i++)
   { 
      ActionList[i] = static_cast<void*>(P[i]);
      ActionList[i].type = 'p';
   }
  for (int i = numP; i < numP+numM; i++)
  {
      ActionList[i] = static_cast<void*>(M[i]);
      ActionList[i].type = 'm';
  }
}

它一直显示错误 C2440。我希望可以与任何人一起解决我的问题,谢谢。

【问题讨论】:

  • P[i] 不是GeneralPlayer*,而是GeneralPlayer
  • 你的意思是在你调用函数之后,你作为P传递的变量似乎没有被初始化?请尝试详细说明,也请尝试创建Minimal, Complete, and Verifiable Example 向我们展示。
  • @songyuanyao 对不起,我还是初学者。如果 P[i] 不是 GeneralPlayer*,那么我应该使用什么?
  • 如果我上面的评论不是问题(还),如果你有例如构建错误,然后请编辑问题以包含完整且未经编辑的构建日志。如果您还没有这样做,请read about how to ask good questions
  • 从不需要static_cast来将指向任何东西的指针转换为void*。这种转换是自动发生的。

标签: c++ class pointers void-pointers


【解决方案1】:

您正在尝试将对象转换为指针,请使用 & 运算符获取相关指针。

ActionList[i] = (void*)&P[i];
ActionList[i] = (void*)&M[i];

【讨论】:

  • 您不需要显式(甚至是 c 风格)演员表。任何数据指针类型都可以隐式转换为void*
  • 另外,Character *ActionList 应该是数据类型 Character **, Character ** ActionList = new Character*[numP + numM];
  • 这是真的,但没有回答问题(ActionList[i ].instance = (void*)&amp;P[i]; 会)或解决 OP 的问题。另外,你为什么要放弃编译器可以为你做的所有类型检查?
【解决方案2】:

这里的一个问题是Character 结构不是GenericPlayerAbstractMonster 的父级。似乎Character::instance 成员应该指向玩家或怪物,这意味着您的代码应该类似于

ActionList[i].type = 'p';
ActionList[i].alive = true;
ActionList[i].instance = &P[i];

这是假设玩家列表已经被Battle构造函数的调用者初始化,那么你不应该分配一个新的玩家数组,所以P = new GenericPlayer[numP];语句应该被删除。

应该注意的是,拥有像你这样的东西,一个“通用指针”(void * 是什么),然后一个成员说出它真正指向的类型被认为是糟糕的设计。相反,您将为怪物和玩家拥有一个公共基类,并使用指向它的指针。然后正确使用 polymorphismvirtual 成员函数,您就不需要 type 字段。然后很容易重构代码以使用其他方法来判断玩家或怪物是否还活着,然后您根本不需要 Battle::Character 类,并且可以使用指向公共的指针数组而是基类,从而稍微简化了代码,对可维护性非常有利。


您展示的代码还有一些其他问题,这些问题会在稍后的运行时引起问题。

一个问题是,在遍历怪物的循环中,您将 o 初始化为 numP 并循环到 numP + numM,但如果数组 M 不包含 numP + numM 元素,您将去越界了。

我建议你这样做,例如

for (int i = 0; i < numM; i++)
{ 
    ActionList[i + numP].type = 'm';
    ActionList[i + numP].alive = true;
    ActionList[i + numP].instance = &M[i];
}

【讨论】:

  • @ShiYiLee 假设你有一个函数void f(int a) { a += 5; }。现在当你调用函数时,比如f(some_int_variable),你会期望some_int_variable 改变吗?这与Battle 构造函数中的指针变量P 相同,在函数P 内部是一个 local 变量,对P 的所有修改都只会在功能。当你分配给P (P = new ...) 时,它只是在函数内部,你在调用中使用的变量不会被修改。
  • @ShiYiLee 我之前评论中讨论的问题是通过引用传递P来解决的,更改很简单:Battle(GenericPlayer*&amp; P, ...)。添加与符号 (&amp;) 使 P 成为指向 GenericPlayer 的指针的 reference
  • 但现在我遇到了另一个问题“如果我按照您的步骤操作,则无法将类型为“GeneralPlayer*”的值分配给类型为“Battle::Character*”的实体
  • @ShiYiLee 哦,我现在看到CharacterBattle 类的本地类型,我假设GenericPlayerAbstractMonster 继承自它是错误的。相反,您应该将instance 成员设置为指向玩家/怪物。我会更新我的答案。
猜你喜欢
  • 2016-03-21
  • 2013-07-19
  • 2021-07-22
  • 2014-05-30
  • 1970-01-01
  • 2017-10-16
  • 2012-03-15
  • 2010-09-29
  • 2014-10-01
相关资源
最近更新 更多