方法调用机制、多态的原理

方法调用

        一起方法在Class文件中存储的只是符号引用,而并不是直接引用。在类的加载的解析阶段只会让其中的一部分符号引用转为直接引用,为什么会出现这种差异呢?原因是在程序运行之前,有很多种因素使得我们不能确定哪些方法应该被正确调用。在运行时就能确定的且这个方法在运行期不可变的就可以立即转为直接引用。

首先看如下一个类

public class TestClass extends Object {
    public TestClass() {}//构造方法
    public static void staticMethod(){};//静态方法
    public final void finalMethod(){}; //final方法
    private void privateMethod(){}; //私有方法
    public void method(){};//普通方法

    public static void main(String[] args) {
       
        TestClass test = new TestClass();
        TestClass.staticMethod();
        test.finalMethod();
        test.privateMethod();
        test.method();
        test.toString();//执行父类Object中的方法
        //类型为接口
        Runnable runnable=new Runnable() {
            @Override
            public void run() {}
        };
        runnable.run();//执行接口方法,多态

    }
}

反编译后,查看它的字节码指令:

 其中的调用方法的指令可分为:

  • invokespecial:调用构造方法私有方法
  • invokestatic:调用静态方法
  • invokevirtual:调用虚方法
  • invokeinterface:接口方法
  • invokedynamic:用于动态方法

        其中invokespecial和invokestatic有个共同特点就是他们调用的方法就是我们前面说的在编译器就已经确定谁是哪个对象调用的此方法,例如如果是public的普通方法,很有可能被子类重写,然后子类采用多态的方式赋值为父类型,编译阶段jvm并不能确定到底是调用子类或是父类的该名称的方法,但是像一些构造方法,和私有方法,静态方法,final修饰的方法都不能被重写就不会发生这种情况,这些方法在编译阶段就能完全的确定下来调用的版本,因此可以在解析阶段就转为直接引用了。

final比较特殊,它属于invokevirtual,但是它不能被重写,它包括在非虚方法里面

        这种能在编译器阶段就转为直接引用的被称为非虚方法,其他的叫非虚方法。

        根据两种方法调用的类别,可分为解析调用和分派调用,解析调用就是执行非虚方法,它在编译器把涉及到的符号全部转为明确的直接引用,不必延迟到运行阶段;分派调用用于在运行阶段执行虚方法。

分派调用

1.静态分派

        先看如下一段代码:采用方法的重载机制。

abstract class Human {
}
class Man extends Human {
}
class Woman extends Human {
}
public class Test{
    public static void who(Human hunam){
        System.out.println("human");
    }
    public static void who(Man hunam){
        System.out.println("man");
    }
    public static void who(Woman woman){
        System.out.println("human");
    }
    public static void main(String[] args) {
        Human man = new Man();
        Human woman = new Woman();
        who(man);//human
    }
}

 可能你已经知道答案了,但是为什么是这样呢?请继续看

Human被称为变量的静态类型,后面的woman和man被称为实际类型,其中静态类型是在编译器可知的,实际类型要等到运行时才能确定

首先调用方法时,在编译期肯定是根据静态类型来匹配的,所以重载方法时是通过静态类型而不是实际类型作为判断依据的,javac编译器根据变量的静态类型发现能够匹配参数为Human的方法,并把这个方法的符号引用写到main()方法里的两条invokevirtual指令的参数中。

这种依赖静态类型来决定之行版本的动作称为静态分派

2.动态分派

        再来看一段代码,属于是方法的重写机制:

abstract class Animal {
    public abstract void eat();
}
class Dog extends Animal{
    @Override
    public void eat() { System.out.println("吃骨头");
    }
}
class Cat extends Animal{
    @Override
    public void eat() {System.out.println("吃鱼");
    }
}
public class Test{
    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal cat = new Cat();
        dog.eat();//吃骨头
        cat.eat();//吃鱼
    }
}

此时我们调用方法的类型不可再根据静态类型来确定,只能根据实际类型来判断到底是执行哪个方法的版本。我们从它的反编译的指令里面需找答案:

 关键的是这个invokevirtual方法,该指令的运行解析过程是如下几个步骤:

  1. 找到栈顶的第一个元素所指向的对象的实际类型,如cat、dog等
  2. 再看看实际类型中是否有和要调用的虚方法相符的方法,有的话就调用(还需权限验证才能调用)
  3. 否则的话从下往上对该实际类型的各个父类继续进行搜素,验证
  4. 没有找到的话就抛出AbstractMehodMethodError异常

