CRTP 或编译时多态性适用于您在编译时知道所有类型的情况。只要您addWidget
用于在运行时收集小部件列表,fooAll
并且barAll
必须在运行时处理该同质小部件列表的成员,您就必须能够在运行时处理不同的类型。因此,对于您提出的问题,我认为您无法使用运行时多态性。
当然,一个标准的答案是在尝试避免它之前验证运行时多态性的性能是否存在问题......
如果您确实需要避免运行时多态性,那么以下解决方案之一可能会起作用。
选项 1:使用小部件的编译时集合
如果您的 WidgetCollection 的成员在编译时是已知的,那么您可以非常轻松地使用模板。
template<typename F>
void WidgetCollection(F functor)
{
functor(widgetA);
functor(widgetB);
functor(widgetC);
}
// Make Foo a functor that's specialized as needed, then...
void FooAll()
{
WidgetCollection(Foo);
}
选项 2:用自由函数替换运行时多态性
class AbstractWidget {
public:
virtual AbstractWidget() {}
// (other virtual methods)
};
class WidgetCollection {
private:
vector<AbstractWidget*> defaultFooableWidgets;
vector<AbstractWidget*> customFooableWidgets1;
vector<AbstractWidget*> customFooableWidgets2;
public:
void addWidget(AbstractWidget* widget) {
// decide which FooableWidgets list to push widget onto
}
void fooAll() {
for (unsigned int i = 0; i < defaultFooableWidgets.size(); i++) {
defaultFoo(defaultFooableWidgets[i]);
}
for (unsigned int i = 0; i < customFooableWidgets1.size(); i++) {
customFoo1(customFooableWidgets1[i]);
}
for (unsigned int i = 0; i < customFooableWidgets2.size(); i++) {
customFoo2(customFooableWidgets2[i]);
}
}
};
丑陋的,真的不是OO。模板可以通过减少列出每个特殊情况的需要来帮助解决此问题;尝试以下类似的方法(完全未经测试),但在这种情况下你又回到了没有内联的状态。
class AbstractWidget {
public:
virtual AbstractWidget() {}
};
class WidgetCollection {
private:
map<void(AbstractWidget*), vector<AbstractWidget*> > fooWidgets;
public:
template<typename T>
void addWidget(T* widget) {
fooWidgets[TemplateSpecializationFunctionGivingWhichFooToUse<widget>()].push_back(widget);
}
void fooAll() {
for (map<void(AbstractWidget*), vector<AbstractWidget*> >::const_iterator i = fooWidgets.begin(); i != fooWidgets.end(); i++) {
for (unsigned int j = 0; j < i->second.size(); j++) {
(*i->first)(i->second[j]);
}
}
}
};
选项 3:消除 OO
OO 很有用,因为它有助于管理复杂性,并且有助于在面对变化时保持稳定性。对于您所描述的情况 - 数千个小部件,其行为通常不会改变,并且其成员方法非常简单 - 您可能没有太多复杂性或需要管理的更改。如果是这种情况,那么您可能不需要 OO。
此解决方案与运行时多态性相同,只是它要求您维护“虚拟”方法和已知子类(不是 OO)的静态列表,并且它允许您将虚拟函数调用替换为内联函数的跳转表。
class AbstractWidget {
public:
enum WidgetType { CONCRETE_1, CONCRETE_2 };
WidgetType type;
};
class WidgetCollection {
private:
vector<AbstractWidget*> mWidgets;
public:
void addWidget(AbstractWidget* widget) {
widgets.push_back(widget);
}
void fooAll() {
for (unsigned int i = 0; i < widgets.size(); i++) {
switch(widgets[i]->type) {
// insert handling (such as calls to inline free functions) here
}
}
}
};