基本机制
类型擦除是一种使用它来隐藏代码类型的方法,即使它不是从公共基类派生的。这样做,它提供了静态多态性世界之间的桥梁(模板;在使用地点,确切类型必须在编译时知道,但不需要声明它符合定义中的接口)和动态多态性(继承和虚函数;在使用地点,确切的类型不需要在编译时知道,但必须声明在定义时符合接口)。
以下代码显示了类型擦除的基本机制。
#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 */; // not implemented
void operator = (Printable const &) /* in C++1x: =delete */; // not implemented
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);