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