c++虚函数与虚函数表原理
作者:考拉爱睡觉鸭~ 发布时间:2023-12-09 07:22:45
标签:c++,虚函数,虚函数表
1.什么是虚函数?
用virtual
修饰的成员函数叫虚函数
小知识: 没有虚构造函数 不写虚函数,没有默认的虚函数
普通函数不影响类的内存:
class MM
{
public:
void print()
{
cout << "普通函数"<< endl; //普通函数不影响类的内存<--->普通函数存在另一段内存中
}
protected:
};
void testVirtual()
{
//C语言不允许存在空的结构体
cout << sizeof(MM) << endl;/*(没有数据成员的)空的类或者结构体 占用1字节 用1字节标识当
前内存为结构体内存*/
}
int main()
{
testVirtual();
return 0;
}
/*输出*/
/* 1 */
2.虚函数会影响类的内存
增加一个指针的内存,32位操作系统多4个字节 ,64位操作系统多8个字节
#include <iostream>
using namespace std;
class MM
{
public:
virtual void print1()
{
cout << "虚函数1"<< endl;
}
/*virtual void print2()
{
cout << "虚函数2" << endl;
} 无论多少个虚函数,增加的字节就是一个指针的字节--->多了一个虚函数,还是4个字节*/
protected:
};
void testVirtual()
{
cout << sizeof(MM) << endl;
}
int main()
{
testVirtual();
return 0;
}
/*输出*/
/* 4 */
小知识:一旦有了数据,标识位就不需要存在了
class A
{
int num; //输出4而不是5 (4+1)
};
class B
{
//用1字节标识当前内存为结构体内存
};
void testVirtual()
{
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
}
int main()
{
testVirtual();
return 0;
}
/*输出*/
/*4
1*/
3.了解虚函数表--->通过虚函数表的指针去访问数据
就是一个指针存储所有虚函数的首地址(虚函数函数名)<--->函数指针
只有指针可以操作一段内存(4字节)
/*无论多少个虚函数,增加的字节就是一个指针的字节*/
所有的虚函数其实是 用一个函数指针去存储的 ,把 这个函数指针指向的这一段内存 称为虚函数表
#include <iostream>
using namespace std;
class MM
{
public:
virtual void print1()
{
cout << "虚函数1"<< endl;
}
virtual void print2()
{
cout << "虚函数2"<< endl;
}
protected:
};
void testVirtual()
{
//虚函数表
MM mm; //构建一个对象
int** vptr = (int** )&mm; //定义一个二级指针&对象的地址 强转类型
typedef void(*PF)(); //函数指针定义别名
PF func = (PF)vptr[0][0]; //把地址转为函数指针,访问第一个函数指针的地址
func(); //通过虚函数表的函数指针调用第一个虚函数
func = (PF)vptr[0][1];
func(); //调用第二个虚函数
}
int main()
{
testVirtual();
return 0;
}
/*输出*/
/*虚函数1
虚函数2*/
4.虚函数声明
虚函数可以在类中声明,在类外实现,不再需要virtual
修饰词,只要类名限定就可以了
class MM
{
public:
virtual void print3();
protected:
};
void MM::print3() {
cout << "虚函数3" << endl;
}
int main()
{
MM mm;
mm.print3();
return 0;
}
/*输出*/
/*虚函数3*/
来源:https://blog.csdn.net/weixin_60569662/article/details/121722479


猜你喜欢
- 今天研究了一下scope的作用域。默认是单例模式,即scope="singleton"。另外scope还有prototy
- 前言本文主要给大家介绍了关于JDK8新增的原子性操作类LongAdder的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的
- 使用场景EntityListeners在jpa中使用,如果你是mybatis是不可以用的它的意义对实体属性变化的跟踪,它提供了保存前,保存后
- 一、新建一个as项目,再新建一个model模块然后再app中的build.gradle中添加model的依赖。然后编译项目。二、编译完成后,
- 一、配置逆向generatoe.xml<?xml version="1.0" encoding="UTF
- 需求说明实现方式嗯 这个可以视作一个经典的消费者和生产者的问题,详细见代码注释代码内容 消费者,负责取走生产者产生的信息/** * @aut
- Java通过证书访问Https请求创建证书管理器类import java.io.FileInputStream;import java.se
- 1. 并行和并发有什么区别?并行:多个处理器或多核处理器同时处理多个任务。并发:多个任务在同一个 CPU 核上,按细分的时间片轮流(交替)执
- 本文实例讲述了Java * 和AOP应用。分享给大家供大家参考,具体如下:一 点睛 * 在AOP(Aspect Orient Progr
- 目前市面上的第三方短信服务平台数量十分庞大,并能为企业提供三网合一的短信接口,这些服务商通过整合短信发送服务,简单的打包成为API和SDK接
- 前言首次通过右滑来返回到上一个页面的操作是在 IOS7上出现。到目前android应用上支持这种操作的依然不多。分析其主要原因应该是andr
- 手动编写 SQL 语句和映射实体类的过程常常是繁琐且易出错的。这时,我们就可以借助 MyBatis Generator (MBG) 这个强大
- Swing组件中的事件处理专门用于响应用户的操作,例如,响应用户的鼠标单击、按下键盘等操作。在Swing事件处理的过程中,主要涉及三类对象:
- 读语句: String str = ConfigurationManager.AppSettings["DemoKey"
- 在C#绘制中国象棋棋盘是C#程序设计中GDI+的一个重要组成部分。这也是非常考验编程技巧的操作。在绘制之前首先要对棋盘有一个完整的认识。下面
- 这篇文章主要介绍了配置springboot项目使用外部tomcat过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作
- forword跳转页面的三种方式:1.使用serlvet/** * 使用forward跳转,传递基本类型参数到页面  
- 举例说明:1、有一个200*200像素的窗口,想要把它放在800*600像素的屏幕中间,屏幕的位置应是(800/2,600/2)=(400,
- 参考链接IDEA 2020.2.3版本IntelliJ IDEA 2020.2.3永久激活码(亲测有效)IDEA 2019.3版本Intel
- 0. Grinder – Grinder是一个开源的JVM负载测试框架,它通过很多负载注射器来为分布式测试提