使用模板方法设计模式考虑以下代码:
class A {
public:
void templateMethod() {
doSomething();
}
private:
virtual void doSomething() {
std::cout << “42\n”;
}
};
class B : public A {
private:
void doSomething() override {
std::cout << “43\n”;
}
};
int main() {
// case 1
A a; // value semantics
a.templateMethod(); // knows at compile time that A::doSomething() must be called
// case 2
B b; // value semantics
b.templateMethod(); // knows at compile time that B::doSomething() must be called
// case 3
A& a_or_b_ref = runtime_condition() ? a : b; // ref semantics
a_or_b_ref.templateMethod(); // does not know which doSomething() at compile time, a virtual call is needed
return 0;
}
我想知道编译器是否能够在案例1和2中内联/取消虚拟化“doSomething()”成员函数。 如果它为templateMethod()创建3个不同的二进制代码片段,则可以实现:一个没有内联,一个没有内联的A :: doSomething()或者B :: doSomething()(在情况3中必须分别调用, 1和2)
您知道标准是否需要此优化,或者是否有任何编译器实现它? 我知道我可以用CRT模式实现同样的效果而不是虚拟,但意图不太明确。
答案 0 :(得分:1)
该标准一般不需要优化(偶尔会不允许它们);它指定了结果,由编译器决定如何最好地实现它。
在所有三种情况下,我都希望内联templateMethod
。然后编译器可以自由地执行进一步的优化;在前两种情况下,它知道this
的动态类型,因此可以为doSomething
生成非虚拟调用。 (然后我希望它可以内联这些电话。)
查看生成的代码并亲自查看。
答案 1 :(得分:0)
优化是编译器不是标准的问题。如果优化导致不尊重或虚函数的原理,那将是一个主要的错误。
所以在第三种情况下:
// case 3
A& b_ref = b; // ref semantics
b_ref.templateMethod();
实际对象是B,并且调用的实际函数必须是B类中定义的函数,无论指针的引用是什么。
我的编译器正确显示43
- 它显示了我会立即改变编译器的其他内容......