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