背景
CRTP 是 一種 C++ 的設計方法,其巧妙的結合了繼承和模闆程式設計技術,可以用來給類提供額外的功能。
CRTP
①.概述
CRTP 的基本特征表現為:基類是一個模闆類;派生類在繼承該基類時,将派生類自身作為模闆參數傳遞給基類。
②.實作示例
template<typename T>
class baseDemo
{
public:
virtual ~baseDemo(){}
void interface()
{
static_cast<T*>(this)->imp();
}
};
class derivedDemo:public baseDemo<derivedDemo>
{
public:
void imp()
{
cout << " hello world " << endl;
}
};
靜态多态
①.概述
多态是指同一個方法在基類和不同派生類之間有不同的實作,C++ 通過虛函數實作多态,但是虛函數會影響類的記憶體布局,并且虛函數的調用會增加運作時的開銷。
②.靜态多态
CRTP 可以實作靜态多态,但本質上 CRTP 中的多個派生類并不是同一個基類,是以嚴格意義上不能叫多态。
template<typename T>
class baseDemo
{
public:
virtual ~baseDemo(){}
void interface() { static_cast<T*>(this)->imp(); }
void imp() { cout << "imp hello world " << endl; }
};
class derivedDemo1:public baseDemo<derivedDemo1>
{
public:
void imp(){ cout << "derivedDemo1 hello world " << endl; }
};
class derivedDemo2 :public baseDemo<derivedDemo2>
{
public:
void imp() { cout << "derivedDemo2 hello world " << endl; }
};
template<typename T>
void funcDemo(T & base)
{
base.interface();
}
int main()
{
derivedDemo1 d1;
derivedDemo2 d2;
funcDemo(d1);
funcDemo(d2);
return 0;
}
代碼複用
①.概述
使用 CRTP 可以把重複性的代碼抽象到基類中,減少代碼備援。
②.代碼示例
template<typename T>
class baseDemo
{
public:
virtual ~baseDemo(){}
void getType()
{
T& t = static_cast<T&>(*this);
cout << typeid(t).name() << endl;
}
};
class derivedDemo1:public baseDemo<derivedDemo1>
{
};
class derivedDemo2 :public baseDemo<derivedDemo2>
{
};
int main()
{
derivedDemo1 d1;
derivedDemo2 d2;
d1.getType();
d2.getType();
return 0;
}
擴充既有類的功能
①.概述
使用 CRTP 可以在基類中調用派生類的成員函數,進而可以在調用前後擴充新的操作。
②.代碼示例
template<typename T>
class baseDemo
{
public:
virtual ~baseDemo() {}
void interface()
{
cout << "hello " << endl;
static_cast<T*>(this)->imp();
}
};
class derivedDemo :public baseDemo<derivedDemo>
{
public:
void imp()
{
cout << "derivedDemo " << endl;
}
};
int main()
{
derivedDemo demo;
demo.interface();
return 0;
}
CRTP 應用示例
應用 CRTP 可以把一個類變為單例模式,代碼如下:
template<typename T>
class singlePatternTemplate
{
public:
virtual ~singlePatternTemplate() {}
singlePatternTemplate(const singlePatternTemplate&) = delete;
singlePatternTemplate & operator=(const singlePatternTemplate&) = delete;
static T& getSingleObj()
{
static T obj;
return obj;
}
protected:
singlePatternTemplate(){}
};
class derivedDemo :public singlePatternTemplate<derivedDemo>
{
friend singlePatternTemplate<derivedDemo>;
private:
derivedDemo(){}
};