似乎答案就在问题中-您建议的方法似乎是正确的方向,除了如果您有大量共享成员,您可能希望将它们收集到一个结构或类中,然后作为基类的构造函数的参数。
如果您坚持将“共享”成员实现为派生类的静态成员,您也许能够自动生成派生类的代码。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 实例。
所以现在我们有每个描述符的一个实例,它也在执行结束时被删除。
请注意,如果派生类的唯一目的是提供相关的“描述符”数据(即,与实现虚函数相反),那么您应该尽量使基类成为非抽象类,并使用适当的创建实例每次的描述符。