多态性问题:如何检查派生类的类型?

时间:2010-03-27 18:23:37

标签: interface polymorphism types virtual dynamic-cast

这是我的第一个问题:)

我知道我不应该检查对象类型,而是使用dynamic_cast,但这不会解决我的问题。

我有一个名为Extension和接口的类,名为IExtendable和IInitializable,IUpdatable,ILoadable,IDrawable(后四个基本相同)。如果Extension实现IExtendable接口,它可以使用不同的Extension对象扩展自身。

问题是我想允许实现IExtendable的Extension只能使用与原始Extension实现相同接口的Extension进行扩展。

你可能不会那么糟糕,所以我试着用代码来解释它:

class IExtendable
{
public:
 IExtendable(void);

 void AddExtension(Extension*);
 void RemoveExtensionByID(unsigned int);

 vector<Extension*>* GetExtensionPtr(){return &extensions;};
private:
 vector<Extension*> extensions;
};

class IUpdatable
{
public:
 IUpdatable(void);
 ~IUpdatable(void);

 virtual void Update();
};

class Extension
{
public:
 Extension(void);
 virtual ~Extension(void);

 void Enable(){enabled=true;};
 void Disable(){enabled=false;};

 unsigned int GetIndex(){return ID;};

private:
 bool enabled;
 unsigned int ID;

 static unsigned int _indexID;
};

现在想象我创建扩展的情况:

class MyExtension : public Extension, public IExtendable, public IUpdatable, public IDrawable
{
public:
    MyExtension(void);
    virtual ~MyExtension(void);

    virtual void AddExtension(Extension*);
    virtual void Update();
    virtual void Draw();
};

我想允许这个类仅使用实现相同接口(或更少)的Extensions来扩展自身。例如,我希望它能够采用实现IUpdatable的Extension;或者IUpdatable和IDrawable;但是例如不是实现ILoadable的扩展。 我想这样做是因为例如Update()将在一些实现IExtendable和IUpdateable的Extension上调用,它也将在扩展此扩展的这些Extensions上调用。

所以,当我添加一些Extension实现IExtendable的扩展和一些IUpdatable,ILoadable ......我不得不检查是否要添加的Extension也实现了这些接口。所以在IExtendable :: AddExtension(Extension *)中,我需要做这样的事情:

void IExtendable::AddExtension(Extension* pEx)
{
bool ok = true;
// check wheather this extension can take pEx
// do this with every interface
if ((*pEx is IUpdatable) && (*this is_not IUpdatable))
ok = false;

if (ok) this->extensions.push_back(pEx);

}
但是怎么样?什么是最好的解决方案?我不想使用dynamic_cast并查看它是否返回null ...谢谢

3 个答案:

答案 0 :(得分:6)

你应该重新考虑你的设计。如果您需要此行为,可能会引入IUpdateExtendableIDrawExtendable

当前方法不好的原因是它违反了Liskov Substitution Principle。你基本上是说“这个对象充当了IExtendable,但实际上并没有,除非....”如果一个类实现了一个接口,那么它真的应该可以通过该接口使用而不需要任何条件。如果不是,那就是等待发生的维护噩梦。

答案 1 :(得分:0)

只是一种直觉,但根据您的扩​​展程序的作用,visitor-pattern可能会对您有所帮助。您可能还想阅读decorator模式。

答案 2 :(得分:0)

我可以将所有这些接口合并到一个类中,所以我会得到这样的东西:

class Extension
{
public:
Extension(void);
virtual ~Extension(void);

void AddExtension(Extension* pEx){extensions.push_back(pEx);};

virtual void Initialize()
{
for each (Extension* pEx in extensions) pEx->Initialize();
};

virtual void Load()
{
for each (Extension* pEx in extensions) pEx->Load();
};

virtual void Update()
{
for each (Extension* pEx in extensions) pEx->Update();
};

virtual void Draw()
{
for each (Extension* pEx in extensions) pEx->Draw();
};

private:
vector<Extension*> extensions;
};

但这意味着将在每个添加的扩展上调用所有方法。例如。一些添加的扩展中的空方法不会加载任何内容而不会绘制任何内容。