根据以下代码,如何在“Controller”类中存储指向Base的指针?
template< class Derived >
class Base
{
public:
template < typename T >
void Serialise( T* t )
{
Derived* d = static_cast< Derived* >( this );
d->Serialise( t );
}
};
class Derived : public Base< Derived >
{
public:
template < typename T >
void Serialise( T* t )
{
printf( "serialising to object T\n" );
}
};
因此,如果我有一个Controller类,它将调用Serialise函数并传入对象以进行序列化,我最终必须存储已知其派生类型的指针,因为它是我需要的对象类型的一部分能够使用Base类型而不知道它的实际类型是什么:
class Controller
{
public:
void DoSerialise();
private:
Base< Derived >* m_myObject; // I want this to just be Base* m_myObject but cant due to template!
};
答案 0 :(得分:1)
简短回答 - 你不能。
假设模板参数不影响Base的接口(即:Derived不出现在任何函数签名中),您可以拥有非模板Base类,派生类可以是模板。但是,这与您当前的模式完全不符。
在你的情况下,如果模板参数影响接口(我强烈怀疑它在这种情况下确实如此),那么Controller需要知道Derived以便使用 Base,所以在哪里其中的伤害也知道为了宣告基础。衍生。
评论后编辑:
您确定要任何派生类能够序列化到任何类型吗?为什么不使用派生自Serialiser
基类的类的层次结构,然后Serialise()
可以接受对Serialiser
类型的引用并丢失模板参数。
答案 1 :(得分:0)
你做不到。但Base :: Serialise唯一能做的就是调用派生类的Serialise方法。为什么不将它设为纯虚拟,以便Base不需要模板参数?
答案 2 :(得分:0)
您似乎想要解决问题的具体方法是不可能的,因为基类的类型取决于派生类的类型。这意味着基类模板实例化不能表示为单一类型,这对于实现您正在采用的方法是必要的。
然而,这似乎是乞求visitor pattern的问题。访问者模式可以在不进行强制转换的情况下进行双重调度,这正是您想要的。这是一个可能的解决方案:
// First declare a base serializable interface that accepts a serializer.
struct ISerializer;
struct ISerializable {
virtual void accept_serializer(ISerializer const &) const = 0;
};
// Now declare a base serializer type that can accept any serializable type.
struct Serializable1;
struct Serializable2;
...
struct ISerializer {
virtual void serialize(Serializable1 const &) = 0;
virtual void serialize(Serializable2 const &) = 0;
...
};
// Then implement your concrete serializable types to accept the serializer and
// invoke it on themselves.
struct Serializable1 : public ISerializable {
void acceptSerializer(ISerializer const &s) const {
s.serialize(*this);
}
};
struct Serializable2 : public ISerializable {
void acceptSerializer(ISerializer const &s) const {
s.serialize(*this);
}
};
// You can actually be a bit more clever to eliminate redundant code:
template<typename DerivedT>
struct SerializableAdapter {
void acceptSerializer(ISerializer const &s) const {
s.serialize(*static_cast<DerivedT const *>(this));
}
};
struct Serializable1 : public SerializableAdapter<Serializable1> {
};
struct Serializable2 : public SerializableAdapter<Serializable2> {
};
// Finally, implement your concrete serializers, including one function for each
// serializable type.
struct Serializer1 : public ISerializer {
void serialize(Serializable1 const &s) const {
...
}
void serialize(Serializable2 const &s) const {
...
}
};
struct Serializer2 : public ISerializer {
void serialize(Serializable1 const &s) const {
...
}
void serialize(Serializable2 const &s) const {
...
}
};
// Now you can store the serializers through the base interface.
struct Controller {
void doSerialize(ISerializable &p_serializable) {
p_serializable.acceptSerializer(*m_serializer)
}
private:
ISerializer *m_serializer;
};