C++多态、动态绑定、虚函数
多态与继承
基类的private只有基类能看见 不仅外部看不见派生类也无法访问
public继承 基类的public 和 protected 在派生类中依然是public和protected
protected继承 基类的public 和 protected 在派生类中都是protected
private继承 基类的public 和 protected 在派生类中都是private
总结
外部只能访问public成员,protected 和private无法访问
在继承结构中,派生类虽然继承了基类的private成员但是无法直接访问
protected和private区别?在基类中定义的成员,想被派生类访问但是不想被外部访问,将该成员定义为protected;若不打算让外部和派生类访问则定义为private。
派生类不能继承基类的构造析构函数,派生类怎么初始化从基类继承来的成员变量?
调用基类相应的构造函数,派生类的构造析构函数负责派生类的部分,从基类继承的成员由基类的构造析构负责
重载
作用域相同,函数名相同,参数不同,:派生类和基类的同名函数不属于重载因为他们的作用域不同
隐藏
作用域的隐藏派生类的函数名与基类相同,调用时默认使用派生类的函数,若想使用基类的函数加上作用域 Base::show()
基类对象 接收一个派生类对象的赋值 类型从下到上 Y 小的指向大的
派生类对象 接收一个基类对象的赋值 类型从上到下 N 大的指向小的
基类指针指向派生类对象 只能访问派生类对象中继承基类的部分
虚函数、静态绑定和动态绑定
静态绑定:编译时就确定了
虚函数
如果类中定义了虚函数,则编译阶段会给这个类的类型产生一个唯一的vftable虚函数表,虚函数表中存储的主要内容是RTTI指针和虚函数的地址。(RTTI)运行时类型信息。当程序运行时,每一张虚函数表都会加载到内存的.rodata区
一个类里面如果定义了虚函数,那么这个类定义的对象在其运行时,内存中开始的部分会多存储一个vfptr虚函数指针,指向该类型的虚函数表vftable。这个类定义的所有对象都指向同一张虚函数表。
一个类里面虚函数的个数不影响对象的大小,因为虚函数地址存在虚函数表中,对象中只存了虚函数表的地址,只会改变虚函数表的大小。
覆盖
如果派生类中的方法和基类继承的某个方法,返回值、函数名、参数列表都相同,并且基类的方法加上了virtual虚函数,那么派生类的这个方法也是虚函数,会重写虚函数表中虚函数 重写《》覆盖。
动态绑定
如果发现对象调用的函数是普通函数则进行静态绑定,如果发现该函数时虚函数则进行动态绑定
mov eax, dword ptr[pb] //将对象的前4个字节即虚函数表地址移入eax寄存器 mov ecx, dword ptr[eax] //eax寄存器中即虚函数表的前四个字节(虚函数地址)移入ecx寄存器 call ecx //运行时才知道ecx寄存器中存的是哪个函数的地址
用类型对应的对象调用虚函数不会发生动态绑定,依旧是静态绑定
Base b; Derive d; b.show() //静态绑定 d.show() //静态绑定 //以下都是动态绑定->指针调用虚函数 Base *pb1 = &b; pb1->show(); Base *pb2 = &d; pb2->show();
哪些函数不能实现成虚函数?
虚函数依赖:
1.虚函数能产生地址,存储在vftable中
2.对象必须存在(vfptr->vftable->虚函数地址)
构造函数1.virtual+构造函数 NO! 2.构造函数中调用的任何函数都是静态绑定
static 静态成员方法 NO! 不依赖对象
虚析构函数
class Base{ public: Base (int data) :ma (data) { cout <<Base()<<endl; } //虚析构函数 virtual ~Base() { cout<<"~Base ( ) " <<endl; virtual void show () {cout << "call Base: : show ( ) " <<endl; } protected: int ma; }; // &Base: :~Base class Derive : public Base{ public: Derive (int data) : Base (data) , mb (data) , ptr (new int (data) ) { cout<< "Derive ( ) " <<endl; } ~Derive () { delete ptr; } private : int mb ; int *ptr; }; int main(){ Base* pb = new Derive(10); delete pb; //派生类的析构函数没被调用! }
基类的虚构函数是虚函数则派生类的析构函数自动是虚函数
什么时候基类的析构函数必须实现成虚函数?
基类的指针指向堆上new出来的派生类对象的时候, delete pb(基类的指针),它调用析构函数的时候,必须动态绑定,否则无法调用派生类的析构函数
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)