0

基于以下代码,如何在我的“控制器”类中存储指向 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!
};
4

3 回答 3

1

Short answer - you can't.

Assuming the template argument doesn't affect Base's interface (ie: Derived doesn't appear in any function signatures) you could have a non template Base class, and the derived classes could be templates. This however doesn't fit at all with your current pattern.

In your case if the template argument DOES affect the interface (and I strongly suspect it does in this case) then the Controller would need to know about Derived in order to use Base, so where's the harm in it also knowing about Derived in order to declare Base.

EDIT after comment: Are you sure that you want any derived class to be able to serialise to any type? Why not to have a heirarchy of classes that derive from a Serialiser base class, then Serialise() can accept a reference to type Serialiser and lose the template parameter.

于 2013-02-12T12:54:45.830 回答
0

由于基类的类型取决于派生类的类型,因此您似乎想要对问题采取的具体方法是不可能的。这意味着基类模板实例不能表示为单一类型,这对于实现您正在采用的方法是必要的。

然而,这看起来是一个乞求访问者模式的问题。访问者模式使双重调度成为可能,而无需强制转换,这正是您想要的。这是一个可能的解决方案:

// 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;
};
于 2013-02-15T23:41:20.070 回答
0

你不能那样做。但是 Base::Serialise 所做的唯一事情就是调用派生类的 Serialise 方法。为什么不把它变成纯虚拟的,这样 Base 就不需要模板参数了?

于 2013-02-12T12:56:20.937 回答