“通过创建一个类来支持新类型地灵活创建,其每个实例都代表一个不同的对象类型。”
例如基类是怪物,设计师告诉我们怪物的种类繁多,如“龙”、“巨魔”。
class Monster
{
public:
virtual ~Monster() {}
virtual const char* getAttack() = 0;
protected:
Monster(int startingHealth)
: health_(startingHealth) {}
private:
int health_; // Current health.
};两个子类,龙和巨魔
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!";
}
};这些是非常糟糕的,
很明显这是非常扯淡的。
目前是一种类型一个类。
所以能不能直接搞两个类就行了,两个类,无限的类型。
示例
// 种族
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_;
};它是一个包含两个数据字段的容器:初始生命值和攻击字符串,怪物如何使用它
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_;
};当我们构造一个怪物时,给它一个种族对象的引用,
class Breed
{
public:
Monster* newMonster()
{
return new Monster(*this);
}
// Previous Breed code...
};修改后,看起来像这样
Monster* monster = someBreed.newMonster();种族都有一个基种族
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的实现
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();
}这么写的好处是,即便在运行时修改了种类,去掉种类继承或去掉某个特性的继承,它仍能够正常运作。
还可以模仿继承
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();
}
}
}一旦构造结束,我们就可以忘掉基类,因为它的属性已经被拷贝了下来,要访问一个种族的特性,现在只需返回它自身的字段。
int getHealth() { return health_; }
const char* getAttack() { return attack_; }假设游戏引擎从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 类中调整这个值,三个种族都会一起更新。
怎么说呢,这种东西真的好吗,说实话真的不一定。想想很美好,但实际用起来还真不一定好。
况且使用场景也有限。