invokevirtual第一步就是根据实际类型来选择方法的版本,这个过程就是方法重写的本质,我们把这种在运行期根据实际类型来确定方法版本的分派称为动态分派。invokevirtual是关键。

字段是不参与多态的,字段只跟静态类型有关!

         动态分派选择方法的调用版本是在运行时,根据接收者的实际类型在它的元空间搜索,但是基于性能考虑,避免频繁且反复的搜索元数据,java建立了一个虚方法表(vtable)来优化,与之对应的invokeinterface也有接口方法表(itable),用方法表来代替消耗更大的元数据查找。

class Father {
    public void eat(){
        System.out.println("father吃东西");
    }
    public void sleep(){
        System.out.println("睡觉");
    }
}
class Son extends Father {
    @Override
    public void eat() {
        System.out.println("son吃东西");
    }
}

 如上的两个类的方法表下图,方法表中存放着各个方法的实际入口地址,如果子类没有重写父类的方法,那么子类的方法表中该方法就指向的是父类的实现入口,如果重写了,就会指向子类中重写的方法的入口。

 方法表一般在类加载的连接阶段进行初始化。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
中文名: 编译原理 作者: 陈意云 张昱 资源格式: PDF 版本: 文字版 出版社: 高等教育出版社书号: 9787040133677发行时间: 2003年09月 地区: 大陆 语言: 简体中文 简介: 内容简介: 本书介绍编译器构造的一般原理和基本实现方法,主要内容包括词法分析、语法分析、语义分析、中间代码生成、代码优化和目标代码生成等。除了介绍命令式编程语言的编译技术外, 本书还介绍面向对象语言和函数式编程语言的实现技术。本书还强调一些相关的理论知识, 如形式语言和自动机理论、语法制导的定义和属性文法、类型论和类型系统等。 本书取材广泛新颖、图文并茂,注意理论联系实际。本书可作为高等学校计算机科学及相关专业的教材,也可供计算机软件工程技术人员参考使用。 目录: 第1章 编译器概述 1.1 词法分析 1.2 语法分析 1.3 语义分析 1.4 中间代码生成 1.5 代码优化 1.6 代码生成 1.7 符号表管理 1.8 错误诊断和报告 1.9 阶段的分组 习题1 第2章 词法分析 2.1 词法记号及属性 2.1.1 词法记号、模式、词法单元 2.1.2 词法记号的属性 2.1.3 词法错误 2.2 词法记号的描述与识别 2.2.1 串和语言 2.2.2 正规式 2.2.3 正规定义 2.2.4 状态转换图 2.3 有限自动机 2.3.1 不确定的有限自动机 2.3.2 确定的有限自动机 2.3.3 NFA到DFA的变换 2.3.4 DFA的化简 2.4 从正规式到有限自动机 2.5 词法分析器的生成器 习题2 第3章 语法分析 3.1 上下文无关文法 3.1.1 上下文无关文法的定义 3.1.2 推导 3.1.3 分析树 3.1.4 二义性 3.2 语言和文法 3.2.1 正规式和上下文无关文法的比较 3.2.2 分离词法分析器的理由 3.2.3 验证文法产生的语言 3.2.4 适当的表达式文法 3.2.5 消除二义性 3.2.6 消除左递归 3.2.7 提左因子 3.2.8 非上下文无关的语言结构 3.2.9 形式语言鸟瞰 3.3 自上而下分析 3.3.1 自上而下分析的一般方法 3.3.2 LL(1)文法 3.3.3 递归下降的预测分析 3.3.4 非递归的预测分析 3.3.5 构造预测分析表 3.3.6 预测分析的错误恢复 3.4 自下而上分析 3.4.1 归约 3.4.2 句柄 3.4.3 用栈实现移进一归约分析 3.4.4 移进一归约分析的冲突 3.5 LR分析器 3.5.1 LR分析算法 3.5.2 LR文法和LR分析方法的特点 3.5.3 构造sLR分析表 3.5.4 构造规范的LR分析表 3.5.5 构造LALR分析表 3.5.6 非LR的上下文无关结构 3.6 二义文法的应用 3.6.1 使用文法以外的信息来解决分析动作的冲突 3.6.2 特殊情况产生式引起的二义性 3.6.3 IR分析的错误恢复 3.7 分析器的生成器 3.7.1 分析器的生成器Yacc 3.7.2 用Yaec处理二义文法 3.7.3 Yaec的错误恢复 习题3 第4章 语法制导的翻译 4.1 语法制导的定义 4.1.1 语法制导定义的形式 4.1.2 综合属性 4.1.3 继承属性 4.1.4 属性依赖图 4.1.5 属性计算次序 4.2 s属性定义的自下而上计算 4.2.1 语法树 4.2.2 构造语法树的语法制导定义 4.2.3 S属性的自下而上计算 4.3 L属性定义的自上而下计算 4.3.1 L属性定义 4.3.2 翻译方案 4.3.3 预测翻译器的设计 4.3.4 用综合属性代替继承属性 4.4 L属性的自下而上计算 4.4.1 删除翻译方案中嵌入的动作 4.4.2 分析栈上的继承属性 4.4.3 模拟继承属性的计算 4.5 递归计算 4.5.1 自左向右遍历 4.5.2 其他遍历方法 4.5.3 多次遍历 习题4 第5章 类型检查 5.1 类型在程序设计语言中的作用 5.1.1 引言 5.1.2 执行错误和安全语言 5.1.3 类型化语言的优点 5.2 描述类型系统的语言 5.2.1 定型断言 5.2.2 定型规则 5.2.3 类型检查和类型推断 5.3 简单类型检查器的说明 5.3.1 一个简单的语言 5.3.2 类型系统 5.3.3 类型检查 5.3.4 类型转换 5.4 多态函数 5.4.1 为什么要使用多态函数 5.4.2 类型变量 5.4.3 一个含多态函数的语言 5.4.4 代换、实例和合 5.4.5 多态函数的类型检查 5.5 类型表达式的等价 5.5.1 类型表达式的结构等价 5.5.2 类型表达式的名字等价 5.5.3 记录类型 5.5.4 类型表示中的环 5.
第1章 编译器概述 第2章 词法分析 2.1 词法记号及属性 2.1.1 词法记号、模式、词法单元 2.1.2 词法记号的属性 2.1.3 词法错误 2.2 词法记号的描述与识别 2.2.1 串和语言 2.2.2 正规式 2.2.3 正规定义 2.2.4 状态转换图 2.3 有限自动机 2.3.1 不确定的有限自动机 2.3.2 确定的有限自动机 2.3.3 NFA到DFA的变换 2.3.4 DFA的化简 2.4 从正规式到有限自动机 2.5 词法分析器的生成器 第3章 语法分析 3.1 上下文无关文法 3.1.1上下文无关文法的定义 3.1.2 推导 3.1.3 分析树 3.1.4 二义性 3.2 语言和文法 3.2.1 正规式和上下文无关文法的比较 3.2.2分离词法分析器的理由 3.2.3 验证文法产生的语言 3.2.4 适当的表达式文法 3.2.5 消除二义性 3.2.6 消除左递归 3.2.7 提左因子 3.2.8 非上下文无关的语言结构 3.2.9 形式语言鸟瞰 3.3 自上而下分析 3.3.1 自上而下分析的一般方法 3.3.2 LL(1)文法 3.3.3 递归下降的预测分析 3.3.4 非递归的预测分析 3.3.5 构造预测分析表 3.3.6 预测分析的错误恢复 3.4 自下而上分析 3.4.1 归约 3.4.2 句柄 3.4.3 用栈实现移进归约分析 3.4.4 移进归约分析的冲突 3.5 LR分析器 3.5.1 LR分析算法 3.5.2 LR文法和LR分析方法的特点 3.5.3 构造SLR分析表 3.5.4 构造规范的LR分析表 3.5.5 构造LALR分析表 3.5.6 非LR的上下文无关结构 3.6 二义文法的应用 3.6.1 使用文法以外的信息来解决分析动作的冲突 3.6.2特殊情况产生式引起的二义性 3.6.3 LR分析的错误恢复 3.7 分析器的生成器 3.7.1 分析器的生成器Yacc 3.7.2 用Yacc处理二义文法 3.7.3 Yacc的错误恢复 第4章 语法制导的翻译 4.1 语法制导的定义 4.1.1 语法制导定义的形式 4.1.2 综合属性 4.1.3 继承属性 4.1.4 属性依赖图 4.1.5 属性计算次序 4.2 S属性定义的自下而上计算 4.2.1 语法树 4.2.2 构造语法树的语法制导定义 4.2.3 S属性的自下而上计算 4.3 L属性定义的自上而下计算 4.3.1 L属性定义 4.3.2 翻译方案 4.3.3 预测翻译器的设计 4.3.4 用综合属性代替继承属性 4.4 L属性的自下而上计算 4.4.1 删除翻译方案中嵌入的动作 4.4.2 分析栈上的继承属性 4.4.3 模拟继承属性的计算 4.5 递归计算 4.5.1 自左向右遍历 4.5.2 其他遍历方法 4.5.3 多次遍历 第5章 类型检查 5.1 类型在程序设计语言中的作用 5.1.1 引言 5.1.2 执行错误和安全语言 5.1.3 类型化语言的优点 5.2 描述类型系统的语言 5.2.1 定型断言 5.2.2 定型规则 5.2.3 类型检查和类型推断 5.3 简单类型检查器的说明 5.3.1 一个简单的语言 5.3.2 类型系统 5.3.3 类型检查 5.3.4 类型转换 *5.4 多态函数 5.4.1 为什么要使用多态函数 5.4.2 类型变量 5.4.3 一个含多态函数的语言 5.4.4 代换、实例和合一 5.4.5 多态函数的类型检查 5.5 类型表达式的等价 5.5.1 类型表达式的结构等价 5.5.2 类型表达式的名字等价 5.5.3 记录类型 5.5.4 类型表示中的环 5.6 函数和算符的重载 5.6.1 子表达式的可能类型集合 5.6.2 缩小可能类型的集合 第6章 运行时存储空间的组织和管理 6.1 局部存储分配策略 6.1.1 过程 6.1.2 名字的作用域和绑定 6.1.3 活动记录 6.1.4 局部数据的安排 6.1.5 程序块 6.2 全局存储分配策略 6.2.1 运行时内存的划分 6.2.2 静态分配 6.2.3 栈式分配 6.2.4 堆式分配 6.3 非局部名字的访问 6.3.1 无过程嵌套的静态作用域 6.3.2 有过程嵌套的静态作用域 6.3.3 动态作用域 6.4 参数传递 6.4.1值调用 6.4.2 引用调用 6.4.3 复写-恢复调用 6.4.4 换名调用 第7章 中间代码生成 7.1 中间语言 7.1.1 后缀表示 7.1.2 图形表示 7.1.3 三地址代码 7.2 声明语句 7.2.1 过程中的声明 7.2.2 作用域信息的保存 7.2.3 记录的域名 7.3 赋值语句 7.3.1 符号表中的名字 7.3.2 临时名字的重新使用 7.3.3 数组元素的地址计算 7.3.4 数组元素地址计算的翻译方案 7.3.5 类型转换 7.4 布尔表达式和控制流语句 7.4.1 布尔表达式的翻译 7.4.2 控制流语句的翻译 7.4.3 布尔表达式的控制流翻译 7.4.4 开关语句的翻译 7.4.5 过程调用的翻译 第8章 代码生成 8.1 代码生成器设计中的问题 8.1.1 目标程序 8.1.2 指令选择 8.1.3 寄存器分配 8.1.4 计算次序选择 8.2 目标机器 8.2.1 目标机器的指令系统 8.2.2 指令的代价 8.3 基本块和流图 8.3.1 基本块 8.3.2 基本块的变换 8.3.3 流图 8.3.4 下次引用信息 8.4 一个简单的代码生成器 8.4.1 寄存器描述和地址描述 8.4.2 代码生成算法 8.4.3 寄存器选择函数 8.4.4 为变址和指针语句产生代码 8.4.5 条件语句 *第9章 代码优化 9.1 优化的主要种类 9.1.1 代码改进变换的标准 9.1.2 公共子表达式删除 9.1.3 复写传播 9.1.4 死代码删除 9.1.5 代码外提 9.1.6 强度削弱和归纳变量删除 9.1.7 优化编译器的组织 9.2 流图中的循环 9.2.1 必经结点 9.2.2 自然循环 9.2.3 前置结点 9.2.4 可归约流图 9.3 全局数据流分析介绍 9.3.1 点和路径 9.3.2 到达-定值 9.3.3 可用表达式 9.3.4 活跃变量分析 9.4 代码改进变换 9.4.1公共子表达式删除 9.4.2复写传播 9.4.3 寻找循环不变计算 9.4.4 代码外提 9.4.5 归纳变量删除 第10章 编译系统和运行系统 10.1 C语言的编译系统 10.1.1 预处理器 10.1.2 汇编器 10.1.3 连接器 10.1.4 目标文件的格式 10.1.5 符号解析 10.1.6 静态库 10.1.7 可执行目标文件及装入 10.1.8 动态连接 10.1.9 处理目标文件的一些工具 10.2 Java语言的运行系统 10.2.1 Java虚拟机语言简介 10.2.2 Java虚拟机 10.2.3即时编译器 *10.3 无用单元收集 10.3.1 标记和清扫 10.3.2 引用计数 10.3.3 拷贝收集 10.3.4 分代收集 10.3.5 渐增式收集 10.3.6 编译器与收集器之间的相互影响 *第11章 面向对象语言的编译 11.1 面向对象语言的概念 11.1.1 对象和对象类 11.1.2 继承 11.1.3 信息封装 11.2 方法的编译 11.3 继承的编译方案 11.3.1 单一继承的编译方案 11.3.2 重复继承的编译方案 *第12章 函数式语言的编译 12.1 函数式程序设计语言简介 12.1.1 语言构造 12.1.2 参数传递机制 12.1.3 变量的自由出现和约束出现 12.2 函数式语言的编译简介 12.2.1 几个受启发的例子 12.2.2 编译函数 12.2.3 环境与约束 12.3 抽象机的系统结构 12.3.1 抽象机的栈 12.3.2 抽象机的堆 12.3.3 名字的寻址 12.3.4 约束的建立 12.4 指令集和编译 12.4.1 表达式 12.4.2 变量的引用性出现 12.4.3 函数定义 12.4.4 函数应用 12.4.5 构造和计算闭包 12.4.6 letrec表达式和局部变量
目录 1、 C++对C的扩展 1 1简单的C++程序 1 1.1求圆的周长和面积 1 1.2初学者易犯错误模型 3 2程序设计方法的发展历程 4 3 C语言和C++语言关系 6 4 C++对C的加强 6 4.1 namespace命名空间 6 4.2 “实用性”增加 6 4.3 register关键字增强 6 4.4变量检测增强 6 4.5 struct类型加强 6 4.6 C++中所有的变量和函数都必须有类型 6 4.7新增Bool类型关键字 6 4.8三目运算符功能增强 6 5 C/C++中的const 6 1 const基础知识(用法、含义、好处) 6 2 C中“冒牌货” 6 3 const和#define相同之处 6 4 const和#define的区别 6 5 结论 6 6引用专题讲座 6 1引用(普通引用) 6 2常引用 6 3 const引用结论 6 4const修饰类 6 5综合练习 6 7C++对C的函数扩展 6 1 inline内联函数 6 2 默认参数 6 3 函数占位参数 6 4 默认参数和占位参数 6 5 函数重载(Overroad) 6 8附录 6 附录1:C++语言对C语言扩充和增强的几点具体体现 6 附录2:C语言register关键字—最快的关键字 6 一、皇帝身边的小太监----寄存器 6 2、类和对象 6 1前言 6 2类和对象 6 2.1 基本概念 6 2.2类的封装 6 2.3 C++面向对象程序设计举例 6 2.4 作业 6 3对象的构造和析构 6 3.1构造和析构函数 6 3.2构造函数的分类及调用 6 3.3构造函数调用规则研究 6 3.4深拷贝和浅拷贝 6 3.5多个对象构造和析构 6 3.6构造函数和析构函数的调用顺序研究 6 3.7构造函数和析构函数综合练习 6 3.8 对象的动态建立和释放 6 4静态成员变量成员函数 6 4.1静态成员变量 6 4.2静态成员函数 6 4.3综合训练 6 5 C++面向对象模型初探 6 5.1基础知识 6 5.2编译器对属性和方法的处理机制 6 5.3总结 6 5.4 this指针 6 5.5全局函数PK成员函数 6 6 6友元 6 6.1友元函数 6 6.2友元类 6 7强化训练 6 1 static关键字强化训练题 6 2 数组类封装 6 3小结 6 8运算符重载 6 8.1概念 6 8.2运算符重载的限制 6 8.3运算符重载编程基础 6 8.4运算符重载提高 6 8.5运算符重载在项目开发中的应用 6 8.7附录:运算符和结合性 6 2、 继承和派生 6 3.1继承概念 6 3.1.1类之间的关系 6 3.1.2继承关系举例 6 3.1.3 继承相关概念 6 3.1.4 派生类的定义 6 3.1.5 继承重要说明 6 3.2派生类的访问控制 6 3.2.1单个类的访问控制 6 3.2.2不同的继承方式会改变继承成员的访问属性 6 3.2.3“三看”原则 6 3.2.3派生类类成员访问级别设置的原则 6 3.2.4综合训练 6 3.3继承中的构造和析构 6 3.3.1类型兼容性原则 6 3.3.2继承中的对象模型 6 3.3.3继承中的构造析构调用原则 6 3.3.4继承与组合混搭情况下,构造和析构调用原则 6 3.3.5继承中的同名成员变量处理方法 6 3.3.6派生类中的static关键字 6 3.4多继承 6 3.4.1多继承的应用 6 3.4.2虚继承 6 3.5继承总结 6 4、多态 6 4.1多态 6 4.1.1问题引出 6 4.1.2面向对象新需求 6 4.1.3解决方案 6 4.1.4多态实例 6 4.1.5多态工程意义 6 4.1.6多态成立的条件 6 4.1.7多态的理论基础 6 4.2多态相关面试题 6 面试题1:请谈谈你对多态的理解 6 面试题2:谈谈C++编译器是如何实现多态 6 面试题3:谈谈你对重写,重载理解 6 #include <cstdlib> 6 #include <iostream> 6 using namespace std; 6 class Parent01 6 { 6 public: 6 Parent01() 6 { 6 cout<<"Parent01:printf()..do"<<endl; 6 } 6 public: 6 virtual void func() 6 { 6 cout<<"Parent01:void func()"<<endl; 6 } 6 virtual void func(int i) 6 { 6 cout<<"Parent:void func(int i)"<<endl; 6 } 6 virtual void func(int i, int j) 6 { 6 cout<<"Parent:void func(int i, int j)"<<endl; 6 } 6 }; 6 class Child01 : public Parent01 6 { 6 public: 6 //此处2个参数,和子类func函数是什么关系 6 void func(int i, int j) 6 { 6 cout<<"Child:void func(int i, int j)"<<" "<<i + j<<endl; 6 } 6 //此处3个参数的,和子类func函数是什么关系 6 void func(int i, int j, int k) 6 { 6 cout<<"Child:void func(int i, int j, int k)"<<" "<<i + j + k<<endl; 6 } 6 }; 6 void run01(Parent01* p) 6 { 6 p->func(1, 2); 6 } 6 int main() 6 { 6 Parent01 p; 6 p.func(); 6 p.func(1); 6 p.func(1, 2); 6 Child01 c; 6 //c.func(); //问题1 6 c.Parent01::func(); 6 c.func(1, 2); 6 run01(&p); 6 run01(&c); 6 system("pause"); 6 return 0; 6 } 6 //问题1:child对象继承父类对象的func,请问这句话能运行吗?why 6 //c.func(); //因为名称覆盖,C++编译器不会去父类中寻找0个参数的func函数,只会在子类中找func函数。 6 //1子类里面的func无法重载父类里面的func 6 //2当父类和子类有相同的函数名、变量名出现,发生名称覆盖(子类的函数名,覆盖了父类的函数名。) 6 //3//c.Parent::func(); 6 //问题2 子类的两个func和父类里的三个func函数是什么关系? 6 面试题4:是否可类的每个成员函数都声明为虚函数,为什么。 c++编译器多态实现原理 6 面试题5:构造函数中调用虚函数能实现多态吗?为什么? c++编译器多态实现原理 6 面试题6:虚函数表指针(VPTR)被编译器初始化的过程,你是如何理解的? 6 面试题7:父类的构造函数中调用虚函数,能发生多态吗? c++编译器多态实现原理 6 面试题8:为什么要定义虚析构函数? 6 其他 6 4.3多态原理探究 6 4.3.1 多态的实现原理 6 4.3.2如何证明vptr指针的存在 6 4.3.3构造函数中能调用虚函数,实现多态吗 6 5、纯虚函数和抽象类 6 5.1基本概念 6 5.2抽象类案例 6 5.3抽象类在多继承中的应用 6 5.3.1有关多继承的说明 6 5.3.2多继承的应用场景 6 5.4抽象类知识点强化 6 5.5面向抽象类编程思想强化 6 5.4.1案例:socket库c++模型设计和实现 6 5.4.2案例:计算员工工资 6 5.4.3案例:计算几何体的表面积和体积 6 5.6 C面向接口编程和C多态 6 5.6.1函数类型语法基础 6 5.6.2函数指针做函数参数 6 5.6.3函数指针正向调用 6 5.6.4函数指针反向调用 6 5.6.5.C动态库升级成框架案例 6 5.6.6附录:诸葛亮的锦囊妙计 6

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值