c++ - C++11 中的 CRTP 调度

标签 c++ templates c++11 crtp

假设我有以下代码:

template <class Derived>
class Base {
public:
   virtual void foo_impl() = 0;
   void foo() {
      static_cast<Derived*>(this)->foo_impl(); //A
      (*static_cast<Derived*>(this)).foo_impl(); //B
   }
};

class Derived : public Base<Derived> {
private:
   void foo_impl() {
      bar();
   }
};

几个问题:

A行会生成虚函数调用吗?尽管我在互联网上找到的大部分内容都建议以这种方式做事,但对我来说,考虑到指向 Derived 的指针实际上仍可能指向 Derived2 类型的对象,我看不出编译器如何进行静态分派(dispatch),其中 Derived2 :公共(public)派生。

B 行是否解决了我在上一点中提出的问题(如果适用)?考虑到现在调用不再在指针上,因此使用 *.会避免虚函数调用。但是,如果编译器将取消引用的转换视为引用类型,它仍然可以生成虚函数调用...在这种情况下,解决方法是什么?

将 C++11 final 关键字添加到 foo_impl() 是否会改变编译器在任一(或任何其他相关)情况下的行为方式?

最佳答案

Will line A generate a virtual function call?

foo_impl()是虚拟的并且Derived覆盖它。尽管foo_impl()Derived明确标记为virtual , 它在基类中,这足以使它成为一个虚函数。

Does line B fix the issue I brought up in my previous point (if applicable)?

。调用是在指针上还是在引用上并不重要:编译器仍然不知道您是否在调用函数 foo_impl()。在 派生自 的类实例上 Derived ,或在 Derived 的直接实例上.因此,调用是通过 vtable 执行的。

明白我的意思:

#include <iostream>

using namespace std;

template <class Derived>
class Base {
public:
   virtual void foo_impl() = 0;
   void foo() {
      static_cast<Derived*>(this)->foo_impl();
      (*static_cast<Derived*>(this)).foo_impl();
   }
};

class Derived : public Base<Derived> {
public:
   void foo_impl() {
      cout << "Derived::foo_impl()" << endl;
   }
};

class MoreDerived : public Derived {
public:
   void foo_impl() {
      cout << "MoreDerived::foo_impl()" << endl;
   }
};

int main()
{
    MoreDerived d;
    d.foo(); // Will output "MoreDerived::foo_impl()" twice
}

最后:

Does adding the C++11 final keyword to foo_impl() change how the compiler would act in either (or any other relevant) case?

理论上,是的final关键字将无法在 Derived 的子类中重写该函数.因此,在执行对 foo_impl() 的函数调用时通过指向 Derived 的指针,编译器可以静态解析调用。但是,据我所知,C++ 标准并不要求编译器这样做。

结论:

无论如何,我相信您真正想要做的是不声明 foo_impl()在基类中完全起作用。当您使用 CRTP 时通常就是这种情况。此外,您必须声明类 Base<Derived>一个friendDerived如果你想让它访问 Derivedprivate函数 foo_impl() .否则,你可以制作foo_impl()公开。

关于c++ - C++11 中的 CRTP 调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14712617/

相关文章:

c++ - 使用模板重载运算符

c++ - 将指针转换为模板参数 : Comeau & MSVC compile, GCC 失败

c++ - 英特尔 TBB 比标准慢 2 倍 - tbb vs std

c++ - 针对 musl 和 glibc 将数据/时间转换为 tm/time_point。一般的方法

c++ - 更改 const 对象的数组成员的元素

c++ - 如何在 std::future 中使用 decltype?

c++ - 相同的代码,如果优先级队列中存在平局,则顺序不同,使用 clang 和 gcc

c++ - 从文件中读取 4 个十六进制值并转换为 float

python - 如何在 Django TemplateView 中为 template_name_field 传递 mixin?

c++ - 如何使用 std::stoi 作为默认值创建 std::function 作为方法参数?