我有一组课程:
// This is #included from another header file
// I don't want to inherit this, because it ain't my code
class DrawableObject;
class Animal {
DrawableObject obj;
// Does not define run() or swim()
};
class Cat : public Animal {
void run() { /* Calls obj.setPosition() and other stuff */ }
};
class Dog : public Animal {
void run() { /* Calls obj.setPosition() and other stuff */ }
void swim() { /* Calls obj.setPosition() and other stuff */ }
};
class Dolphin : public Animal {
void swim() { /* Calls obj.setPosition() and other stuff */ }
};
在这里,Dog::run()
和Cat::run()
恰好使用完全相同的代码,而Dog::swim()
和Dolphin::swim()
也使用相同的代码。我不想在各处复制粘贴代码,而是要重用它。明智的解决方案似乎是在基类(Animal
)和具体类(Cat/Dog/Dolphin
)之间添加中间子类:
/-> RunnableAnimal --> Cat
| \
Animal-| |-> Dog
| /
\-> SwimmableAnimal -> Dolphin
问题是:我违背“继承构成”规则吗?如果是这样,这是否完美,还是在实现代码重用时遵守CoI的方法?
注意:我不需要,当我使用run()
时,我总是使用具体的(Cat/Dog/Sloth
)类来调用它,而不是Animal
基类的成员。
答案 0 :(得分:4)
更好的继承模式:
/–––––––––– Cat
/ /
/ Runner
/ \
Animal –––––––––––––– Dog
\ /
\ Swimmer
\ \
\–––––––––– Dolphin
您避免在方法中引入菱形图案。
代替继承,您可以在需要的动物内聚合一个Runner
/ Swimmer
实例,并使动物的功能仅委派给成员。
关于您的模型的一个小问题:它并不能真正反映现实,实际上,尽管不喜欢水,但是猫还是很好的游泳者...
编辑:由于Runner
和Swimmer
需要访问Animal
的成员:您可以通过curiously recurring template pattern提供此权限;在下面添加了一个演示:
class Animal
{
protected:
int n = 7;
};
template <typename T>
class Swimmer
{
public:
void swim()
{
std::cout << static_cast<T*>(this)->n << std::endl;
}
};
class Dolphin : public Animal, public Swimmer<Dolphin>
{
friend class Swimmer; // n is protected!
// (alternatively, Swimmer might already be a friend of Animal)
};
int main(int argc, char* argv[])
{
Dolphin d;
d.swim();
return 0;
}