# 类型对象

“通过创建一个类来支持新类型地灵活创建，其每个实例都代表一个不同的对象类型。”

例如基类是怪物，设计师告诉我们怪物的种类繁多，如“龙”、“巨魔”。

```cpp
class Monster
{
public:
　virtual ~Monster() {}
　virtual const char* getAttack() = 0;

protected:
　Monster(int startingHealth)
　: health_(startingHealth) {}

private:
　int health_; // Current health.
};
```

两个子类，龙和巨魔

```cpp
class Dragon : public Monster
{
public:
　Dragon() : Monster(230) {}
　virtual const char* getAttack()
　{
　　return "The dragon breathes fire!";
　}
};

class Troll : public Monster
{
public:
　Troll() : Monster(48) {}

　virtual const char* getAttack()
　{
　　return "The troll clubs you!";
　}
};
```

这些是非常糟糕的，

1. 收到设计师的邮件，要把巨魔的攻击力从18修改为52
2. 查看并修改Troll.h
3. 重新编译游戏
4. 查看变化
5. 回复邮件
6. 重复上述步骤

很明显这是非常扯淡的。

目前是一种类型一个类。

所以能不能直接搞两个类就行了，两个类，无限的类型。

示例

```cpp
// 种族
class Breed
{
public:
　Breed(int health, const char* attack)
　: health_(health),
　　attack_(attack)
　{}

　int getHealth() { return health_; }
　const char* getAttack() { return attack_; }

private:
　int health_; // Starting health.


　const char* attack_;
};
```

它是一个包含两个数据字段的容器：初始生命值和攻击字符串，怪物如何使用它

```cpp
class Monster
{
　friend class Breed;

public:
　const char* getAttack() 
　{
　　return breed_.getAttack();
　}

private:
　Monster(Breed& breed)
　: health_(breed.getHealth()),
　　breed_(breed)
　{}

　int health_; // Current health.

　Breed& breed_;
};
```

当我们构造一个怪物时，给它一个种族对象的引用，

```cpp
class Breed
{
public:
    Monster* newMonster()
    {
        return new Monster(*this);
    }

    // Previous Breed code...
};
```

修改后，看起来像这样

```cpp
Monster* monster = someBreed.newMonster();
```

## 通过继承共享数据

种族都有一个基种族

```cpp
class Breed
{
public:
　Breed(Breed* parent, int health, 
　　　　const char* attack)
　: parent_(parent),
　　health_(health),
　　attack_(attack)
　{}

　int　　　　　 getHealth();
　const char* getAttack();

private:
　Breed*　　　 parent_;
　int　　　　　 health_; // Starting health.


　const char* attack_;
};
```

当我们构造一个种族时，先为它传入一个基种族，我们可以传入NULL来表示它没有祖先。

Breed getHealth和getAttack的实现

```cpp
int Breed::getHealth()
{
　// Override.

　if (health_ != 0 || parent_ == NULL) 
  {
　　return health_;
  }
　// Inherit.

　return parent_->getHealth();
}

const char* Breed::getAttack()
{
　// Override.

　if (attack_ != NULL || parent_ == NULL) 
　{
　　return attack_;
　}

　// Inherit.

　return parent_->getAttack();
}
```

这么写的好处是，即便在运行时修改了种类，去掉种类继承或去掉某个特性的继承，它仍能够正常运作。

还可以模仿继承

```cpp
Breed(Breed* parent, int health, const char* attack)
: health_(health),
　attack_(attack)
{
　// Inherit non-overridden attributes.

  // 继承 parent的属性
　if (parent != NULL)
　{
　　if (health == 0) health_ = parent->getHealth();

　　if (attack == NULL)
　　{
　　　attack_ = parent->getAttack();
　　}
　}
}
```

一旦构造结束，我们就可以忘掉基类，因为它的属性已经被拷贝了下来，要访问一个种族的特性，现在只需返回它自身的字段。

```cpp
int getHealth() { return health_; }
const char* getAttack() { return attack_; }
```

假设游戏引擎从JSON文件创建种族，数据示例如下

```json
{
　"Troll": {
　　"health": 25,
　　"attack": "The troll hits you!"
　},
　"Troll Archer": {
　　"parent": "Troll",
　　"health": 0,
　　"attack": "The troll archer fires an arrow!"
　},
　"Troll Wizard": {
　　"parent": "Troll",
　　"health": 0,
　　"attack": "The troll wizard casts a spell"
　}
}
```

其中巨魔的基种族是 Troll, Throll Archer 和 Troll Wizard 都是派生种族。

两个派生类的生命值是0，这个值可从父类继承。设计师可以在 Troll 类中调整这个值，三个种族都会一起更新。

## 评价

怎么说呢，这种东西真的好吗，说实话真的不一定。想想很美好，但实际用起来还真不一定好。

况且使用场景也有限。
