在类中创建对象的最佳实践

Posted

技术标签:

【中文标题】在类中创建对象的最佳实践【英文标题】:Best practise creating objects within class 【发布时间】:2015-10-26 15:48:28 【问题描述】:

我有一个通用类 Player,在该类中我声明了一个较小类的对象,例如 Weapon、Inventory 等。

当然,我使用指针 (shared_ptr) 来实例化我的 Player 对象,并使用相同的方法来实例化我的类中的任何对象。我应该继续这样做还是应该尝试通过不使用指针来使其更简单,这会带来一定的缺点吗?

class Player: public Human, public Control
    
    public:
        Player();
       ~Player();

    private:
        Weapon           myWeapon;
        std::vector<std::tr1::shared_ptr<Weapon> > WeaponsList;

    ;

对比

class Player: public Human, public Control
    
    public:
        Player();
       ~Player();

    private:
        Weapon           myWeapon;
        std::vector<Weapon> WeaponsList;

    ;

注意,我使用 shared_ptr 并希望保留一个选项,让 Weapon 在某个时候成为基类(但不要着急!)。

【问题讨论】:

Weapon 是多态类型吗? Err...class Player 的构造函数不会被称为Player(),而不是gPlayer()?为什么MountWeapon() 工作在ints 而myWeapon 类型为Weapon为什么public 是成员? 为什么rWeapon() 返回一个非const 对成员的引用?为什么使用指针是“自然”的?为什么Draw()Player 的成员? Ohmagawd... :-D 还没有,我尽量保持简单,但里面有一个“Ammo”对象。不过,我想保持该选项处于打开状态以使其在某些时候具有多态性。 @DevSolar:问题太多了。。不要在不知道里面有什么的情况下取出代码并坚持问题。我有 42k 行代码工作得很好,20k 个物体表现得很漂亮,碰撞和射击以及稳定的 120 fps 速率。 @DevSolar。没有冒犯。请注意,编写需要维护的代码(例如在工作室工作并被其他人阅读)与爱好编程之间存在差异。我在这个项目上工作了 5 年(偶尔),并且没有遇到任何麻烦,甚至休息了一年。在 42k 的代码中,引擎运行平稳,到目前为止我没有遇到任何错误。如果将来我计划扩展它时它开始崩溃,我会重新考虑并更多地考虑有缺陷的游戏设计。 【参考方案1】:

肯定是前者(即,是的,继续使用指针),只需确保定义了一个灵活的抽象类Weapon,其中包含播放器需要与之交互的所有方法/属性;您希望尽可能避免解析派生类型(这会使代码变得混乱且速度较慢)。

如果您不熟悉设计模式,我建议您阅读Factories 以及在这种情况下如何使用它们来处理分配。这将使您的代码易于维护/理解,如果有人想稍后在您的游戏中添加另一种武器。您将需要使用命名标签来阐明您的代码并选择要在您的工厂中构建的对象;这可以使用enums 来完成,但如果您不能使用强类型enums (c++11),我倾向于使用命名空间或结构,例如:

struct WeaponID

    static const int DESERT_EAGLE = 0;
    static const int SHOTGUN = 1;
 
// ... use in a switch/case e.g. WeaponID::SHOTGUN

您可以轻松查看如何在开关中使用此类标签并输出指向抽象类的共享指针(如果需要,您甚至可以定义别名标签)。

如果您怀疑您可能需要经常解析派生类型,那么考虑将前一个标记存储为抽象类的成员,这将比使用 dynamic_casts 更容易和更清晰。

如果您担心性能(我想您是 120 fps),请考虑使用 memory pools 的对象(武器、玩家等),尽管在游戏的上下文中,我预计数量游戏开始时对象(几乎)保持不变?

【讨论】:

是的,我保持数量不变并保留内存。在实际游戏开始之前初始化对象。我喜欢你对抽象类的想法。 Weapons 是一个灵活的类,它通过读取的外部文件添加。我使用枚举作为我的武器,但这里没有显示。 我避免动态转换。我创建了一个二级列表,其中包含指向我需要的对象(例如可控对象)的指针并使用它们。我对动态演员感到畏缩,这可能是不合理的,并且只有很少的电话作为例外.. 不知道,你怎么看? @user2856452 我认为dynamic_casts 本质上并不意味着经常使用。尽可能远离它们是件好事,正如我所说,如果您知道需要经常解析派生类,则很容易提前计划和存储 ID。 是的,这又回到了有远见的游戏设计的讨论。有一些事情我什至觉得它们是错误的(比如动态强制转换),但其他一些事情,比如我完全没问题的 sigleton,因为他们实际上简化了我的代码,因为我注意尽量减少它们的劣势。一般来说,我对游戏设计并不教条,只要它为我未来的目的而努力。 我刚读到你提议的工厂。我的游戏中有这个(或类似的)实现(不知道它被称为工厂)。基本上我从我的游戏编辑器创建的文件中读取,将其解析为枚举并传递给“工厂”函数以返回要添加到通用基类列表的正确对象。我没有遇到任何问题,据我所知,这似乎与应该采用的保理相似。【参考方案2】:

根据最初提供的信息,我认为唯一的答案是“视情况而定”。

如果你的WeaponsList 是一个指针向量,什么负责清除各种Weapon 对象? 如果WeaponsListWeapon的向量,则需要保证拷贝构造函数是完整的。 什么是Weapon?它是一个基类,您将从中派生SwordDaggerLance 等?或者武器的类型仅仅是物体的一个属性? 可以在没有Player 的情况下存在Weapon 对象吗?是否会有所有Player 对象指向的武器共享列表?

换句话说,我认为我们没有足够的细节来完全回答您的问题。

更新

使用评论中提供的其他信息:

如果你创建一个对象,它需要被清除(销毁);当您使用 shared_ptr 时,应该自动处理。

由于Weapon 可以在没有Player 的情况下存在并且将来可能成为基类,因此使用指针向量可能是要走的路。

【讨论】:

第 1 点:它是一个 shared_ptr。我必须清除它吗?第 2 点:(同第 1 点) 第 3 点:武器目前是独立存在的,它可能在以后的某个阶段变得多态。第4点:是的,可以 @user2856452;根据您的评论更新了我的答案。 谢谢,这是一个很好的答案!是的,我就是这么想的。这取决于我想让武器成为未来的基类。干杯..

以上是关于在类中创建对象的最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中创建同时支持 Unicode 和 ASCII 的库的最佳实践是啥?

在 Doctrine 中创建多对多关系的最佳实践。

在 JavaScript 中创建自定义 UI 框架的最佳实践 [关闭]

最佳实践?在活动之间传递参数

在 C# 中创建(按需)SQL Server 2008 Express 数据库的最佳实践?

标记 SQL Oracle 开发人员最佳实践