liam0205.github.io icon indicating copy to clipboard operation
liam0205.github.io copied to clipboard

C++ 惯用法 CRTP 简介 | 始终

Open Liam0205 opened this issue 7 years ago • 7 comments

https://liam.page/2016/11/26/Introduction-to-CRTP-in-Cpp/

虚函数与动态绑定C++ 通过类的继承与虚函数的动态绑定,实现了多态。这种特性,使得我们能够用基类的指针,访问子类的实例。例如我们可以实现一个名为 Animal 的基类,以及 Cat, Dog 等子类,并通过在子类中重载虚函数 jump,实现不同动物的跳跃动作。而后我们可以通过访问 Zoo 类的实例中存有 Animal 指针的数组,让动物园中所有的动物都跳一遍。 123456789101112cla

Liam0205 avatar Jan 12 '19 08:01 Liam0205

写的很好,简单清晰!

pengzh0928 avatar Jul 12 '20 20:07 pengzh0928

std::vector<shared_ptr<Animal>> animals; 应该写成 std::vector<shared_ptr<Animal*>> animals; 否则派生类就截断成基类对象了

ck-dachui avatar Nov 18 '20 13:11 ck-dachui

很好; 多谢分享; thrift 里面,这种方式非常多;

andylau004 avatar May 17 '21 07:05 andylau004

博主最后一个case的实现并没有利用到CRTP的性质 事实上由于CatAnimal_CRTP<Cat>同时拥有签名相同的say()使得Cat中的say()依然也是被重写的虚函数,所以(*iter)->say()实际上直接调用了Cat的虚函数say(). 可以通过在Animal_CRTP<derived>中修改say()的实现来证明:

void say() const override {
      cout << "Calling CRTP say" << endl;
      static_cast<const T*>(this)->say();
    }

按理说应该输出"Calling CRTP say\n Meow~I'm a cat",如果CRTP性质被用到的话

解决方案: 1 在Cat中修改say()say_impl(),在模板类中调用say_impl(), 2 在模板类中给say()加上final修饰符,防止Cat中误override 但是这样做的本质还是调用Animal`的虚函数 所以并不清楚CRTP意义何在

Stewart778 avatar May 23 '21 17:05 Stewart778

@Stewart778 晚点我看一下。

写这篇的时候还很稚嫩,很可能写的不对的。

Liam0205 avatar May 24 '21 02:05 Liam0205

@Stewart778 晚点我看一下。

写这篇的时候还很稚嫩,很可能写的不对的。

No offence for my final sentence. 我个人也是新手,用到CRTP更多是类似duck type的用法 比如:

template<class T>
void foo(Animal_CRTP<T>& concreteAnimal){
    concreteAnimal.say();
}

foo(Cat());
foo(Dog());

感觉利用统一的基类指针操纵子类对象还是一个相当dynamic多态的操作,仅个人意见

Stewart778 avatar May 24 '21 03:05 Stewart778

“而事实上,动态绑定慢,通常是因为多级继承;如果继承很短,那么查虚函数表的开销实际上也没多大。”

多级继承的时候,子类的实例查虚函数表也只需查一次啊,这个是什么意思?

onlytheworld avatar May 01 '24 09:05 onlytheworld