CRTP o polimorfismo en tiempo de compilación es para cuando conoce todos sus tipos en tiempo de compilación. Siempre que use addWidget
para recopilar una lista de widgets en tiempo de ejecución y siempre que fooAll
y barAll
tengan que manejar miembros de esa lista homogénea de widgets en tiempo de ejecución, debe ser capaz de manejar diferentes tipos en tiempo de ejecución. Entonces, para el problema que has presentado, creo que estás atrapado usando el polimorfismo en tiempo de ejecución.
una respuesta estándar, por supuesto, es verificar que el rendimiento de polimorfismo de tiempo de ejecución es un problema antes de intentar evitarlo ...
Si realmente necesita para evitar polimorfismo en tiempo de ejecución, a continuación, una de las siguientes las soluciones pueden funcionar
Opción 1: Utilice una colección de tiempo de compilación de widgets
Si los miembros de su WidgetCollection se conocen en tiempo de compilación, entonces se puede utilizar muy fácilmente plantillas.
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);
}
Opción 2: Reemplazar el polimorfismo en tiempo de ejecución con funciones gratuitas
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]);
}
}
};
feo, y realmente no OO. Las plantillas podrían ayudar con esto al reducir la necesidad de enumerar cada caso especial; intente algo como lo siguiente (completamente no probado), pero está de vuelta a no incluir en este caso.
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]);
}
}
}
};
Opción 3: Eliminar OO
OO es útil porque ayuda a gestionar la complejidad y porque ayuda a mantener la estabilidad en la cara del cambio. Para las circunstancias que pareces estar describiendo, miles de widgets, cuyo comportamiento generalmente no cambia, y cuyos métodos miembros son muy simples, es posible que no tengas mucha complejidad o cambios para administrar. Si ese es el caso, entonces es posible que no necesite OO.
Esta solución es igual que el polimorfismo de tiempo de ejecución, excepto que requiere mantener una lista estática de métodos "virtuales" y subclases conocidas (que no es OO) y le permite reemplazar llamadas de funciones virtuales con una tabla de salto a funciones inline
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
}
}
}
};
Solo una pequeña mentira: los constructores en C++ no pueden ser virtuales :) –
uy, perdón, corregido –
¿Puedes cambiar tus clases base "AbstractWidget" "WidgetCollection" o están diseñadas por otro desarrollador/comunidad? – umlcat