C++多态的原因

多态性可以简单的概括为“1个接口,多种方法”,在程序运行的过程中才决定调用的机制C++编译器在编译的时候,要确定每个对象调用的函数的地址,这称为早期绑定(early binding), 程序实现上是这样,通过父类指针调用子类的函数,可以让父类指针有多种形态。而要让编译器采用迟绑定,就要在基类中声明函数时使用virtual关键字,这样的函数我们称为虚函数。一旦某个函数在基类中声明为virtual,那么在所有的派生类中该函数都是virtual,而不需要再显式地声明为virtual。

正是由于每个对象调用的虚函数都是通过虚表指针来索引的,也就决定了虚表指针的正确初始化是非常重要的。换句话说,在虚表指针没有正确初始化之前,我们不能够去调用虚函数。那么虚表指针在什么时候,或者说在什么地方初始化呢?
答案是在构造函数中进行虚表的创建和虚表指针的初始化。构造函数的调用顺序,在构造子类对象时,要先调用父类的构造函数,此时编译器只“看到了”父类,并不知道后面是否后还有继承者,它初始化父类对象的虚表指针,该虚表指针指向父类的虚表。当执行子类的构造函数时,子类对象的虚表指针被初始化,指向自身的虚表。

C++的多态性用一句话概括就是:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时将会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数。

时间: 2024-10-18 23:42:00

C++多态的原因的相关文章

浅谈为什么只有指针能够完成多态及动态转型的一个误区

c++多态由一个函数地址数组Vtable和一个指向Vtable的指针vptr实现. 具体来说,类拥有自己的vtable,类的vtable在编译时刻完成. 每个对象有自己的vptr指针,该指针初始化时指向对象所实现的类的vtable. 关于向上转型的误区: 通常对于向上转型的理解是这样的,当子类对象向上转型(允许隐式)成父类对象时,实际上只是将子类对象暂时看做父类对象,内部的数据并未改变. 对于没有虚函数的对象,这句话是正确的,但是,当引入虚函数后,这样的理解是有问题的,实际上,向上转型的过程中,

java之多态(Polymorphic)、动态绑定(Dynamic Binding)、迟绑定(Late Binding)

今天,我们来说说java面向对象最核心的东西,多态.通过多态可以使我们的程序可复用性达到极致,这就是我们为什么要学多态的原因. “多态”(Polymorphic)也叫“动态绑定”(Dynamic Binding)同时也叫“迟绑定”(Late Binding). 动态绑定是指“在执行期间(而非编译期间)判断所引用对象的实际类型,根据其实际类型调用其相应的方法.” 程序代码: public class TestPolymorphic{ public static void main(String a

java面向对象基础

思想 面向过程:是分析出解决问题所需的步骤,从上往下步步求精,自顶向下的编程,最重要的是模块化思想,考虑实际的实现 优点:性能高 面向对象:以事物为中心,将事物高度抽象为对象,对象包括属性与行为. 优点:易重用.易扩展.易维护.适合大型项目 联系与区别 联系:面向对象也含有面向过程的思想 区别:面向过程是一件事"该怎么做",面向对象是一件事"该让谁来做" 举例 汽车发动  汽车到站 面向过程  汽车发动与汽车到站分别为两个事件,形成两个函数,依次调用 面向对象  关

C++构造函数虚函数例题

虚函数: #include <iostream> class A { public: A ():m_iVal(0) { test(); } virtual void func() { std::cout<<m_iVal<<' '; } void test() { func(); } public: int m_iVal; }; class B : public A { public: B() { test(); }; virtual void func() { ++m_

Exception-异常

异常(Exception)是程序执行过程中所产生的问题 产生原因:用户输入无效数字.找不到需要打开的文件.在通讯中网络连接中断.JVM发生了内存溢出 异常的三个种类:检查异常.运行时异常.错误(类似异常.无法控制) 异常(Exception)处理:捕获异常不让它沿着调用栈继续向下抛出. 捕获并继续向下抛出. 不捕获导致方法从调用栈中弹出异常对象继续抛给调用栈的main()方法. Throwable 类是 Java 语言中所有错误(Error)或异常(Exception)的超类(这就是一切皆可抛的

android 的消息处理

算是工作记录吧... 首先,android中界面的更新都必须放到主线程中间去做,当我们在子线程中想要更新界面的时候,可以通过Handler和Message这两个类来进行处理.比如新开了一个线程,用来进行下载任务,通过Handler显示进度条等.大概的过程是这样的,首先获得一个message ,然后调用sendMessage发送出去,然后就可以在重写的handler类的函数里面进行处理了. new Thread() { public void run() { ... Message msg = M

MFC框架

第一点:类别型录网的搭建: 类别型录网搭建的目的是为了实现所谓的"执行期类型识别",也就是在程序运行的时候识别出某个对象是否是某个类的实例(基类也可以).这里还不是很明白为什么需要实现"执行期类型识别",这种技巧具体被应用在哪里. 例如在MFC中CView继承于CWnd,那么可以进行这样的判断: CView view; bool result = view.IsKindOf(CWnd); // result == true 如上,通过调用IsKindOf函数,可以判

PHP面向对象编程(imooc)代码合集(四)

class10 多态 多态简单说就是用不同的类去实现同一个接口的方法,以实现不同类自己的方法 <?php date_default_timezone_set("PRC"); /** * 多态 * 1. 只要某个对象实现了接口(instanceof),就可以直接在对象上调用接口的方法 */ interface ICanEat { public function eat($food); } // Human类实现了ICanEat接口 class Human implements IC

025医疗项目-模块二:药品目录的导入导出-HSSF导入类的封装

上一篇文章提过,HSSF的用户模式会导致读取海量数据时很慢,所以我们采用的是事件驱动模式.这个模式类似于xml的sax解析.需要实现一个接口,HSSFListener接口. 原理:根据excel底层存储(07以版本采用xml存储,以下版本采用二进制)标签决定事件出发点. 目标:在解析完一行(row)数据时进行触发. 优点:读取大数据时,不会导致内存溢出 缺点:用户在解析数据时比较困难.读取数据时速度不快的,因为读取数据的同时根据每个标签进行事件触发. HSSF事件驱动读取文件的封装类解析. 主要