【问题标题】:Interface for template member functions模板成员函数的接口
【发布时间】:2012-07-25 13:54:12
【问题描述】:

有没有一些通用的方法来定义模板成员函数的接口?我想创建一些带有模板成员函数声明的纯抽象基类,这些模板成员函数应该在派生类中被覆盖。比我希望能够通过接口调用派生类的功能。我知道不允许使用虚拟模板成员函数。所以直到现在我想出了以下解决方案(见下文)。我想知道的是我的方法是否是糟糕的设计,或者是否有一些更好的方法可以实现我的目标:

编辑:我要实现的是一个序列化系统(类似于 boost::serialization)。因此,我希望有一个通用的基本接口函数 serialize 可用于保存和加载对象。调用 *do_serialize* 函数时,正确的保存和加载函数调用将由提供的派生存档类确定。

因为我不确定我提供的解决方案,所以我想问一下是否有更好的方法(甚至更简单的方法)来实现我的目标?

接口:

template<typename Derived>
class Archive{
public:
  virtual ~Archive() = 0 {}

  template<typename T>
  Archive& serialize(T t) {
    Derived* derived = static_cast<Derived*>(this);
    return derived->serialize_derived(t);
  }
};

template<typename Derived>
class Writer : public Archive<Derived> {
public:
  virtual ~Writer() = 0 {}

  template<typename T> 
  void write(const T& t) {
    Derived* derived = static_cast<Derived*>(this);
    derived->write_derived(t);
  }
};

template<typename Derived>
class Reader : public Archive<Derived> {
public:
  virtual ~Reader() = 0 {}

  template<typename T> 
  void read(const T& t) {
    Derived* derived = static_cast<Derived*>(this);
    derived->read_derived(t);
  }
};

派生类:

class BinaryWriter : public Writer<BinaryWriter> {
public:
  template<typename T>
  BinaryWriter& serialize_derived(T t) {
    save(t);
    return *this;
  }

  template<typename T>
  void save(T t) {
    std::cout << "DerivedWriter::save: " << t << std::endl;
  }

  template<typename T> 
  void write_derived(const T& t) {
    std::cout << "DerivedWriter::write_derived: " << t << std::endl;
  }
};

class BinaryReader : public Reader<BinaryReader> {
public:
  template<typename T>
  BinaryReader& serialize_derived(T t) {
    load(t);
    return *this;
  }

  template<typename T>
  void load(T t) {
    std::cout << "DerivedWriter::load: " << t << std::endl;
  }

  template<typename T> 
  void read_derived(const T& t) {
    std::cout << "DerivedReader::read_derived: " << t << std::endl;
  }
};

示例测试函数和调用(注意:同样需要调用Writer/Reader-interface(其他派生的Writer/Reader-classes在此省略(即TextReader、XMLReader等)):

template<typename Derived, typename T>
void do_serialize(Archive<Derived>& obj, T t) {
  obj.serialize(t);
}

DerivedWriter dw;
DerivedReader dr;

do_serialize(dw, 1);
do_serialize(dr, 2);

输出:

DerivedWriter::save: 1
DerivedReader::read: 2

【问题讨论】:

  • 你想解决什么问题?
  • 为什么test 不直接取一个Derived&amp; obj 并直接调用正确的方法? (因为您需要在编译时知道派生类型,并且无论如何都不能真正使它像一个虚函数。)
  • 您正在做的事情称为CRTP(或静态多态性)并且很常见。真正的问题在哪里?模板不需要接口,因为它们在编译时检查(不考虑Concepts)。
  • 感谢您的回复。我认为配方不好。我基本上试图实现的是一个类似于 boost 的序列化器。基类用作接口写入/读取的地方。我将更新我的示例以使其更清晰...
  • @aschepler 我想要一个通用的do_serialize(之前的test)函数,它接受所有类型的派生类作为它的参数。如果 do_serialize 直接采用派生类,我想我必须重载函数?!

标签: c++ templates interface virtual member-functions


【解决方案1】:

在知道这种技术称为 CRTP(感谢 pmr)后,我发现了这篇文章 CRTP to avoid virtual member function overhead,我认为它回答了我的问题。正如该帖子中 Kerrek SB 的回答中所述,该技术可用于提供接口。在我的例子中,这个接口甚至可以为模板成员函数定义。

似乎这种模式很常见(我不确定)所以我会接受它作为我问题的答案。

感谢您的所有回复!

【讨论】:

    猜你喜欢
    • 2016-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-07-02
    • 1970-01-01
    • 2010-12-22
    相关资源
    最近更新 更多