我已经读了
Are inline virtual functions really a non-sense?.但我还是有一些疑问,没有发现任何答案.
他们说如果情况不模糊,编译器应该在虚拟函数内联.
然而:
This can happen only when the compiler has an actual object rather than a pointer or reference to an object.
那么如果我有一个派生自A的B类(它包含一个虚拟的void doSth()函数),而我使用B *指针,而不是A *:
B* b = new B; b->doSth();
>假设B没有任何子类.这是很明显的(在编译时)应该调用什么函数.所以有可能内联.是吗?
>假设B有一些子类,但是这些类没有自己的doSth()函数.所以编译器应该“知道”调用唯一的函数是B :: doSth().我想这不是内联吗?
解决方法
B是否有任何派生类没有关系.在这种情况下,b指向B对象,因此编译器可以内联调用.
任何体面的现代编译器肯定会在你的情况下做到这一点.如果你不使用指针,它会变得容易一些.那不是一个真正的“优化”.通过查看运算符左侧的AST节点,可以省略虚拟呼叫的事实变得很明显.但是,如果使用指针,则需要跟踪被指针的动态类型.但是现代编译器是有能力的.
编辑:一些实验是有序的.
// main1.cpp struct A { virtual void f(); }; struct B : A { virtual void f(); }; void g() { A *a = new A; a->f(); a = new B; a->f(); } // clang -O2 -S -emit-llvm -o - main1.cpp | c++filt // ... define void @g()() { %1 = tail call noalias i8* @operator new(unsigned int)(i32 4) %2 = bitcast i8* %1 to %struct.A* %3 = bitcast i8* %1 to i32 (...)*** store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @vtable for A,i32 0,i32 2) to i32 (...)**),i32 (...)*** %3,align 4 tail call void @A::f()(%struct.A* %2) %4 = tail call noalias i8* @operator new(unsigned int)(i32 4) %5 = bitcast i8* %4 to i32 (...)*** store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @vtable for B,i32 (...)*** %5,align 4 %tmp = bitcast i8* %4 to %struct.B* tail call void @B::f()(%struct.B* %tmp) ret void } // ...
可以看出,cl ang ang ang……when when when when when……….