如果使用CRTP,派生类方法是否覆盖方法的基类版本? 几天前,我发现了一个有趣的C++构造,名为奇怪的重复模板模式(通常在缩写CRTP下已知)。从那时起,我一直试图完全理解这个技巧是如何工作的

如果使用CRTP,派生类方法是否覆盖方法的基类版本? 几天前,我发现了一个有趣的C++构造,名为奇怪的重复模板模式(通常在缩写CRTP下已知)。从那时起,我一直试图完全理解这个技巧是如何工作的,c++,inheritance,crtp,static-polymorphism,C++,Inheritance,Crtp,Static Polymorphism,假设我有以下代码片段 #include <iostream> template<class T> struct GraphicalObject { void draw() { static_cast<T*>(this)->draw(); } }; struct Circle : GraphicalObject<Circle> { void draw() { std::

假设我有以下代码片段

#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;
}
因此,创建了具有特殊版本的
draw
方法的struct。结构
GraphicalObject
构成
结构的基础结构


在第二步中,创建
Circle
结构的实例
c
,即调用
Circle
的隐式构造函数。由于
是从
GraphicalObject
继承的,因此首先调用该结构的隐式构造函数。在我看来,这将导致在
c
对象内部创建
GraphicalObject
的实例。是这样吗?然后我认为
draw
方法在
Circle
结构中声明,它覆盖了
GraphicalObject
结构中声明的
draw
方法。但这对我来说没有意义。我更希望从
GraphicalObject
提交的
draw
方法的“专用”版本不会被覆盖。请您告诉我,我对CRTP工作原理的理解有什么错误?

您没有在
main
中进行任何多态性操作,这将演示CRTP的功能。试试这个,看看会发生什么:

模板
void drawObject(GraphicalObject和obj){
obj.draw();
}
int main(){
正方形s;
圈c;
s、 draw();
c、 draw();
drawObject;//这里发生了什么?
图形对象&c_ref=c;
drawObject(c_ref);//这里发生了什么?
}

Circle::draw
不会覆盖
GraphicalObject::draw
(作为非虚拟对象),而是隐藏它。实际上,我们的想法是使用不同的名称。@Jarod42感谢您的回复。这是否意味着我对CRTP工作原理的理解基本正确,但
Circle::draw
隐藏了
GraphicalObject::draw
,而不是覆盖它?感谢您的回复。我是否正确理解,如果我调用
drawObject
,将进行切片,并将
s
切片到
GraphicalObject
。因此,首先调用了
draw
方法的多态版本?我想您已经找到了。
drawObject
中的“切片”(
obj
)调用基类
draw
方法,然后该方法依次调用子类
draw
。这允许您创建伪虚拟函数,而无需将其定义为
虚拟
(即静态多态性)。
struct GraphicalObject<Circle>
{
 void draw()
 {
  static_cast<Circle*>(this)->draw();
 }
};