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++ RTTI 及 虚函数表 -> 正文阅读

[C++知识库]C++ RTTI 及 虚函数表

RTTI

RTTI概念

RTTI(Run Time Type Identification)即通过运行时类型识别,程序能够使用基类的指针或引用来检查着这些指针或引用所指的对象的实际派生类型。

RTTI机制的产生

C++是一种静态类型语言。其数据类型是在编译期就确定的,不能在运行时更改。然而由于面向对象程序设计中多态性的要求,C++中的指针或引用(Reference)本身的类型,可能与它实际代表(指向或引用)的类型并不一致。有时我们需要将一个多态指针转换为其实际指向对象的类型,就需要知道运行时的类型信息,这就产生了运行时类型识别的要求。和Java相比,C++要想获得运行时类型信息,只能通过RTTI机制,并且C++最终生成的代码是直接与机器相关的。

RTTI机制的实现

  • typeid运算符,用于返回表达式的类型。
  • dynamic_cast<>运算符,用于将基类的指针或引用安全的转换成派生类的指针或引用。
#include <iostream>
#include <string.h>
#include <cxxabi.h> //使用abi::__cxa_demangle

class Base{
public:
    virtual void g(){
        std::cout << "Base::g()" << std::endl;
    }
    virtual  ~Base(){

    }
};

class Derive :public Base{
public:
    virtual void g(){
        std::cout << "Derive::g()" << std::endl;
    }
    virtual void myself(){
        std::cout << "Derive::myself()" << std::endl;
    }
    virtual ~Derive(){
    }
};

int main(int argc, const char * argv[]) {
    Derive mydrive;
    Base &yb = mydrive;
    
    std::cout<<typeid(mydrive).name()<<std::endl; // 输出 6Derive
    
    const std::type_info &info = typeid(mydrive);
    std::cout<<abi::__cxa_demangle(info.name(),0,0,0 )<<std::endl; //输出 Derive
    
    Base *pb = new Derive();
    Derive* clp = dynamic_cast<Derive*>(pb);
    clp->myself();   //输出 Derive::myself()
    return 0;
}

总结:

  1. typeid函数的主要作用就是知道当前的变量是什么类型的。typeid()函数的返回类型为typeinfo类型的引用。typeid(a).name()返回变量a的类型。
  2. dynamic_cast强制转换符用于将一个指向派生类的基类指针或引用转换为派生类的指针或引用,注意dynamic_cast转换符只能用于含有虚函数的类
  3. RTTI,运行时类型识别。实现的要求就是必须存在虚函数,也就是说一定要有虚函数表。没有虚表,则RTII毫无意义!

虚函数

1、多态

多态:即一个接口多种实现,是面向对象的核心。可以实现接口复用,解决项目中紧偶合的问题,提高程序的可扩展性.。

静态多态:即 重载,因为在编译期决议确定,所以称为静态多态。在编译时就可以确定函数地址。

动态多态:即重写,通过继承重写基类的虚函数实现的多态,因为实在运行时决议确定,所以称为动态多态。运行时在虚函数表中寻找调用函数的地址。

注:?

1、重载的概念并不属于“面向对象编程”,重载的实现是:编译器根据函数不同的参数表,对同名函数的名称做修饰,然后这些同名函数就成了不同的函数(至少对于编译器来说是这样的)。

2、重载只是一种语言特性,与多态无关,与面向对象也无关!引用一句Bruce Eckel的话:“不要犯傻,如果它不如果它不是晚绑定,它就不是多态。”

继承中要构成多态还需要两个条件:
a. 调用函数的对象必须是指针或者引用
b. 被调用的函数必须是虚函数,且完成了虚函数的重写。

2、虚表及虚表指针

虚函数的实现是由两个部分组成的,虚函数指针与虚函数表。

上文提到typeinfo类型,通过测试发现:

#include <iostream>

class Base {
public:
	virtual ~Base() {}
	virtual void funcA() {
		std::cout << "Base::funcA()" << std::endl;
	}
	virtual void funcB() {
		std::cout << "Base::funcB()" << std::endl;
	}
};

class Derive : virtual public Base {
public:
	virtual ~Derive() {}
	virtual void funcA() {
		std::cout << "Derive::funcA()" << std::endl;
	}
	virtual void funcC() {
		std::cout << "Derive::funcC()" << std::endl;
	}
	void funcD() {
		std::cout << "Derive::funcD()" << std::endl;
	}
private:
	int i;
};

int main(){
	Base *pb2 = new Derive();
	const type_info &info = typeid(*pb2);
	printf("type_info地址为:%p\n", &info);
	long *pvptr = (long *)pb2;
	long *vptr = (long *)(*pvptr);
	printf("虚函数表首地址为:%p\n", pvptr);

	long *prtti = (long *)(*(vptr - 1));  // //这里的-1实际上是往上走了4个字节
	printf("虚函数表首地址为:%p\n", pvptr);
	prtti += 3; //跳过12字节
	long * rtti = (long *)(*prtti);
	const std::type_info *ptypeinfoaddrreal = (const std::type_info *)rtti;
	printf("type_info地址为:%p\n", ptypeinfoaddrreal);
}

测试结果:

???????

typeinfo的存放位置如下图:

?????????编译器会在虚函数表 vftable 的开头插入一个指针,指向当前类对应的 type_info 对象。当程序在运行阶段获取类型信息时,可以通过对象指针 p 找到虚函数表指针 vfptr,再通过 vfptr 找到 type_info 对象的指针,进而取得类型信息

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-15 11:36:23  更:2021-10-15 11:38:45 
 
开发: 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年11日历 -2024/11/24 2:54:30-

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