【问题标题】:Polymorphism problem: How to check type of derived class?多态问题:如何检查派生类的类型?
【发布时间】:2011-02-01 14:11:44
【问题描述】:

这是我的第一个问题:)

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

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

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

你可能不明白这个混乱,所以我尝试用代码来解释它:

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();
};

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

因此,当我向实现 IExtendable 和一些 IUpdatable、ILoadable 的扩展添加一些扩展时...我不得不检查将要添加的扩展是否也实现这些接口。所以在 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...谢谢

【问题讨论】:

    标签: interface polymorphism types virtual dynamic-cast


    【解决方案1】:

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

    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;
    };
    

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

    【讨论】:

      【解决方案2】:

      只是一种直觉,但根据您的扩​​展程序正在做什么,visitor-pattern 可能会对您有所帮助。您可能还想了解decorator 模式。

      【讨论】:

      • 谢谢,但由于我不是经验丰富的程序员,这些模式对我来说似乎相当复杂
      • 如果你不是一个有经验的程序员,并且你正在尝试做上面的事情,你会搞砸设计,以后会后悔的。
      • 我猜你是对的,我将使用我稍后发布的代码......我会将这些接口合并到一个类中。
      【解决方案3】:

      您应该重新考虑您的设计。如果你需要这种行为,或许可以引入IUpdateExtendableIDrawExtendable

      当前方法不好的原因是它违反了Liskov Substitution Principle。你基本上是在说“这个对象作为一个 IExtendable,但它真的没有,除非......”如果一个类实现了一个接口,它真的应该可以通过该接口使用而没有 any状况。如果不是,那将是一场等待发生的维护噩梦。

      【讨论】:

      • 谢谢,但我真的不明白 IUpdateExtendable 将如何解决我的问题
      • @malymato:如果您为每个“操作”创建了一个单独的接口,您的工作可以只检查该特定接口 - 而不是尝试使用单个 IExtendable 接口。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-05-20
      • 2016-07-03
      • 1970-01-01
      • 1970-01-01
      • 2019-08-27
      • 1970-01-01
      • 2013-02-04
      相关资源
      最近更新 更多