龙盟编程博客 | 无障碍搜索 | 云盘搜索神器
快速搜索
主页 > 软件开发 > C/C++开发 >

C++ 多重继承和虚拟继承对象模型、效率分析(3)

时间:2014-08-15 02:45来源:网络整理 作者:网络 点击:
分享到:
实际上具体继承(非virtual继承)并不会增加空间或者存取时间上的额外负担,但是虚拟继承的“间接性”压抑了“把所有运算都移往缓存器执行”的优化

    实际上具体继承(非virtual继承)并不会增加空间或者存取时间上的额外负担,但是虚拟继承的“间接性”压抑了“把所有运算都移往缓存器执行”的优化能力,即使通过类对象访问编译器也会像对待指针一样(目前是,编译器都没能识别出对“继承而来的data member”的存取是通过一个非多态对象,因而不需要执行期的间接存取), 效率令人担心。但间接性并不会严重影响非优化程序的执行效率,各类型继承效率差别不大。一般来说,virtual base class最有效的运用形式:一个抽象的virtual base class,没有任何data   members。

多态中的function member访问

     在C++中,nonmember/static member/nonstatic member函数都被转化为完全相同的形式(通过managling命名处理),所以它们的效率完全相同。

     如果是通过引用和指针调用虚函数,效率将会降低,这是由C++多态性质决定的。而多重继承和虚拟继承中虚函数的调用比单一继承的效率更低。这个从上面表格可以清楚的看出来:this指针调(比如通过thunk技术调整)和多次初始化vptr。当然,请记住:通过对象访问虚函数和访问非虚成员函数效率是一样的。在调用虚函数而又不需要多态的情况下,可以明确地调用该函数实体:类名::函数名,压制由于虚拟机制而产生的不必要的重复调用操作。

this指针地址调整
       多重继承和虚拟继承中this指针调整使得这两种继承效率降低,实际编程时应该有所警惕。下面列出常见的需要调整this指针的情形:

      1、new 派生类给第二(后继)个基类指针或通过第二(后继)base class调用派生类虚析构函数

      必须调整Derived对象的地址,以使其指向Base2 subobject对象。当删除基类指向的对象时必须再一次调整,使其指向Derived对象的起始地址,然而这个调整只能在执行期完成,在编译时无法确定指针指向的对象类类型。

      下次你看到这种情况不要好奇:pBase2不等于pDerived。      

Derived* pDerived = new Derived;
Base2* pBase2 = pDerived; // Base2为Derived的第二个基类
pBase2 != pDerived;    // 两者不等

 2、通过派生类指针调用第二或后继base class拥有的虚函数

      如果想正确调用必须在编译时调整派生类指针,以指向后继base subobject调用正确的虚函数。由上面的模型图可以看到:如果通过派生类指针调用mumble函数,而mumble函数只存在于后继类的虚函数表中,故必须调整之。

      3、后继base class指针调用返回derived class type的虚函数并且赋值给另一后继base class指针时

      示例如下:

Base2* pb1 = new Derived;  // 调整指针指向base2 clss子对象
Base2* pb2 = pb1->clone(); // pb1被调整至Derived对象的地址,产生新的对象,再次调整对象指针指向base2基类子对象,赋值给pb2。

 记住:Base class指针一定得指向一个完整的与自身类型相同的对象或者子对象地址,不满足这个条件的情形都需要this指针的调整。

     详细知识请参考:《Inside The C++ Object Model》。

精彩图集

赞助商链接