【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

相关文章

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Vue3绑定props默认值问题

《Vue3绑定props默认值问题》使用Vue3的defineProps配合TypeScript的interface定义props类型,并通过withDefaults设置默认值,使组件能安全访问传入的... 目录前言步骤步骤1:使用 defineProps 定义 Props步骤2:设置默认值总结前言使用T

Web服务器-Nginx-高并发问题

《Web服务器-Nginx-高并发问题》Nginx通过事件驱动、I/O多路复用和异步非阻塞技术高效处理高并发,结合动静分离和限流策略,提升性能与稳定性... 目录前言一、架构1. 原生多进程架构2. 事件驱动模型3. IO多路复用4. 异步非阻塞 I/O5. Nginx高并发配置实战二、动静分离1. 职责2

解决升级JDK报错:module java.base does not“opens java.lang.reflect“to unnamed module问题

《解决升级JDK报错:modulejava.basedoesnot“opensjava.lang.reflect“tounnamedmodule问题》SpringBoot启动错误源于Jav... 目录问题描述原因分析解决方案总结问题描述启动sprintboot时报以下错误原因分析编程异js常是由Ja

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

深入解析C++ 中std::map内存管理

《深入解析C++中std::map内存管理》文章详解C++std::map内存管理,指出clear()仅删除元素可能不释放底层内存,建议用swap()与空map交换以彻底释放,针对指针类型需手动de... 目录1️、基本清空std::map2️、使用 swap 彻底释放内存3️、map 中存储指针类型的对象

Python Counter 函数使用案例

《PythonCounter函数使用案例》Counter是collections模块中的一个类,专门用于对可迭代对象中的元素进行计数,接下来通过本文给大家介绍PythonCounter函数使用案例... 目录一、Counter函数概述二、基本使用案例(一)列表元素计数(二)字符串字符计数(三)元组计数三、C

MySQL 表空却 ibd 文件过大的问题及解决方法

《MySQL表空却ibd文件过大的问题及解决方法》本文给大家介绍MySQL表空却ibd文件过大的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录一、问题背景:表空却 “吃满” 磁盘的怪事二、问题复现:一步步编程还原异常场景1. 准备测试源表与数据

解决Nginx启动报错Job for nginx.service failed because the control process exited with error code问题

《解决Nginx启动报错Jobfornginx.servicefailedbecausethecontrolprocessexitedwitherrorcode问题》Nginx启... 目录一、报错如下二、解决原因三、解决方式总结一、报错如下Job for nginx.service failed bec

SysMain服务可以关吗? 解决SysMain服务导致的高CPU使用率问题

《SysMain服务可以关吗?解决SysMain服务导致的高CPU使用率问题》SysMain服务是超级预读取,该服务会记录您打开应用程序的模式,并预先将它们加载到内存中以节省时间,但它可能占用大量... 在使用电脑的过程中,CPU使用率居高不下是许多用户都遇到过的问题,其中名为SysMain的服务往往是罪魁