VS2017中测试结果
重写、同名隐藏、函数重载区别 首先说一下函数重载,函数重载,两个必须在同一个作用域里,函数名,参数名必须相同,参数列表必须不同。 同名隐藏和重写都是在继承体系中,前者,眼球基类与派生类具有同名成员函数,且它与虚函数无关。后者要求被重写的函数载基类中必须是虚函数,且函数原型完全一致。
什么是抽象类?抽象类特性?一般什么情况下需要将一个类设置成抽象类 我们将包含纯虚函数的类称为抽象类。纯虚函数即为在虚函数的后面加上=0。抽象类不能实例化对象。派生类简单继承后也不能实例化对象,在派生类中必须重写纯虚函数,该派生类才可以实例化对象。有的时候设计一个类时并不需要创建这个类的实例,(或者你无法具体的给出这个类中虚函数的具体内容)声明这个类的目的主要是为了让派生类继承他,并实现抽象的方法,以实现多态的效果,这种情况下需要设计抽象类。
虚函数实现原理 简单来说,每个虚函数都有与之相对应的虚函数表,虚函数表的实质是一个指针数组, 该数组中存放的是每个对象的虚函数的地址。派生类会继承基类的虚函数,也会继承虚函数表,同时把自己的虚函数的地址加进去,如果派生类重写了基类的虚函数,则派生类重写的虚函数地址会覆盖掉它从基类中继承下来的虚函数地址,生成自己的虚函数表。
虚函数调用原理 虚函数存放在虚函数表中,虚函数表的地址存放在对象的前四个字节中(后面存放的是该对象的成员变量),我们从对象的前四个字节中取出虚函数表的地址,即就是函数指针数组的首地址,再将其转换成函数指针,通过解引用和++,可调用其中的虚函数。
#include<iostream> #include<string> using namespace std ; class Base { public : virtual void TestFunc1 ( ) { cout << "Base::TestFunc1()" << endl ; } virtual void TestFunc2 ( ) { cout << "Base::TestFunc2()" << endl ; } virtual void TestFunc3 ( ) { cout << "Base::TestFunc3()" << endl ; } int _b ; } ; class Derived : public Base { public : virtual void TestFunc4 ( ) { cout << "Derived::TestFunc4()" << endl ; } virtual void TestFunc1 ( ) { cout << "Derived::TestFunc1()" << endl ; } virtual void TestFunc3 ( ) { cout << "Derived::TestFunc3()" << endl ; } virtual void TestFunc5 ( ) { cout << "Derived::TestFunc5()" << endl ; } int _d ; } ; typedef void ( * PVFT ) ( ) ; //声明函数指针,方便掉用虚函数 void PrintVFT ( Base & b , const string & str ) { cout << str << endl ; PVFT * pVFT = ( PVFT * ) ( * ( int * ) & b ) ;//(int *)&b 就是取虚表的地址,即就是函数指针数组的首地址,再将其转换成函数指针 while (* pVFT) //虚表中最后放的是00 00 00 00(我用的vs编译器) { (* pVFT) ( ) ; // 解引用就是函数指针数组里面的第一个元素(即就是第一个虚函数地址) + + pVFT ; //取下一个 } cout << endl ; } void TestVirtualFunc ( Base & b ) { b . TestFunc1 ( ) ; b . TestFunc3 ( ) ; return; } int main ( ) { Base b ; Derived d ; // 打印基类与派生类的虚表 PrintVFT ( b , "Base VFT:" ) ; PrintVFT ( d , "Derived VFT:" ) ; // 传递Base类对象 TestVirtualFunc ( b ) ; cout << endl ; // 传递派生类对象 TestVirtualFunc ( d ) ; return 0 ; } 小白一只,若有错误的地方,欢迎指出:>