假设我有以下代码:
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>
一个friend
的 Derived
如果你想让它访问 Derived
的 private
函数 foo_impl()
.否则,你可以制作foo_impl()
公开。
关于c++ - C++11 中的 CRTP 调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14712617/