C++,多态

 // 多态:默认情况下,编译器只会根据指针类型调用对应的函数,不存在多态
   多态是面向对象非常重要的一个特性
   同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果
   在运行中,可以识别出真正的对象类型,调用对应子类中的函数
   
   多态的要素:
   子类重写父类的成员函数(override)
   父类指针指向子类对象
   利用父类指针调用重写的成员函数
   
   
   
   
   // 虚函数
   C++中的多态通过虚函数(virtual function)来实现的.
   虚函数:被virtual修饰的成员函数
   只要在父类中声明为虚函数,子类中的重写的函数也自动变成虚函数(也就是说子类中可以省略virtual)
   
   class Animal {
       public:
       virtual void run(){
       cout << "Animal::run()" << endl;
       }
   };
   
   class Cat:public Animal {
       public:
       void run(){
       cout << "Cat::run()" << endl;
       }
   };
   
   class Dog:public Animal {
       public:
       void run(){
       cout << "Dog::run()" << endl;
       }
   }
   
   int main() {
   
       Animal *animal1 = new Dog()
       animal1->run();
   
       return 0;
   
   }
   
   &&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&7&&&&&&&&&
   // 虚函数:虚函数的实现原理是虚表,这个虚表里面存储着最终需要调用的虚函数地址,这个虚表也叫虚函数表
   
   class Animal {
       public:
       int m_age;
       virtual void speak() {
       cout << "Animal::speak()" << endl;
       }
   
       virtual void run() {
       cout << "Animal::run()" << endl;
       }
   };
   
   class Cat:public Animal {
       public:
       int m_life;
       void speak() {
       cout << "Cat::speak()"<<endl;
       }
       void run() {
       cout << "Cat::run()" << endl;
       }
   }
   
   int main() {
   
       Animal *cat = new Cat()
       cat->m_age = 20;
       cat->speak();
       cat->run();
   
   
       //汇编:调用Cat::speak
   
       mov eax, dword ptr [cat]
       // 取出cat指针变量里面存储的地址值,所以eax里面存放的是Cat对象的地址值
       mov edx, dword ptr [eax]
       // 取出Cat对象的签名4个字节给edx,所以edx里面存储的是虚表的地址
        // 取出虚表中的前面4个字节给eax,所以eax存放的是Cat::speak的函数地址
       mov eax, dword ptr [edx]
       call eax
   
       return 0;
   
   }
   
   
   虚表(x86环境的图)
            内存地址           内存数据                   内存地址           内存数据
   cat     0x00E69B60                       虚表      0x00B89B64
           0x00E69B61      0x00B89B64                0x00B89B65        0x00B814E7
           0x00E69B62                                0x00B89B66
           0x00E69B63                                0x00B89B67
   
   &m_age  0x00E69B64                                0x00B89B68
           0x00E69B65         20                     0x00B89B69        0x00B814CE
           0x00E69B66                                0x00B89B6A
           0x00E69B67                                0x00B89B6B
   
   &m_life 0x00E69B68
           0x00E69B69         0             Cat::speak的调用地址:0x00B814E7
           0x00E69B6A
           0x00E69B6B                         Cat::run的调用地址:0x00B814CEE
   
   
   // 所有的Cat对象(不管在全局区,栈,堆)共用同一份虚表

   
   // 虚析构函数
   含有虚函数的类,应该讲虚析构函数声明为虚函数(虚析构函数)
   delete父类指针时,才会调用子类的析构函数,保证析构的完整性
   
   
   // 纯虚函数
   没有函数体且初始化为0的虚函数,用来定义接口规范.
   含有纯虚函数的类叫做抽象类(abstract Class),不可以实例化,抽象类也可以包含非抽象函数,如果父类是抽象类,子类没有完全实现纯虚函数,那么这个子类依然是抽象类.
   class Animal {
  		     public:
    		 virtual void speak()  = 0;
   			 virtual void run() = 0;
   };
   
   
   // 多继承 - 虚函数
   C++允许一个类可以有多个父类(不建议使用,会增加程序设计复杂度)
   如果子类继承的多个父类都有虚函数,那么子类对象就会产生对应的多张虚表
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值