试图使用C++中的多态性来使我的头脑清醒。下面是两个基本的抽象类,Duck和FlyingBehavior,以及一系列继承的类(这是基于Head first Design Patterns的第一章)。
// Define an abstract fly behaviour class
class FlyBehavior {
public:
virtual void fly() { cout << "No Flying Set!" << endl; }
};
class FlySwoop : public FlyBehavior {
public:
void fly() { cout << "Swoop Flying!" << endl; }
};
class CantFly : public FlyBehavior {
public:
void fly() { cout << "Can't Fly!" << endl; }
};
// Define an abstract Duck class
class Duck {
CantFly nf;
FlyBehavior *flyBehavior;
public:
Duck() { flyBehavior = &nf; }
void goFly() { flyBehavior->fly(); }
void setFlyBehavior(FlyBehavior *fb) { flyBehavior = fb; }
};
// Define a new Mallard Duck class
class MallardDuck : public Duck {
FlySwoop fb;
public:
MallardDuck(){ setFlyBehavior(&fb); }
};
// Define a new Rubber Duck class
class RubberDuck : public Duck {
CantFly fb;
public:
RubberDuck(){ setFlyBehavior(&fb); }
};
// Define a new Toilet Duck Class
class ToiletDuck : public Duck {};
int main(void) {
Duck *p;
MallardDuck mallardDuck;
RubberDuck rubberDuck;
ToiletDuck toiletDuck;
p = &mallardDuck;
p->goFly();
p = &rubberDuck;
p->goFly();
p = &toiletDuck;
p->goFly();
}使用上面的代码,我得到以下输出
Swoop Flying!
Can't Fly!
Can't Fly!当我期待
Swoop Flying!
Can't Fly!
No Flying Set!我是否以正确的方式处理此示例(习惯于使用Java)?不禁觉得我错过了一些最基本的东西。我试图了解如何从类中提取行为,将其放入另一个类,然后使用多态性将其委托给正确的行为。是否有更好的方法来处理上述问题?
嗯,也许这是你使用多重继承的地方吗?
发布于 2014-10-29 19:58:49
如果你改变了
class Duck {
CantFly nf;
FlyBehavior *flyBehavior;
public:
Duck() { flyBehavior = &nf; }
void goFly() { flyBehavior->fly(); }
void setFlyBehavior(FlyBehavior *fb) { flyBehavior = fb; }
};至
class Duck {
FlyBehavior nf;
FlyBehavior *flyBehavior;
public:
Duck() { flyBehavior = &nf; }
void goFly() { flyBehavior->fly(); }
void setFlyBehavior(FlyBehavior *fb) { flyBehavior = fb; }
};您的代码将产生所需的输出。
在当前版本的代码中,ToiletDuck编译器生成的默认构造函数调用Duck类的默认构造函数,该构造函数将nf设置为指向CantFly类的实例。当然,它会打印Can't fly。
发布于 2014-10-29 22:19:10
首先,您的代码没有抽象的基类类。抽象基类是具有纯virtual成员函数(如virtual fly() const=0)的基类。FlyBehavior是一个多态类,但不是抽象类,因为它的虚拟函数不是纯虚拟的。Duck甚至不是多态类(没有虚拟成员方法)。
其次,任何多态类都应该有一个virtual析构函数,这样派生类型的任何对象都可以从指向多态基的指针中删除。
接下来,派生鸭子拥有比实际使用的更多的数据成员。例如,MallardDuck有一个CantFly、一个FlySwoop和一个FlyBehaviour*。可以通过在堆上分配实际的FlyBehaviour并通过智能指针管理它来避免这种情况。(这可能不是这个简单示例的问题,但一旦这些对象变大,就会成为一个问题。)
最后,成员函数setFlyBehavior()向公众公开,允许用户更改FlyBehavior --您真的想要这样吗?
可能的设计如下
struct FlyBehavior // polymorphic class
{
virtual void fly() const { cout << "No Flying Set!" << endl; }
virtual~FlyBehavior() {}
};
struct FlySwoop : FlyBehavior
{
void fly() const { cout << "Swoop Flying!" << endl; }
};
struct CantFly : FlyBehavior
{
void fly() const { cout << "Can't Fly!" << endl; }
};
class Duck // non-polymorphic, but using polymorphism through member
{
std::unique_ptr<FlyBehavior> flyBehavior; // calls FlyBehavior::~FlyBehavior at destruction
protected:
explicit Duck(FlyBehavior*f) : flyBehavior(f) { assert(f); }
public:
Duck() : flyBehavior(new FlyBehavior) {} // note: not CantFly as in your code
Duck(Duck&&) = default; // allow move (but no copy)
Duck&operator=(Duck&&) = default;
void goFly() const { flyBehavior->fly(); }
};
struct MallardDuck : Duck
{
MallardDuck() : Duck(new FlySwoop) {}
};
struct RubberDuck : Duck
{
RubberDuck() : Duck(new CantFly) {}
};通常情况下,FlyBehavior更倾向于抽象。在这种情况下,Duck只能用一个protected构造函数来实现(除了move & copy):
struct FlyBehavior // polymorphic class
{
virtual void fly() const=0 ; // pure virtual
virtual~FlyBehavior() {}
};
class Duck // non-polymorphic, but using polymorphism through member
{
std::unique_ptr<FlyBehavior> flyBehavior; // calls FlyBehavior::~FlyBehavior at destruction
protected:
explicit Duck(FlyBehavior*f) : flyBehavior(f) { assert(f); }
public:
Duck() = delete; // no default constructor
Duck(Duck&&) = default; // allow move (but no copy)
Duck&operator=(Duck&&) = default;
void goFly() const { flyBehavior->fly(); }
};以及上面所示的其余代码。区别在于您不能创建一个Duck对象,但是只能创建一个派生的Duck类型。这两种设计中哪一种最适合,取决于应用。
https://stackoverflow.com/questions/26639244
复制相似问题