C++ 基本机制

示例

类型擦除是一种使用对象从代码中隐藏对象类型的方法,即使它不是从通用基类派生的也是如此。这样,它为静态多态性(模板;在使用时必须在编译时知道确切的类型,但不必在定义时声明为符合接口)之间建立桥梁。 (继承和虚函数;在使用时,不需要在编译时知道确切的类型,而必须在定义时声明其符合接口)。

以下代码显示了类型擦除的基本机制。

#include <ostream>

class Printable
{
public:
  template <typename T>
  Printable(T value) : pValue(new Value<T>(value)) {}
  ~Printable() { delete pValue; }
  void print(std::ostream &os) const { pValue->print(os); }

private:
  Printable(Printable const &)        /* in C++1x: =delete */; // 未实现
  void operator = (Printable const &) /* in C++1x: =delete */; // 未实现
  struct ValueBase
  {
      virtual ~ValueBase() = default;
      virtual void print(std::ostream &) const = 0;
  };
  template <typename T>
  struct Value : ValueBase
  {
      Value(T const &t) : v(t) {}
      virtual void print(std::ostream &os) const { os << v; }
      T v;
  };
  ValueBase *pValue;
};

在使用现场,仅上述定义是可见的,就像带有虚拟函数的基类一样。例如:

#include <iostream>

void print_value(Printable const &p)
{
    p.print(std::cout);
}

请注意,这不是模板,而是仅需要在头文件中声明且可以在实现文件中定义的常规函数(与模板不同,模板的定义必须在使用位置可见)。

在具体类型的定义中,不需要了解任何信息Printable,它只需要符合接口,就像模板一样:

struct MyType { int i; };
ostream& operator << (ostream &os, MyType const &mc)
{
  return os << "MyType {" <<mc.i<< "}";
}

现在,我们可以将此类的对象传递给上面定义的函数:

MyType foo = { 42 };
print_value(foo);