将被编译器转化为一般的C函数调用形式,如同这样:

mangled_name_of_X_StaticFunc();
//obj.StaticFunc();
mangled_name_of_X_StaticFunc();
// ptr- >StaticFunc();
mangled_name_of_X_StaticFunc();
// X::StaticFunc();

  mangled_name_of_X_StaticFunc()是指编译器将X::StaticFunc()函数经过变形(mangled)后的内部名称(C++编译器保证每个函数将被mangled为的名称,不同的编译器有不同的算法,C++标准并没有规定统一的算法,所以mangled之后的名称也可能不同)。可以看出,静态函数的调用同普通的C函数调用有完全相同的效率,并没有额外的开销。

  普通成员函数的调用,如下列方式:

X obj; X* ptr = &obj;
obj.NormalFunc();
ptr->NormalFunc();

  将被被编译器转化为如下的C函数调用形式,如同这样。

mangled_name_of_X_NormalFunc(&obj);
//obj.NormalFunc();
mangled_name_of_X_NormalFunc(ptr);
// ptr- >NormalFunc();

  可以看出普通成员函数的调用同普通的C调用没有大的区别,效率与静态函数也相同。编译器将重新改写函数的定义,增加一个const X* this参数将调用对象的地址传送进函数。

  虚函数的调用稍微复杂一些,为了支持多态性(其基础是函数重载),实现运行时刻绑定,编译器需要在每个对象上增加一个字段也是vptr以指向类的虚函数表vtbl。

  虚函数的多态性只能通过对象指针或对象的引用调用来实现,如下的调用:

X obj;
X* ptr = &obj; X& ref = obj;
ptr->VirtualFunc();
ref.VirtualFunc();

  将被C++编译器转换为如下的形式。

( *ptr->vptr[2] )(ptr);
( *ptr->vptr[2] )(&ref);

  其中的2表示VirtualFunc在类虚函数表的第2个槽位。可以看出,虚函数的调用相当于一个C的函数指针调用,其效率也并未降低。

  由以上的四个例子可以看出,C++的函数调用效率依然很高。但C++还是有其特殊性,为了保证面向对象语义的正确性,C++编译器会在程序员所编写的程序基础上,做大量的扩展,如果程序员不了解编译器背后所做的这些工作,可能写出效率不高的程序。对于一些继承层次很深的派生类或在成员变量中包含了很多其它类对象(如XX中的m_strName变量)的类来说,对象的创建和销毁的开销是相当大的,比如XX类的缺省构造函数,即使程序员没有定义任何语句,编译器依然会给其构造函数扩充以下代码来保证对象语义的正确性:

XX::XX()
{
// 编译器扩充代码所要做的工作

1、调用父类X的缺省构造函数
2、设定vptr指向XX类虚函数表
3、调用String类的缺省构造函数构造m_strName
};