何时使用模板而不是派生类
When to use templates rather than derived classes
除了简化的通用算法之外,模板相对于类层次结构还有什么好处吗?例如,在类层次结构上使用模板是否更有效?模板作为金融工具受到程序员的高度赞扬,但我真的不明白为什么。
模板与类层次结构
主要是虚拟函数调用的成本。如果函数的实际工作的计算成本很小,那么虚拟调度的成本可能很大。与内联函数相比,如果在紧密循环中使用,情况尤其如此。使用运行时多态性排除了函数内联的可能性。
C++模板是一个非常强大的工具
除了C++标准库中常见的通用容器和算法外,C++模板还支持一系列高级技术,如:
- 基于策略的设计
- 模板元编程
从本质上讲,您正在对编译器进行编程,以构建所需的类。如果使用得当,这可以提供高度可重用的最佳代码。如果误用,它可能会给出比更合适的方法更臃肿的对象代码。
当需要速度时,我们使用模板而不是运行时动态多态性,并且模板可能提供编译时多态性(在编译时解决),而没有虚拟方法查找开销。
来自维基百科:
多态性是一种常见的标准编程工具对象可以用作其基础对象的实例,但是将调用派生对象的方法,其中虚拟方法将是派生类最多的方法。这动态多态行为(通常)通过用虚拟方法为类创建虚拟查找表,在运行时遍历的表,以标识要执行的方法调用。因此,运行时多态性必然需要执行开销(尽管在现代建筑中,开销可以忽略不计)。然而,在许多情况下,所需的多态行为是不变的并且可以在编译时确定。然后奇怪地重复模板模式(CRTP)可以用于实现静态多态性,这是对编程代码中多态性的模仿,但在编译时解析,从而取消运行时虚拟表查找。
另一个例子是模板在编译时计算的能力,例如众所周知的阶乘,通常像一样编写
unsigned int factorial(unsigned int n) {
return (n==0)? 1 : n * factorial(n-1);
}
const int x = factorial(4); // == (4 * 3 * 2 * 1 * 1) == 24
const int y = factorial(0); // == 0! == 1
是在运行时计算的。但是使用模板编写
template <int N>
struct Factorial {
enum { value = N * Factorial<N - 1>::value };
};
template <>
struct Factorial<0> {
enum { value = 1 };
};
// Factorial<4>::value == 24
// Factorial<0>::value == 1
const int x = Factorial<4>::value; // == 24
const int y = Factorial<0>::value; // == 1
是在编译时计算的,没有强加任何运行时开销。
- 何时为派生类初始化 vptr?
- 何时使函数成为类成员函数C++?
- 使(虚拟)函数在大多数派生类中无法访问中间基类中可访问,定义良好?
- 如何使函数在派生类中工作?
- 如何使派生类函数在调用时始终调用相同的基类函数?
- 如何使虚函数接受仅在派生类中定义的数据类型?
- C++ 如何使派生类自动获取基类参数
- CRTP 如何使派生类具有基类的容器
- 指向派生类的指针中的"static_cast<Base*>(static_cast<void*>(派生))"何时有效?
- 使派生类遵循特征
- 何时必须使操作员<<过载?
- 使从一个基类派生的类能够使用继承的受保护成员
- 如何使黑客合法化,该黑客假定派生的类变量的相邻存储
- C 虚拟函数何时派生类是最终的
- 使派生类使用重写运算符
- 如何使程序使用功能过载用于派生的类对象
- 为什么通过引用传递从 std::function 派生的对象会使程序崩溃?
- 在Windows上,何时有必要将附加到目录路径上,以使_stat成功
- 如何从 C++ std::basic_ostream 派生并使<<运算符虚拟化?
- 从 ostream 或 ostream_iterator 派生,使流在C++中漂亮的打印机