Кажется, что ответ в вопросе - предложенный вами метод, кажется, является правильным направлением, за исключением того, что если у вас есть большое количество этих общих членов, вы можете собрать их в структуру или класс и мимо этого в качестве аргумента для конструктора базового класса.
Если вы настаиваете на том, чтобы «общие» члены были реализованы как статические члены производного класса, вы можете автоматически генерировать код производных классов. XSLT - отличный инструмент для автоматической генерации простых классов.
В общем, в примере не показана потребность в «виртуальных статических» членах, потому что для подобных целей вам на самом деле не нужно наследование - вместо этого вы должны использовать базовый класс и заставить его принимать соответствующие значения в Конструктор - возможно, создание одного экземпляра аргументов для каждого «подтипа» и передача указателя на него, чтобы избежать дублирования общих данных. Другой аналогичный подход заключается в использовании шаблонов и передаче в качестве аргумента шаблона класса, который предоставляет все соответствующие значения (обычно это называется шаблоном «Политика»).
В заключение - для целей исходного примера такие «виртуальные статические» члены не нужны. Если вы все еще считаете, что они необходимы для написанного вами кода, попробуйте разработать и добавить больше контекста.
Пример того, что я описал выше:
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 */ }
};
Я хотел бы подробнее остановиться на этом решении и, возможно, дать решение проблемы деинициализации:
С небольшими изменениями вы можете реализовать описанный выше дизайн, не обязательно создав новый экземпляр «дескриптора» для каждого экземпляра производного класса.
Вы можете создать одноэлементный объект DescriptorMap, который будет содержать отдельный экземпляр каждого дескриптора и использовать его при создании производных объектов следующим образом:
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;
}
Теперь мы можем сделать это:
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 */ }
};
В конце выполнения, когда среда выполнения C выполняет неинициализацию, она также вызывает деструктор статических объектов, включая наш autoptr, который удаляет наш экземпляр DescriptorsMap.
Итак, теперь у нас есть один экземпляр каждого дескриптора, который также удаляется в конце выполнения.
Обратите внимание, что если единственная цель производного класса состоит в том, чтобы предоставить соответствующие данные "дескриптора" (т.е. в отличие от реализации виртуальных функций), то вы должны обойтись без создания базового класса неабстрактным и просто создания экземпляра с соответствующим дескриптором каждый раз.