【C++】多态 ⑨ ( vptr 指针初始化问题 | 构造函数 中 调用 虚函数 - 没有多态效果 )

本文主要是介绍【C++】多态 ⑨ ( vptr 指针初始化问题 | 构造函数 中 调用 虚函数 - 没有多态效果 ),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 一、vptr 指针初始化问题
    • 1、vptr 指针与虚函数表
    • 2、vptr 指针初始化时机
    • 3、构造函数 中 调用 虚函数 - 没有多态效果
    • 4、代码示例


构造函数 的 作用就是 创建对象 , 构造函数 最后 一行代码 执行完成 , 才意味着 对象构建完成 , 对象构建完成后 , 才会将 vptr 指针 指向 虚函数表 ;

如果在 构造函数 中 调用 虚函数 , 则 没有 多态效果 ;





一、vptr 指针初始化问题




1、vptr 指针与虚函数表


" 虚函数表 " 由 C++ 编译器 负责 创建 与 维护 , 被 virtual 关键字 修饰的 虚函数 , 会自动 被 C++ 编译器 存储到 " 虚函数表 " 中 , 类中会自动添加一个 " vptr 指针 " 成员变量 指向 虚函数表 ;


2、vptr 指针初始化时机


对象中的 vptr 指针 指向 虚函数表 ,

在 对象 被 创建时 , 由 C++ 编译器 对 对象中的 vptr 指针进行初始化操作 ,

对象 创建完成 后 , 也就是 虚函数 整理完毕 , 全部放到 虚函数表 中后 ,

vptr 指针 才会指向 虚函数表 的首地址 ;


父类 对象 的 vptr 指针 指向 父类 的 虚函数表 首地址 ;

子类 对象 的 vptr 指针 指向 子类 的 虚函数表 首地址 ;


3、构造函数 中 调用 虚函数 - 没有多态效果


构造函数 的 作用就是 创建对象 ,

构造函数 最后 一行代码 执行完成 , 才意味着 对象构建完成 ,

对象构建完成后 , 才会将 vptr 指针 指向 虚函数表 ;


如果在 构造函数 中 调用 虚函数 , 则 没有 多态效果 ;

在 父类 的 构造函数中 , 调用了 父类的 虚函数 ;

此时 , 如果 创建 子类对象 , 执行 父类构造函数 , 仍然调用 父类 的虚函数 , 子类的虚函数 没有被调用 , 说明 构造函数 执行期间 , 多态没有生效 ;


参考 【C++】继承 ⑧ ( 继承 + 组合 模式的类对象 构造函数 和 析构函数 调用规则 ) 博客中的 构造函数 调用规则 :

  • 构造函数 : 父类 -> 成员 -> 自身 ;
    • 首先 , 调用 父类 构造函数 ;
    • 然后 , 调用 成员 构造函数 ; 也就是 成员变量 类型的 构造函数 ;
    • 最后 , 调用 自己 构造函数 ; 自身定义的 构造函数 ;
  • 析构函数 : 自身 -> 成员 -> 父类 ;
    • 首先 , 调用 自己 析构函数 ; 自身定义的 析构函数 ;
    • 然后 , 调用 成员 析构函数 ; 也就是 成员变量 类型的 析构函数 ;
    • 最后 , 调用 父类 析构函数 ;

4、代码示例


执行 Child c; 代码 , 创建 子类对象 ;

构造函数调用顺序是 父类 -> 成员 -> 自身 ;

首先 , 调用 父类 的 构造函数 , 然后再 父类构造函数 中调用 fun 虚函数 , 只能调用 父类本身的 fun 函数 , 此时 vptr 指针没有指向 虚函数表 , 虚函数表未生效 , 只能调用 父类的 fun 函数本身 ;

  • 父类的 构造函数 调用完毕后 , vptr 指针 才指向 父类的 虚函数表 ;

然后 , 调用 子类 的构造函数 , 此时在 子类构造函数 中调用 fun 虚函数 , 只能调用 子类本身的 fun 函数 , 此时 vptr 指针没有指向 虚函数表 , 虚函数表未生效 , 只能调用 子类的 fun 函数本身 ;

  • 子类的 构造函数 调用完毕后 , vptr 指针 才指向 子类的 虚函数表 ;

代码示例 :

