继承是代码重用最常用的方法之一。 面向对象语言致力于继承以收集基类中的通用功能。
什么是多态?
如果您考虑该术语的希腊语根源,应该会很明显。
聚=许多:多边形=多面的,聚苯乙烯=许多苯乙烯(a),多种语言=许多语言,等等。形态=改变或形式:形态=研究生物学形式,莫非斯=希腊梦之神任何形式。
因此,多态性是(在编程中)针对不同底层形式(数据类型)呈现相同接口的能力。
C ++中的多态
C ++支持动态和静态多态。
- 动态多态性:在这种类型的多态性中,在编译时不知道对象的类型(可能基于用户输入等),因此编译器添加了额外的数据结构来支持这一点。 该标准并未规定应如何实施。
- 静态多态性:在这种类型中,对象的类型在编译时本身是已知的,因此实际上无需在数据结构中保存额外的信息。 但是如前所述,我们需要在编译时知道对象的类型。
使用好奇重复模板模式的静态多态
由于本文是关于静态多态性的,因此我们将忽略关于动态多态性的所有讨论。
让我们尝试模拟调用不同的二元运算符。 在事物的总体方案中,可以在需要自己的表达模板库时使用它。
让我们看一个简单的示例代码。
template < typename Derived>
struct BinaryOperator {
float interface ( float x, float y) {
return static_cast <Derived*>( this )->implementation(x, y);
}
};
在这里,我们有一个基类模板BinaryOperator
(请注意,这不是一个类,因为它不会实例化Derived Type,所以它会被实例化),其接口方法调用了派生类的实现。
struct Add : BinaryOperator<Add>{
float implementation ( float x, float y) {
std :: cout << "Implementation Add" << std :: endl ;
return x + y;
}
};
struct Subtract : BinaryOperator<Subtract>{
float implementation ( float x, float y) {
std :: cout << "Implementation Sub" << std :: endl ;
return x - y;
}
};
这些是BinaryOperator
派生类。 在查看BinaryOperator<Add>
,编译器会为Add
和Subtract
生成一个专门的基类。
因此,现在如果我们创建派生类的对象并使用我们的基类持有对它们的引用,则可以调用该接口。 此调用将调度到派生类的实现。
int main () {
std :: cout << std :: endl ;
BinaryOperator<Add>&& add = Add{};
BinaryOperator<Subtract>&& subtract = Subtract{};
std :: cout << add.interface( 4 , 5 ) << std :: endl ;
std :: cout << subtract.interface( 4 , 5 ) << std :: endl ;
std :: cout << std :: endl ;
}
与预期的一样,对add.interface的调用将分派到Add's
实现中,对于Subtract
也是类似的。
Implementation Add
9
Implementation Sub
-1
这是整个代码段。
# include <iostream>
template < typename Derived>
struct BinaryOperator {
float interface ( float x, float y) {
return static_cast <Derived*>( this )->implementation(x, y);
}
};
struct Add : BinaryOperator<Add>{
float implementation ( float x, float y) {
std :: cout << "Implementation Add" << std :: endl ;
return x + y;
}
};
struct Subtract : BinaryOperator<Subtract>{
float implementation ( float x, float y) {
std :: cout << "Implementation Sub" << std :: endl ;
return x - y;
}
};
int main () {
std :: cout << std :: endl ;
BinaryOperator<Add>&& add = Add{};
BinaryOperator<Subtract>&& subtract = Subtract{};
std :: cout << add.interface( 4 , 5 ) << std :: endl ;
std :: cout << subtract.interface( 4 , 5 ) << std :: endl ;
std :: cout << std :: endl ;
}
如果对显式使用浮点数不满意,那么我们也可以将DataType
作为模板参数。
# include <iostream>
template < typename Derived, typename DataType>
struct BinaryOperator {
DataType operator () (DataType x, DataType y) {
return static_cast <Derived*>( this )->implementation(x, y);
}
};
template < typename DataType>
struct Add : BinaryOperator<Add<DataType>, DataType>{
DataType implementation (DataType x, DataType y) {
std :: cout << "Implementation Add" << std :: endl ;
return x + y;
}
};
template < typename DataType>
struct Subtract : BinaryOperator<Subtract<DataType>, DataType>{
DataType implementation (DataType x, DataType y) {
std :: cout << "Implementation Sub" << std :: endl ;
return x - y;
}
};
template < typename DType, template < typename > class Op >
DType execute ( Op <DType> op , DType x , DType y ){
return op(x, y);
}
int main () {
using DType = double ;
std :: cout << std :: endl ;
DType x = 4 ;
DType y = 5 ;
std :: cout << execute(Add<DType>{}, x, y) << std :: endl ;
std :: cout << execute(Subtract<DType>{}, x, y) << std :: endl ;
std :: cout << std :: endl ;
}
谢谢阅读!
From: https://hackernoon.com/static-polymorphism-using-curiously-recurring-template-pattern-crtp-nd2e3yn2