联盟和阶级

时间:2017-12-20 21:06:52

标签: c++ oop unions

我有很多空闲时间(也有圣诞假期传入!)所以,我尝试合并我的两个激情,视频游戏和c ++。 它不是一个真正的视频游戏项目,只是一些使用类的控制台脚本。 所以,这就是问题所在;

#include <stdafx.h>
#include <iostream>

class m4a1 {
    public:
        int Damage = 12;
        int Mag = 30;
};

class ak47 {
    public: 
        int Damage = 14;
        int Mag = 24;
};

union Gun_Union {
    m4a1 M4A1_Union;
    ak47 Ak47_Union;
};

class Player {
    public:
        Gun_Union Gun_Player;
        int Health = 200;
};

template <typename Type> 
void Shot(Type* Player_Obj) {
    Player_Obj->Gun_Player->AK47_Union->Mag--;
    Player_Obj->Health = Player_Obj->Health - Player_Obj->Gun_Player->AK47_Union->Damage;
}   
int main() {

    Player Player_Obj;
    Player_Obj.Gun_Player;
    Shot <Player> (&Player_Obj);
    std::cout << Player_Obj.Health;
}

在第35行,它给了我错误 Player :: Player(void)试图引用一个消除函数。 我发现在类Player(第25行)中使用任何其他类型更改Gun_Union并不会给我一个错误。

我也问是否可以使用命令Player_Obj.Gun_Player = Ak47_Union; 抱歉英语不好。

2 个答案:

答案 0 :(得分:1)

要回答原始问题,您的union会有非平凡的成员(因为初始值设定项),但没有构造函数。您需要告诉编译器您最初希望拥有哪个union成员,因为编译器必须构造一个或另一个。这可以通过给union构造函数来完成。

然后您将.->运营商混合在一起。

这是一个编译的版本(我不敢称之为&#34;固定&#34;但是):

#include <iostream>

class m4a1 {
public:
  int Damage = 12;
  int Mag = 30;
};

class ak47 {
public:
  int Damage = 14;
  int Mag = 24;
};

union Gun_Union {
  m4a1 M4A1_Union;
  ak47 Ak47_Union;
  Gun_Union() : Ak47_Union() {}   // <=== the initial state is ak47
};

class Player {
public:
  union Gun_Union Gun_Player;
  int Health = 200;
};

template <typename Type>
void Shot(Type* Player_Obj) {
  Player_Obj->Gun_Player.Ak47_Union.Mag--;
  Player_Obj->Health = Player_Obj->Health - Player_Obj->Gun_Player.Ak47_Union.Damage;
}
int main() {

  Player Player_Obj;
  Player_Obj.Gun_Player;
  Shot <Player>(&Player_Obj);
  std::cout << Player_Obj.Health;
}

答案 1 :(得分:0)

  

我也问是否可以使用命令Player_Obj.Gun_Player = Ak47_Union;抱歉英语不好。

所以你在这里尝试做的是将玩家当前的武器设置为ak47。这是问题所在。你的联盟代表一个类,而不仅仅是一个常规类型。出于某些原因,这是一个问题。

一个类很有用,因为它提供了一个蓝图,可以从中创建相似但最终不同的对象。由于你所有的武器类都具有相同的结构(伤害和磁化),因此没有理由为每种武器分别设置类。

此外,这里的类很棘手,因为为了让你使用一个类,你必须首先实例化它或者声明它的成员函数是静态的。这里的问题来自于你使用联盟处理玩家武器的事实。联盟不起作用,因为根据定义持有事物(一次一个),这不是一件事,因为我们想要一个静态类。

现在,你可以实例化你的武器类并实际将它们添加到联合中,如下所示:

int main()
{
    Player Player_Obj;
    Player_Obj.Gun_Player;

    // Remember to pick better names for classes, not the metasynctactic
    // b.s. I'm using
    m4a1 m4a1_class_instance;
    ak47 ak47_class_instance;

    // Populate the union
    union Gun_Union weapons;
    weapons.Ak47_Union = ak47_class_instance;

    // Finally, set player weapon
    Player_Obj.Gun_player = weapons;

    // <Rest of program...>

我相信你可以说,这很笨重,并没有多大意义。我们为什么要这些课程?它没有多大意义。我认为在这里进行重新设计会很棒,特别是因为你不必处理工会问题,这会让你在设置玩家的武器方面绊倒。这是一个非常基本的。

// Using constants for simplicity

// Weapon Ids
const auto M4A1 = 1000;
const auto AK47 = 1001;

const auto FIRST_WEAPON_ID = M4A1;
const auto LAST_WEAPON_ID = AK47;

class Player {
    int weapon_id;
    int health;
    int damage;
    int magazine_capacity;
    int magazine;

public:
    void setWeapon(const int weapon_id) {
        // Validate id first; you should somehow handle error,
        // I'm just exiting the function here
        if ((weapon_id < FIRST_WEAPON_ID) || (weapon_id > LAST_WEAPON_ID)) return;

        switch (weapon_id) {
            case M4A1: {
                damage = 12;
                magazine_capacity = 30;
            } break;

            case AK47: {
                damage = 14;
                magazine_capacity = 24;
            } break;

            default: // Error should have been handled in validation, but
                     // it's best practice to guard your code everywhere
                return;
        }
    }
};

这显然不是完整的类,我只写了一个函数只是为了向你展示我将如何实现一个更天真的方法,但实际的实现细节取决于你,我真的会强调设计概念,特别是以下内容:


访问班级成员

您不希望直接访问类成员,尤其是在您谈论指针时。 “拥有指针指向的数据的人”的问题是一个重要问题,这就是我们现在拥有共享和唯一指针的原因。无论你使用哪个指针,都应该有<return-type> getValue() const之类的东西。这样,您的数据就会受到间接层的保护。同样,要设置一个值,您可以执行void setValue(const <type> value)之类的操作,现在您可以执行验证或该功能中的任何内容。


联盟

首先,我不建议使用工会。在您的特定情况下,使用联合并不是真的有意义,因为您已经在播放器类(在编辑问题之前)中有指针,这意味着玩家只能拥有一个。拥有一个联盟并不会在那时添加任何东西。此外,不推荐使用工会,主要是因为您失去了一些类型安全性。如果你确实想要类似联合的东西,你可能想在STL中查看std :: variant。


您的模板功能

一般来说,模板函数用于泛型编程,它们可以接受类型T,而您不必担心不必要地重写代码。在您的情况下,它不应该适用。

你提到你只是为练习做这件事,所以我明白干净的设计不是你的目标,但我认为开始考虑设计原则永远不会太早。