《C++高级编程》关键字virtual的真相

    技术2022-05-14  12

    1、如果不使用virtual修饰父类中将要被覆盖的方法的话,那么在子类中就会出现“隐藏而不是覆盖”。 隐藏而不是覆盖:可以使用一个指向子类对象的父类指针或者引用来调用隐藏的父类方法。 如:

    class Super { public: void talk( ){cout<<"Super says hi in public talk( )/n";} }; class Sub:public Super { protected: void talk( ){cout<<"Sub says hi in protected talk( )/n";} }; Sub mySub; mySub.talk(); //output:Sub says hi in protected talk( ) Super& ptrSuperSub=mySub; ptrSuperSub.talk(); //output:Super says hi in public talk( )

    注意: 试图覆盖非virtual方法将“隐藏”超类的定义,但是仍然可以使用超类的定义。 值得注意的一点是:ptrSuperSub.talk()会调用父类的方法说明:编译器在处理的时候是按照编译时类型来进行解释的,而不是 看对象的实际类型。

    2、virtual是怎样实现的 在C++中编译类时,要创建一个二进制对象,它包含了该类的所有数据成员和方法。在没有关键字virtual的情况下,在基于编译时类型调用 的方法处,跳转到正确方法的代码是直接硬编码hard-coded的。 如果声明方法时使用了virtual,则是在一块特别的内存区域寻找方法的实现,这块内存区域叫做vtable,就是“虚拟表”。包含一个或多个virtual方法的类都有一个vtable,它包含了只想virtual方法实现的指针。通过这种方式,在一个对象上调用方法时,指针就进入vtable查找对应的函数,并且是基于对象的类型执行该方法的正确版本,而不是基于用来访问该方法的变量类型来执行。

    3、virtual的合理性 假如事实建议所有的方法都应该声明为virtual,那为什么还要这个关键字,而不是让编译器默认都添加virtual那? 原因在于vtable的运行开销有关。实际上JAVA就是默认添加全部的virtual的。 要掉用一个vitrual的方法,首先,要先对函数指针进行解引用,这增加了额外的操作。 但是C++的设计者认为应该让程序员决定是否使用。 但是,所有的析构函数都应该写成virtual的形式,否则会引起内存泄漏。 构造函数不能也不许要声明为virtual,因为创建一个对象时,总是会指定要构造的具体类型。


    最新回复(0)