如何让类包含指向自身的指针列表
How to have a class contain a list of pointers to itself?
我正在用C++做一个游戏。在这个游戏中,有一个游戏对象指针列表。游戏对象是世界中可能与之交互的每个对象的基类。Main的工作是充当裁判,因此它会通知每个对象有关碰撞,渲染它们,删除它们等。
玩家的角色具有能力。某些技能可能会产生射弹。每个射弹都是不同的,但都来自游戏对象。必须将它们添加到列表中,以便主可以看到它们。我希望游戏对象指针列表是全局的,以便对象可以将自己推到列表中,但 main 仍可能看到并更新它们。就目前而言,如果列表是在main中创建的,则游戏将运行。
有 3 种可能的解决方案:我将此列表放在 Globals.h 中,将单例模式应用于游戏对象类,或者我将此列表放在 GameObject.h 中,但在游戏对象类之外。所有解决方案都会导致错误。
我相信解决方案 1 会导致循环依赖关系,因为 Globals.h 定义了游戏对象类所需的枚举值,但该列表由游戏对象指针组成。列表中的第一个错误显示"游戏对象是未声明的标识符",并在全局变量中弹出。
//Globals.h
#include "GameObject.h"
#include <list>
std::list<GameObject *> objects;
enum Id{ENEMY, PLAYER, ROCK};
//GameObject.h
#pragma once
#include "Globals.h"
class GameObject{
public:
GameObject();
~GameObject();
Id id;
};
对于解决方案 2,如果我在 GameObject 类中有列表,我就可以编译,但是一旦我尝试将自己推到列表中,链接器就会抛出错误。它说"未解析的外部符号"。如果对象本身是指针,则也不会更改。
//GameObject.h
#pragma once
#include "Globals.h"
#include <list>
class GameObject{
public:
static std::list <GameObject *> objects;
GameObject();
~GameObject();
void init(){ objects.push_back(this); }
Id id;
};
对于最终解决方案,链接器告诉我 main.obj 已经定义了列表对象符号。找到一个或多个乘法符号。
//GameObject.h
#pragma once
#include "Globals.h"
#include <list>
class GameObject{
public:
GameObject();
~GameObject();
Id id;
};
std::list <GameObject *> objects;
我已经完全没有想法了,我真的需要这个列表可以访问。解决方案 1 最可取,其次是 2,然后是 3。如何使此列表可全局访问?可能吗?有没有比我尝试过的 3 种方法更好的方法?
更新:如果我使用前向声明和 extern 关键字,解决方案1 将编译,但是当我尝试时
GameObject *test = new GameObject
objects.push_back(test);
总的来说,我得到了一个未解决的外部。
1 和 2 是合理的想法,只是理解上的一些小差距:
1 - 在全局变量中声明
循环依赖关系是这样通过前向声明解决的。在访问其成员或需要知道它有多大(通常实例化对象)之前,您不需要完整的类定义。
您将遇到的下一个问题是,这会导致在包含 Globals.h 的每个源文件中创建一个单独的objects
列表。您可以通过在声明中使用 extern
关键字(告诉编译器暂时不要为其分配空间)并在 1 个 cpp 文件中定义它而不带extern
(内存在那里分配)来避免这种情况。但是,这更像是一种 C 风格的做法:在现代C++使用静态类成员是更标准的做法(如 2)。
//Globals.h
#include "GameObject.h"
#include <list>
class GameObject; // Forward declaration
extern std::list<GameObject *> objects; // Declare, don't define
enum Id{ENEMY, PLAYER, ROCK};
//GameObject.h
#pragma once
#include "Globals.h"
class GameObject{
public:
GameObject();
~GameObject();
Id id;
};
//GameObject.cpp
#include "GameObject.h"
std::list<GameObject *> objects; // The list lives here.
2 - 静态类成员
与 extern
关键字非常相似,当您声明静态类成员时,它实际上并没有在程序中为链接器分配空间以供查找,因此它会引发未解析的符号错误。您需要在正好 1 cpp 中定义存储空间。
此外,通常的做法是使全局可访问的成员,例如private
,但创建一个public
访问器函数。这是一个很容易养成的习惯,有时会为您省去一些麻烦。
//GameObject.h
#pragma once
#include "Globals.h"
#include <list>
class GameObject{
public:
GameObject();
~GameObject();
void init(){ objects.push_back(this); }
Id id;
// Accessor function
static std::list <GameObject *> & GetAllObjects() { return objects; }
private:
static std::list <GameObject *> objects; // Declaration only
};
//GameObject.cpp
#include "GameObject.h"
std::list <GameObject *> GameObject::objects; // Definition
3 - 多个副本
别这样。
每个包含 GameObject.h 的文件最终都将使用单独的 objects
副本。
在要使用类名创建对类的指针或引用之前,先向前声明该类。 您不需要完整的类定义。 您还应该只在头文件中声明全局变量,而不是定义它们。 如果定义它们并将标头包含在多个源文件中,则最终会出现多个定义链接器错误。 当然,您确实需要在某个源文件中定义变量(一次)。
//Globals.h
#include <list>
class GameObject; // forward declaration of GameObject
extern std::list<GameObject *> objects; // declaration of objects
enum Id{ENEMY, PLAYER, ROCK};
//Globals.cpp
#include "Globals.h"
std::list<GameObject *> objects; // definition of objects
您可以通过修改第一种情况来做到这一点:在创建GameObject
指针的list
之前声明类原型。
//Globals.h
class GameObject; //Defined the class prototype first before including
//"GameObject.h"
#include "GameObject.h"
#include <list>
std::list<GameObject *> objects;
enum Id{ENEMY, PLAYER, ROCK};
//GameObject.h
#pragma once
#include "Globals.h"
class GameObject{ //Class body
public:
GameObject() {}
~GameObject() {}
Id id;
};
我已经定义了GameObject::GameObject
,因为当编译器遇到行class GameObject;
时,它会自动生成默认构造函数,这与我们之前提供给类的定义冲突。
因此,我们可以删除GameObject
构造函数,或者提供默认构造函数的实现,这已经在代码中完成。
- 为什么这个 std::queue/指向结构的指针列表直到 List.Size() == 0 才释放内存?
- 什么更好?返回对象指针列表?或返回指向对象列表的指针?
- 如何将共享指针列表传递到pybind11中的c++对象
- C++:如何初始化包含具有给定键的指针列表的映射
- 使用继承的指针列表复制构造函数或重载运算符=
- 我应该如何在工厂类中存储弱指针列表?
- Qt单元测试:指针列表上的QCOMPARE函数
- 如何正确释放要配对的指针列表?
- 如何在 c++ 上对指针列表进行排序
- 从地图复制到指针列表
- 我对C 中共享指针列表进行排序的功能未完成类型
- const_iterator引用的指针列表
- 在 c++ 中生成字符串到 std::指针列表的映射
- 访问链表中的结构(带有指向其子实现的指针列表的树)
- 有没有办法使用基于范围的迭代器来迭代对指针列表值的引用?
- 使用迭代器指针 (C++) 从对象指针列表中删除元素
- 无法列出定制类型的指针列表
- 创建指针列表的正确范例是什么
- 如何将指向指针列表的私有指针作为 const 返回
- C++填充指向指针**列表的指针,该列表指向指针地址