Кажется, что ответ в вопросе - метод, который вы предложили, кажется правильным направлением, за исключением того, что если у вас есть большое количество этих общих членов, вы можете захотеть их собрать в структуру или класс и минус это как аргумент конструктору базового класса.
Если вы настаиваете на том, чтобы «общие» члены реализовывались как статические члены производного класса, вы могли бы автоматически генерировать код производных классов. 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 runtime выполняет uninitializations, он также вызывает деструктор статических объектов, включая наш autoptr, который удаляет наш экземпляр DescriptorsMap.
Итак, теперь у нас есть один экземпляр каждого дескриптора, который также удаляется в конце выполнения.
Обратите внимание, что если единственной целью производного класса является предоставление соответствующих «дескрипторных» данных (т. Е. В отличие от реализации виртуальных функций), то вам следует сделать неклассический базовый класс и просто создать экземпляр с соответствующим дескриптором каждый раз.