虚函数的多态性只能通过对象指针或对象的引用调用来实现,如下的调用:
X obj;
X* ptr = &obj; X& ref = obj;
ptr->VirtualFunc();
ref.VirtualFunc();
将被C++(www.cppentry.com)编译器转换为如下的形式。
( *ptr->vptr )(ptr);
( *ptr->vptr )(&ref);
其中的2表示VirtualFunc在类虚函数表的第2个槽位。可以看出,虚函数的调用相当于一个C的函数指针调用,其效率也并未降低。
由以上的四个例子可以看出,C++(www.cppentry.com)的函数调用效率依然很高。但C++(www.cppentry.com)还是有其特殊性,为了保证面向对象语义的正确性,C++(www.cppentry.com)编译器会在程序员所编写的程序基础上,做大量的扩展,如果程序员不了解编译器背后所做的这些工作,就可能写出效率不高的程序。对于一些继承层次很深的派生类或在成员变量中包含了很多其它类对象(如XX中的m_strName变量)的类来说,对象的创建和销毁的开销是相当大的,比如XX类的缺省构造函数,即使程序员没有定义任何语句,编译器依然会给其构造函数扩充以下代码来保证对象语义的正确性:
XX::XX()
{
// 编译器扩充代码所要做的工作
1、调用父类X的缺省构造函数
2、设定vptr指向XX类虚函数表
3、调用String类的缺省构造函数构造m_strName
};
所以为了提高效率,减少不必要的临时对象的产生、拖延暂时不必要的对象定义、用初始化代替赋值、使用构造函数初始化列表代替在构造函数中赋值等方法都能有效提高程序的运行效率。以下举例说明:
1、减少临时对象的生成。如以传送对象引用的方式代替传值方式来定义函数的参数,如下例所示,传值方式将导致一个XX临时对象的产生
效率不高的做法 高效率做法
void Function( XX xx ) void Function( const XX& xx)
{ {
//函数体 //函数体
} }
2、拖延暂时不必要的对象定义。在C中要将所有的局部变量定义在函数体头部,考虑到C++(www.cppentry.com)中对象创建的开销,这不是一个好习惯。如下例,如果大部分情况下bCache为“真”,则拖延xx的定义可以大大提高函数的效率。
效率不高的做法 高效率做法
void Function( bool bCache ) void Function( bool bCache )
//函数体 //函数体
XX xx;
if( bCache )
if( bCache ) {// do something without xx{ return;
// do something without xx}
return; }
}
//对xx进行操作XX xx;
//对xx进行操作
…
return; return;
} }
3、可能情况下,以初始化代替先定义后赋值。如下例,高效率的做法会比效率不高的做法省去了cache变量的缺省构造函数调用开销。
效率不高的做法 高效率做法
void Function( const XX& xx ) oid Function( const XX& xx )(传引用可以省去临时对象构造和析构的过程)
{ {
XX cache; (调用了构造函数) XX cache = xx;(只调用了复制构造函数)
cache = xx ; (调用了赋值函数)
} }
4、在构造函数中使用成员变量的初始化列表代替在构造函数中赋值。如下例,在效率不高的做法中,XX的构造函数会首先调用m_strName的缺省构造函数,再产生一个临时的String object,用空串“”初始化临时对象,再以临时对象赋值(assign)给m_strName,然后销毁临时对象。而高效的做法只需要调用一次m_strName的构造函数。
效率不高的做法 高效率做法
XX::XX() XX::XX() : m_strName( “” )
{ {
m_strName = “”; …
…
} }
类似的例子还很多,如何写出高效的C++(www.cppentry.com)程序需要实践和积累,但理解C++(www.cppentry.com)的底层运行机制是一个不可缺少的步骤,只要平时多学习和思考,编写高效的C++(www.cppentry.com)程序是完全可行的。