基本機制
型別擦除是一種使用它來隱藏程式碼型別的方法,即使它不是從公共基類派生的。這樣做,它提供了靜態多型性世界之間的橋樑(模板;在使用地點,確切型別必須在編譯時知道,但不需要宣告它符合定義中的介面)和動態多型性(繼承和虛擬函式;在使用地點,確切的型別不需要在編譯時知道,但必須宣告在定義時符合介面)。
以下程式碼顯示了型別擦除的基本機制。
#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);