c++ - 如果使用 CRTP,派生类方法是否会覆盖该方法的基类版本?
问题描述
几天前,我发现了一个有趣的 C++ 结构,名为Curiously Recurring Template Pattern(通常缩写为 CRTP)。从那时起,我一直试图完全理解这个技巧是如何工作的。
假设我有以下代码片段
#include <iostream>
template<class T>
struct GraphicalObject
{
void draw()
{
static_cast<T*>(this)->draw();
}
};
struct Circle : GraphicalObject<Circle>
{
void draw()
{
std::cout << "Drawing circle!" << std::endl;
}
};
struct Square : GraphicalObject<Square>
{
void draw()
{
std::cout << "Drawing square!" << std::endl;
}
};
int main(int argc, char** argv) {
Square s;
Circle c;
s.draw();
c.draw();
return 0;
}
CRTP 背后的所有“魔力”显然都在行static_cast<T*>(this)->draw()
。但它是如何详细工作的?我的理解如下。假设我有Circle c
.
如果编译器看到这个声明,这是他GraphicalObject
用参数实例化模板的信号Circle
。我认为这会导致GraphicalObject<Circle>
编译器创建结构
struct GraphicalObject<Circle>
{
void draw()
{
static_cast<Circle*>(this)->draw();
}
};
draw
因此创建了具有该方法的特殊版本的 struct 。该结构GraphicalObject<Circle>
构成该结构的基础Circle
结构。
在第二步中创建结构的实例c
,即调用隐式构造函数。由于首先调用的是从该结构的隐式构造函数继承的事实。在我看来,这会导致创建对象内部的实例。这样对吗?然后我认为struct中声明的方法覆盖了struct中声明的方法。但这对我来说没有意义。我宁愿期望来自 的方法的“专业”版本不会被覆盖。请你能告诉我我对 CRTP 工作原理的理解有什么问题吗?Circle
Circle
Circle
GraphicalObject<Circle>
GraphicalObject<Circle>
c
draw
Circle
draw
GraphicalObject<Circle>
draw
GraphicalObject<Circle>
解决方案
你没有做任何多态的事情main
来展示 CRTP 的特性。试试这个,看看会发生什么:
template <typename T>
void drawObject(GraphicalObject<T>& obj) {
obj.draw();
}
int main() {
Square s;
Circle c;
s.draw();
c.draw();
drawObject(s); // what happens here?
GraphicalObject<Circle>& c_ref = c;
drawObject(c_ref); // what happens here?
}
推荐阅读
- html - CSS 类样式影响类定义之外的 HTML 元素
- typescript - 如何设置 VS Code 以使用 Typescript 调试 Jest?
- android - Android:如何使用模拟位置进行仪器测试?
- mysql - GCP 数据流专用连接 - 无法连接到 MySQL 服务器
- r - 如何在 R studio 的分类多个 ggboxplots 中纠正重叠的 x 轴标签
- asp.net-core - 关于如何绕过不支持 IIS 的 Windows 11 ARM 的想法
- c++ - 如何为成员函数声明一个概念并在友元函数中使用
- python - 如何在不使用 shell=True 的情况下通过 Python subprocess.check_output 调用 FFmpeg 时捕获输出?
- python - 语法错误代码之前有效,但现在无效
- python - 按组和虚拟代码分类变量透视长格式分类数据