• 初步认识虚函数(三)


    #include<iostream>
    using namespace std;
    class A{//虚函数示例代码2
        public:
            virtual void fun(){cout<<"A::fun"<<endl;}
            virtual void fun2(){cout<<"A::fun2"<<endl;}
    };
    class B : public A{
        public:
            void fun(){cout<<"B::fun"<<endl;}
            void fun2(){cout<<"B::fun2"<<endl;}
    };//end//虚函数示例代码2
    int main()
    {
        void(A::*fun)();//定义一个函数指针
        A *p=new B;
        fun=&A::fun;
        (p->*fun)();
        fun=&A::fun2;
        (p->*fun)();
        delete p;
        system("pause");
        return 0;
    }
    误区
    你能估算出结果吗?如果你估算出的结果是A::fun和A::fun2,呵呵,恭喜恭喜,你中圈套了。其实真正的结果是B::fun和B::fun2,如果你想不通就接着往下看。给个提示,&A::fun和&A::fun2是真正获得了虚函数的地址吗?
    首先我们回到第二部分,通过段实作代码,得到一个“通用”的获得虚函数地址的方法
    #include<iostream>
    using namespace std;
    //将上面“虚函数示例代码2”添加在这里
    void CallVirtualFun(void*pThis,intindex=0)
    {
        void(*funptr)(void*);
        long lVptrAddr;
        memcpy(&lVptrAddr,pThis,4);
        memcpy(&funptr,reinterpret_cast<long*>(lVptrAddr)+index,4);
        funptr(pThis);//调用
    }
    int main()
    {
        A *p = new B;
        CallVirtualFun(p);//调用虚函数p->fun()
        CallVirtualFun(p,1);//调用虚函数p->fun2()
        system("pause");
        return 0;
    }
    CallVirtualFun
    现在我们拥有一个“通用”的CallVirtualFun方法。
    这个通用方法和第三部分开始处的代码有何联系呢?联系很大。由于A::fun()和A::fun2()是虚函数,所以&A::fun和&A::fun2获得的不是函数的地址,而是一段间接获得虚函数地址的一段代码的地址,我们形象地把这段代码看作那段CallVirtualFun。编译器在编译时,会提供类似于CallVirtualFun这样的代码,当你调用虚函数时,其实就是先调用的那段类似CallVirtualFun的代码,通过这段代码,获得虚函数地址后,最后调用虚函数,这样就真正保证了多态性。同时大家都说虚函数的效率低,其原因就是,在调用虚函数之前,还调用了获得虚函数地址的代码。
    其他信息
    定义虚函数的限制:(1)非类的成员函数不能定义为虚函数,类的成员函数中静态成员函数和构造函数也不能定义为虚函数,但可以将析构函数定义为虚函数。实际上,优秀的程序员常常把基类的析构函数定义为虚函数。因为,将基类的析构函数定义为虚函数后,当利用delete删除一个指向派生类定义的对象指针时,系统会调用相应的类的析构函数。而不将析构函数定义为虚函数时,只调用基类的析构函数。
    (2)只需要在声明函数的类体中使用关键字“virtual”将函数声明为虚函数,而定义函数时不需要使用关键字“virtual”。
    (3)当将基类中的某一成员函数声明为虚函数后,派生类中的同名函数(函数名相同、参数列表完全一致、返回值类型相关)自动成为虚函数。
    (4)如果声明了某个成员函数为虚函数,则在该类中不能出现和这个成员函数同名并且返回值、参数个数、类型都相同的非虚函数。在以该类为基类派生类中,也不能出现和这个成员函数同名并且返回值、参数个数、类型都相同的非虚函数。
    虚函数联系到多态,多态联系到继承。所以本文中都是在继承层次上做文章。没了继承,什么都没得谈。
  • 相关阅读:
    Kibana详细入门教程
    Python爬取食品商务网蔬菜价格数据,看看蔬菜最近的价格情况
    用Python爬取某蔬菜网的行情,分析底哪个地区的蔬菜便宜
    ES启动失败;java.lang.IllegalStateException: No factory method found for class org.apache.logging.log4j.c
    ELK 5.0 组件后台启动
    linux中/etc/security/limits.conf配置文件说明
    redis面试常见问题
    单线程的Redis为什么能支持10w+的QPS?
    Redis大Key优化
    redis中查找大key方法汇总
  • 原文地址:https://www.cnblogs.com/ye-ming/p/9294259.html
Copyright © 2020-2023  润新知