IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 多重继承虚函数表分析 -> 正文阅读

[C++知识库]多重继承虚函数表分析

多重继承虚函数表分析

演示在多重继承下,虚函数表的样子

创建两个父类Base1 Base2,并创建Derived先后继承Base1 Base2 ,查看对于各个函数的调用结果

#include <iostream>
using namespace std;

class Base1
{
public:
	virtual void f() {
		cout << "Base1::f()" << endl;
	}

	virtual void g() {
		cout << "Base1::g()" << endl;
	}
};

class Base2
{
public:
	virtual void h() {
		cout << "Base2::h()" << endl;
	}

	virtual void i() {
		cout << "Base2::i()" << endl;
	}
};

class Derived : public Base1, public Base2
{
public:
	virtual void f() {
		cout << "Derived::f()" << endl; // 只覆盖Base1的f
	}

	virtual void i() {
		cout << "Derived::i()" << endl; // 只覆盖Base2的i
	}

	// 如下三个是本类自己的虚函数
	virtual void mh() {
		cout << "Derived::mh()" << endl;
	}

	virtual void mi() {
		cout << "Derived::mi()" << endl;
	}

	virtual void mj() {
		cout << "Derived::mj()" << endl;
	}
};

int main()
{
	typedef void(*Func)(void); // 定义了一个函数指针,typedef就代表Func是一个函数指针类型,可以将它当作类型使用
	
	cout << "sizeof(Base1)" << " = " << sizeof(Base1) << endl;
	cout << "sizeof(Base2)" << " = " << sizeof(Base2) << endl;
	cout << "sizeof(Derived)" << " = " << sizeof(Derived) << endl;
	cout << "子类的大小有8且无成员变量,说明有两个虚函数指针" << endl;

	
	Derived ins;		// 子类对象
	Base1& b1 = ins;	// 父类指针指向子类
	Base2& b2 = ins;	// 父类指针指向子类
	Derived& d = ins;	// 子类指针指向子类

	// 第一个虚函数指针(子类的)
	long* pderived1 = (long*)(&ins);
	long* vptr1 = (long*)(*pderived1);

	// 第二个虚函数指针(子类的)
	long* pderived2 = pderived1 + 1;
	long* vptr2 = (long*)(*pderived2);
	
	// 先从第一个继承的父类里找函数,如果覆盖的,就弄成自己的,如果自己没覆盖,就弄成父亲的
	// 子类分别覆盖了 f, i
	Func f1 = (Func)vptr1[0];	// Derived::f()
	Func f2 = (Func)vptr1[1];	// Base1::g()
	Func f3 = (Func)vptr1[2];	// Derived::mh()
	Func f4 = (Func)vptr1[3];	// Derived::mi()
	Func f5 = (Func)vptr1[4];	// Derived::mj()
	Func f6 = (Func)vptr1[5];
	Func f7 = (Func)vptr1[6];
	Func f8 = (Func)vptr1[7];

	// 这里找另一个父类
	Func f11 = (Func)vptr2[0];	// Base2::h
	Func f22 = (Func)vptr2[1];	// Derived::i()
	Func f33 = (Func)vptr2[2];	
	Func f44 = (Func)vptr2[3];	
	Func f55 = (Func)vptr2[4];

	cout << "-------------------" << endl;
	cout << "父类指针指向子类,调用函数得到的都是子类的虚函数" << endl;
	b1.f();	// Derived::f()
	b2.i();	// Derived::i()	
	d.f();	// Derived::f()
	d.i();	// Derived::i()
	d.mh();	// Derived::mh()
	
	cout << "-------------------" << endl;
	cout << "打印子类第一个虚函数表,对应Base1,子类覆盖了Base::f()" << endl;
	f1();
	f2();
	f3();
	f4();
	f5();
	//f6(); 无法访问

	cout << "-------------------" << endl;
	cout << "打印子类第二个虚函数表,对应Base2,子类覆盖了Base::i()" << endl;
	cout << "并且第二个虚函数表里面无法访问子类自己的虚函数,说明子类的虚函数都在第一个虚函数表" << endl;
	f11();
	f22();
	//f33(); 无法访问
	//f44(); 无法访问
	//f55(); 无法访问
	cout << "-------------------" << endl;

	return 0;
}
sizeof(Base1) = 4
sizeof(Base2) = 4
sizeof(Derived) = 8
子类的大小有8且无成员变量,说明有两个虚函数指针
-------------------
父类指针指向子类,调用函数得到的都是子类的虚函数
Derived::f()
Derived::i()
Derived::f()
Derived::i()
Derived::mh()
-------------------
打印子类第一个虚函数表,对应Base1,子类覆盖了Base::f()
Derived::f()
Base1::g()
Derived::mh()
Derived::mi()
Derived::mj()
-------------------
打印子类第二个虚函数表,对应Base2,子类覆盖了Base::i()
并且第二个虚函数表里面无法访问子类自己的虚函数,说明子类的虚函数都在第一个虚函数表
Base2::h()
Derived::i()
-------------------
  • 一个对象,如果它所属的类有多个基类,则有多个虚函数表指针(是虚函数表指针而不是有多个虚函数表)

  • 在多重继承中,对应各个记类的vptr按继承顺序依次放置在类内存空间中,且子类与基类共用同一个vptr

    比如本例子,第一个vptr指向的虚函数表里含有子类的虚函数,而第二个vptr的虚函数表并无

虚函数表图片

image-20211203111747442

  • 子类对象ins有两个虚函数表指针,vptr1 vptr2
  • Derived有两个虚函数表,因为它继承自两个基类
  • 子类和第一个基类共用一个vptr,也可以说共用一个虚函数表
  • 子类中的虚函数覆盖了父类中的同名虚函数
  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-28 11:37:29  更:2022-04-28 11:38:53 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/21 1:24:47-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码