【发布时间】:2010-05-26 14:56:13
【问题描述】:
由于我的前一个问题听起来令人困惑,我认为最好清楚地说明我想要实现的目标。
我有(暂时忽略继承,专注于 X):
class Base {};
class X : public Base {
private:
double m_double;
public:
template<class A> friend
void state( A& a, const X& x ) {
data( a, x.m_double, "m_double" );
}
};
我现在可以根据数据函数的重载方式引入执行不同操作的任意新类,我们将在下面将它们称为访问器:
class XmlArchive {...}; //One Accessor
template<class T>
void data( XmlArchive& a, const T& t, const std::string& str ) {
//read data and serialize it to xml Archive
}
class ParameterList {...}; //Another Accessor
template<class T>
void data( ParameterList& a, const T& t, const std::string& str ) {
//put data in a parameter list
}
然后我可以写:
X myX;
XmlArchive myArchive;
state( myArchive, myX );
ParameterList myParameters;
state( myParameters, myX );
太棒了,代码重用! :D 但是以下(显然)失败了:
Base* basePtr = new X; //This would come from factory really, I should not know the type X
state( myParameters, *basePtr ); //Error
目标是使最后一次调用成功。我考虑过的(以及为什么不可接受):
第一种选择:让所有的Accessor都继承自一个通用的基类,比如AccessorBase,然后写在Base中
virtual state( AccessorBase& a ) const = 0;
并在 X 中实现所需的代码(调用状态的语法会略有不同,但可以修复)。 问题是 AccessorBase 需要为每个可能的类型提供一个虚函数,作为数据函数中的第二个参数。由于这些类型可以是用户定义的类(参见类组合的案例,X 具有 Y 作为数据成员)我不知道如何使这种策略起作用。
第二个选项:在 Base 中为每个 Accessor 创建一个虚函数。这违反了打开/关闭原则,因为添加新的访问器类(比如 TxtArchive)将需要修改基类。
我明白为什么不能对虚拟成员函数进行模板化(不同编译单元中可能有不同的 vtbls)。 但是在我看来,这个问题应该有一个解决方案...... Base 知道它确实是 X 类型,并且 Accessor 的类型始终是明确的,所以找到一种调用方式(对于XmlArchive 类型的访问器):
state( xmlArchive, x ); //xmlArchive of type XmlArchive, x of type X
这将产生结果。
总而言之,我想打电话:
state( myParameters, *basePtr );
如果 basePtr 指向具有与调用兼容的函数模板的派生类,则成功,否则抛出异常。
在我看来 boost::serialize 做了类似的事情,但我不知道如何(可能是通过模板在 C++ 中重新实现继承关系,我看到一个 This() 函数返回最派生的指针但是它变得非常混乱......)
再次感谢您的帮助!
【问题讨论】:
标签: c++ inheritance templates boost