#include "iostream"
using namespace std;// 父类
class Parent {
public:Parent(){cout << "调用父类构造函数" << endl;// 构造函数中调用父类的虚函数// 如果创建子类 , 此处调用的仍是 父类的 虚函数fun(1);}virtual void fun(int a){cout << "执行 父类 Parent 的 virtual void fun(int a) 函数" << endl;}
};class Child : public Parent
{
public:Child(){cout << "调用子类构造函数" << endl;// 构造函数中调用子类的虚函数// 如果创建子类 , 此处调用的仍是 子类的 虚函数 // 多态未生效fun(1);}virtual void fun(int a){cout << "执行 子类 Child 的 virtual void fun(int a) 函数" << endl;}
};int main() {Child c;// 控制台暂停 , 按任意键继续向后执行system("pause");return 0;
}

执行结果 :

调用父类构造函数
执行 父类 Parent 的 virtual void fun(int a) 函数
调用子类构造函数
执行 子类 Child 的 virtual void fun(int a) 函数
请按任意键继续. . .

在这里插入图片描述

这篇关于【C++】多态 ⑨ ( vptr 指针初始化问题 | 构造函数 中 调用 虚函数 - 没有多态效果 )的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/321898

相关文章

Spring实现Bean的初始化和销毁的方式

《Spring实现Bean的初始化和销毁的方式》:本文主要介绍Spring实现Bean的初始化和销毁的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Bean的初始化二、Bean的销毁总结在前面的章节当中介绍完毕了ApplicationContext,也就

使用easy connect之后,maven无法使用,原来需要配置-Djava.net.preferIPv4Stack=true问题

《使用easyconnect之后,maven无法使用,原来需要配置-Djava.net.preferIPv4Stack=true问题》:本文主要介绍使用easyconnect之后,maven无法... 目录使用easGWowCy connect之后,maven无法使用,原来需要配置-DJava.net.pr

Kotlin运算符重载函数及作用场景

《Kotlin运算符重载函数及作用场景》在Kotlin里,运算符重载函数允许为自定义类型重新定义现有的运算符(如+-…)行为,从而让自定义类型能像内置类型那样使用运算符,本文给大家介绍Kotlin运算... 目录基本语法作用场景类对象数据类型接口注意事项在 Kotlin 里,运算符重载函数允许为自定义类型重

解决tomcat启动时报Junit相关错误java.lang.ClassNotFoundException: org.junit.Test问题

《解决tomcat启动时报Junit相关错误java.lang.ClassNotFoundException:org.junit.Test问题》:本文主要介绍解决tomcat启动时报Junit相... 目录tomcat启动时报Junit相关错误Java.lang.ClassNotFoundException

解决Maven项目报错:failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.13.0的问题

《解决Maven项目报错:failedtoexecutegoalorg.apache.maven.plugins:maven-compiler-plugin:3.13.0的问题》这篇文章主要介... 目录Maven项目报错:failed to execute goal org.apache.maven.pl

Java调用Python的四种方法小结

《Java调用Python的四种方法小结》在现代开发中,结合不同编程语言的优势往往能达到事半功倍的效果,本文将详细介绍四种在Java中调用Python的方法,并推荐一种最常用且实用的方法,希望对大家有... 目录一、在Java类中直接执行python语句二、在Java中直接调用Python脚本三、使用Run

Python如何调用指定路径的模块

《Python如何调用指定路径的模块》要在Python中调用指定路径的模块,可以使用sys.path.append,importlib.util.spec_from_file_location和exe... 目录一、sys.path.append() 方法1. 方法简介2. 使用示例3. 注意事项二、imp

Flutter实现文字镂空效果的详细步骤

《Flutter实现文字镂空效果的详细步骤》:本文主要介绍如何使用Flutter实现文字镂空效果,包括创建基础应用结构、实现自定义绘制器、构建UI界面以及实现颜色选择按钮等步骤,并详细解析了混合模... 目录引言实现原理开始实现步骤1:创建基础应用结构步骤2:创建主屏幕步骤3:实现自定义绘制器步骤4:构建U

MySQL主从同步延迟问题的全面解决方案

《MySQL主从同步延迟问题的全面解决方案》MySQL主从同步延迟是分布式数据库系统中的常见问题,会导致从库读取到过期数据,影响业务一致性,下面我将深入分析延迟原因并提供多层次的解决方案,需要的朋友可... 目录一、同步延迟原因深度分析1.1 主从复制原理回顾1.2 延迟产生的关键环节二、实时监控与诊断方案

SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法

《SQLyog中DELIMITER执行存储过程时出现前置缩进问题的解决方法》在SQLyog中执行存储过程时出现的前置缩进问题,实际上反映了SQLyog对SQL语句解析的一个特殊行为,本文给大家介绍了详... 目录问题根源正确写法示例永久解决方案为什么命令行不受影响?最佳实践建议问题根源SQLyog的语句分