Parece que la respuesta está en la pregunta: el método que sugirió parece ser la dirección correcta, excepto que si tiene una gran cantidad de miembros compartidos, puede reunirlos en una estructura o clase y más allá de eso como argumento para el constructor de la clase base.
Si insiste en tener los miembros "compartidos" implementados como miembros estáticos de la clase derivada, es posible que pueda generar automáticamente el código de las clases derivadas. XSLT es una gran herramienta para autogenerar clases simples.
En general, el ejemplo no muestra la necesidad de miembros "estáticos virtuales", porque para fines como estos no necesita herencia, en su lugar debe usar la clase base y que acepte los valores apropiados en el constructor - quizás creando una instancia única de los argumentos para cada "subtipo" y pasándole un puntero para evitar la duplicación de los datos compartidos. Otro enfoque similar es usar plantillas y pasar como el argumento de la plantilla una clase que proporciona todos los valores relevantes (esto se conoce comúnmente como el patrón de "Política").
Para concluir, a los fines del ejemplo original, no hay necesidad de tales miembros "estáticos virtuales". Si aún cree que se necesitan para el código que está escribiendo, intente elaborar y agregar más contexto.
Ejemplo de lo que he descrito anteriormente:
class BaseClass {
public:
BaseClass(const Descriptor& desc) : _desc(desc) {}
string GetName() const { return _desc.name; }
int GetId() const { return _desc.Id; }
X GetX() connst { return _desc.X; }
virtual void UseClass() = 0;
private:
const Descriptor _desc;
};
class DerivedClass : public BaseClass {
public:
DerivedClass() : BaseClass(Descriptor("abc", 1,...)) {}
virtual void UseClass() { /* do something */ }
};
class DerDerClass : public BaseClass {
public:
DerivedClass() : BaseClass("Wowzer", 843,...) {}
virtual void UseClass() { /* do something */ }
};
me gustaría dar más detalles sobre esta solución, y tal vez dar una solución al problema de inicialización:
Con un pequeño cambio, se puede implementar el diseño descrito anteriormente sin crear necesariamente una nueva instancia del "descriptor" para cada instancia de una clase derivada.
Puede crear un objeto único, DescriptorMap, que llevará a cabo la única instancia de cada descriptor, y lo utilizan en la construcción de los objetos derivados de este modo:
enum InstanceType {
Yellow,
Big,
BananaHammoc
}
class DescriptorsMap{
public:
static Descriptor* GetDescriptor(InstanceType type) {
if (_instance.Get() == null) {
_instance.reset(new DescriptorsMap());
}
return _instance.Get()-> _descriptors[type];
}
private:
DescriptorsMap() {
descriptors[Yellow] = new Descriptor("Yellow", 42, ...);
descriptors[Big] = new Descriptor("InJapan", 17, ...)
...
}
~DescriptorsMap() {
/*Delete all the descriptors from the map*/
}
static autoptr<DescriptorsMap> _instance;
map<InstanceType, Descriptor*> _descriptors;
}
Ahora podemos hacer esto:
class DerivedClass : public BaseClass {
public:
DerivedClass() : BaseClass(DescriptorsMap.GetDescriptor(InstanceType.BananaHammoc)) {}
virtual void UseClass() { /* do something */ }
};
class DerDerClass : public BaseClass {
public:
DerivedClass() : BaseClass(DescriptorsMap.GetDescriptor(InstanceType.Yellow)) {}
virtual void UseClass() { /* do something */ }
};
Al final de la ejecución, cuando el tiempo de ejecución de C realiza desinicializaciones, también llama al destructor de objetos estáticos, incluido nuestro autoptr, que elimina nuestra instancia de DescriptorsMap.
Así que ahora tenemos una única instancia de cada descriptor que también se está eliminando al final de la ejecución.
Tenga en cuenta que si el único propósito de la clase derivada es proporcionar los datos del "descriptor" relevante (es decir, en lugar de implementar funciones virtuales) entonces debe conformarse con hacer que la clase base no sea abstracta y crear un instancia con el descriptor apropiado cada vez.