C++ 多态性的一种更干净的代码替代方案

C++ 多态性的一种更干净的代码替代方案,c++,inheritance,polymorphism,C++,Inheritance,Polymorphism,构建一个GUI系统,我为不同的GUI组件提供了几个类,这些组件派生自一个基本的“GUIcontrol”类。我想要的是只有一个函数来返回任何类型的组件,但能够使用特定于该组件类型的函数(派生类的函数)。我注意到多态性方法将成为一个问题,我必须在基类中声明所有派生函数,这是不必要的,因为我永远不会仅仅从基类创建对象 class GUIcontrol { protected: std::string _name; // these two methods (along with n

构建一个GUI系统,我为不同的GUI组件提供了几个类,这些组件派生自一个基本的“GUIcontrol”类。我想要的是只有一个函数来返回任何类型的组件,但能够使用特定于该组件类型的函数(派生类的函数)。我注意到多态性方法将成为一个问题,我必须在基类中声明所有派生函数,这是不必要的,因为我永远不会仅仅从基类创建对象

class GUIcontrol {
  protected:
    std::string _name;
    // these two methods (along with name()) will be used by all types
    virtual void position(/*parameters*/)
    virtual void useImage(/*parameters*/)

    // these should be only in derived types
    virtual void setHotSpot(/*parameters*/);
    virtual void setScrollButtons(/*parameters*/);
  public:
    std::string name();
  /*etc*/
}

class GUIbutton : public GUIcontrol {
  public:
    void setHotSpot(/*parameters*/);
}

class GUIscrollBar : public GUIcontrol {
  public:
    void setScrollButtons(/*parameters*/);
}

GUIcontrol* GUIsystem::getControl(std::string name);
问题是,如果我想添加更多GUIbutton或GUIscrollBar特有的函数,或者向其他派生的GUI类添加任何函数,我还必须在基类中声明它们是虚拟的,这样编译器就不会抱怨“setHotSpot”之类的东西不是它返回的基类的成员

基类确实有将应用于所有派生类的成员函数,例如告诉对象它应该定位在哪里,它需要使用什么映像,应该调用什么,等等。但是我不想继续用其他函数填充基类,这些函数需要保持对某些派生类的独占性

随着我不断添加更多的虚拟函数,我最终会为基类创建一个巨大的blob对象。我可以用更干净的方式设计这个吗?请注意,我仍然不确定是否要使用getControl()的静态\u cast/动态\u cast来解决此问题,但我只想知道是否有其他方法可以解决此问题。

基类应该只包含所有控件共有的功能的方法

如果要使用仅对一种控件类型有意义的功能,则应检查该控件是否为正确的类型,然后可以将其强制转换为该类型。

基类应仅包含所有控件共有的功能的方法

如果要使用仅对一种类型的控件有意义的功能,则应检查该控件是否为正确的类型,然后可以将其强制转换为该类型。

基类仅为通用功能。如果希望您的方法在不同控件中表现不同,请使用
dynamic\u cast
。如果希望它对所有控件的作用相同,请使用虚拟方法

这就是你的问题:

我只想要一个 函数返回任何类型的 组件,但能够与 特定于该组件的功能 类型(派生类的函数)

你想要的是以相同但不同的方式对待他们。呵呵。我不知道你打算怎么做。您需要决定是要对它们一视同仁,还是要区别对待。

基类是唯一通用的功能。如果希望您的方法在不同控件中表现不同,请使用
dynamic\u cast
。如果希望它对所有控件的作用相同,请使用虚拟方法

这就是你的问题:

我只想要一个 函数返回任何类型的 组件,但能够与 特定于该组件的功能 类型(派生类的函数)


你想要的是以相同但不同的方式对待他们。呵呵。我不知道你打算怎么做。你需要决定是要一视同仁,还是要区别对待。

类型检查,然后向下转换不是正确的方法。您应该做的是将泛型方法放置到执行所需操作类型的基类上,然后在子类中重写它们。例如,如果您希望GUIControl能够绘制自身,那么在基类上放置一个doDraw()方法,然后在每个子类中重写该方法以根据需要执行操作。如果改为在子类上放置getTitleBar()、getText()等方法,然后让调用方向下转换,并根据类型调用这些特定方法,则封装被破坏。如果您有一些多个子类需要绘制的公共代码,那么您可以通过另一个父类或组合来考虑这些代码。使用dynamic_cast,或者在泛型子类上放置特定的方法,可能会使代码变得更糟糕。

类型检查然后向下转换不是正确的方法。您应该做的是将泛型方法放置到执行所需操作类型的基类上,然后在子类中重写它们。例如,如果您希望GUIControl能够绘制自身,那么在基类上放置一个doDraw()方法,然后在每个子类中重写该方法以根据需要执行操作。如果改为在子类上放置getTitleBar()、getText()等方法,然后让调用方向下转换,并根据类型调用这些特定方法,则封装被破坏。如果您有一些多个子类需要绘制的公共代码,那么您可以通过另一个父类或组合来考虑这些代码。使用dynamic_cast,或在泛型子类上放置特定方法,可能会使代码变得更糟。

如果我有这个权利:您希望能够传递基类对象,但有一种干净的方法来调用特定的派生类方法,而派生类实现了这些方法

听起来“mixin”模式可能会有所帮助:

struct Base
{
    virtual ~Base() {}
};


struct Mixin
{
    virtual ~Mixin() {}
    virtual void mixedMethod() = 0;
};

struct Concrete : Base, Mixin
{
    virtual void mixedMethod() { std::cout << "Mixing" << std:: endl; }
};

Base* create() { return new Concrete;}

bool mixIt(Base& b)
{
    Mixin* m = dynamic_cast<Mixin*>(&b);
    if (m)
        m->mixedMethod();
    return m;
}    

void test ()
{
    Base* b = create();
    assert(mixIt(*b));
    Base base;
    assert(!mixIt(base));   
}
struct Base
{
虚拟~Base(){}
};
结构混合
{
虚拟~Mixin(){}
虚拟void mixedMethod()=0;
};
结构混凝土:基础、拌合物
{

virtualvoid mixedMethod(){std::cout如果我有这个权利:您希望能够传递基类对象,但有一种干净的方法来调用特定的派生类方法,其中派生类实现了这些方法

听起来“mixin”模式可能会有所帮助:

struct Base
{
    virtual ~Base() {}
};


struct Mixin
{
    virtual ~Mixin() {}
    virtual void mixedMethod() = 0;
};

struct Concrete : Base, Mixin
{
    virtual void mixedMethod() { std::cout << "Mixing" << std:: endl; }
};

Base* create() { return new Concrete;}

bool mixIt(Base& b)
{
    Mixin* m = dynamic_cast<Mixin*>(&b);
    if (m)
        m->mixedMethod();
    return m;
}    

void test ()
{
    Base* b = create();
    assert(mixIt(*b));
    Base base;
    assert(!mixIt(base));   
}
struct Base
{
虚拟~Base(){}
};
结构混合
{
虚拟~Mixin(){}
虚空混合法