个人站长做电音网站,c 微信小程序开发教程,西安网站建设高端,山东网站建设开发维护文章目录 参考虚函数使用虚函数的class结构相关实现源码IDA反编译子类虚表和父类虚表调用函数菱形继承 参考
https://showlinkroom.me/2017/08/21/C-%E9%80%86%E5%90%91%E5%88%86%E6%9E%90/ https://www.cnblogs.com/bonelee/p/17299985.html https://xz.aliyun.com/t/5242?t… 文章目录 参考虚函数使用虚函数的class结构相关实现源码IDA反编译子类虚表和父类虚表调用函数菱形继承 参考
https://showlinkroom.me/2017/08/21/C-%E9%80%86%E5%90%91%E5%88%86%E6%9E%90/ https://www.cnblogs.com/bonelee/p/17299985.html https://xz.aliyun.com/t/5242?time__1311n4%2BxnD07itGQ%3DD54AKDsA3xCuU%3DwQNY4Dalichlgrefhttps%3A%2F%2Fxz.aliyun.com%2Fu%2F15779#toc-3
虚函数
在C中虚函数virtual function是一种特殊的成员函数它允许在派生类中重写或覆盖基类中定义的函数从而实现多态性polymorphism。虚函数的关键特征和用途可以概括如下 声明与定义 要声明一个虚函数需要在基类的成员函数声明前加上virtual关键字。例如 class Base {
public:virtual void someFunction() {// 基类的实现}
};派生类可以重写该函数也可以不重写如果重写则在派生类中提供新的实现 class Derived : public Base {
public:void someFunction() override {// 派生类的实现}
};虚函数表VTable 实现虚函数的机制通常涉及到虚函数表Virtual Table简称vtable。每个含有虚函数的类都会有一个虚函数表表中存储着该类所有虚函数的地址。每个对象都有一个指向相应类虚函数表的指针称为vptr。当通过基类指针或引用调用虚函数时程序会根据对象的vptr查找到正确的虚函数表从而调用实际对象类型的函数实现。 纯虚函数与抽象类 如果基类中的虚函数没有提供实现并且在声明时被 0初始化那么这个函数被称为纯虚函数。含有纯虚函数的类不能实例化只能作为基类被继承这样的类称为抽象类。
使用虚函数的class结构 相关实现 new的本质实际上就是malloc构造函数delete的本质就是析构函数free
源码
#include iostream
#include stringusing namespace std;class Person
{public:Person() {age 0;name ;};~Person() {};virtual void setName(string name) 0;virtual void setAge(int age) 0;
protected:int age;string name;};class Student :public Person {public:Student() {age 17;}void setName(string name) {this-name name;}string getName() {return this-name;}void setAge(int age) {if (age 30 || age 6) {cout not suitable for school! endl;return;}this-age age;}int getAge() {return this-age;}
};int main() {Student* stu new Student();stu-setName(Link);stu-setAge(18);cout stu-getName() with age stu-getAge() endl;return 0;
}IDA反编译 子类构造函数 父类构造函数
子类虚表和父类虚表 纯虚函数的抽象类的虚表由__cxa_pure_virtual填充,有几个纯虚函数就有几个__cxa_pure_virtualstudent类虚表分别有各自实现的虚函数虚表上面是该类的typeinfo的地址
RTTI (Run-Time Type Information) 是C的一项特性允许程序在运行时识别对象的类型。typeid运算符和dynamic_cast都是基于RTTI实现的。每个包含虚函数的类实例在内存中都有一个隐藏的指针称为vptr虚函数指针指向该类的虚函数表vtable。这个vptr是在对象创建时由编译器自动初始化的。RTTI信息通常与vtable一起管理其中可能包括类型描述信息和继承链信息等。 Aclass* ptra new Bclass;这行代码创建了一个指向Bclass实例的指针但这个指针被声明为Aclass*类型。因为Bclass是Aclass的子类假设如此所以这是向上转型是多态的基础。 int ** ptrvf (int**)(ptra);这里进行了一次不安全的类型转换将Aclass指针转换为了int**。这种转换通常是为了直接访问虚函数指针vptr因为在许多系统上vptr是对象内存布局的第一个元素可以被视为一个指针的指针。但是请注意这种做法非常危险且非标准违反了类型安全原则。 *((int*)ptrvf[0]-1)这一部分是为了找到RTTI信息的位置。ptrvf[0]访问的是第一个虚函数按指针算起减1则是尝试访问vptr前的一个位置期望那里存放着RTTI相关数据的指针。这一步同样非常危险依赖于特定编译器和平台的实现细节。 *((RTTICompleteObjectLocator*)(...))这里进一步将找到的地址强制转换为RTTICompleteObjectLocator指针并解引用它。RTTICompleteObjectLocator是一个内部使用的结构非标准公开接口用于存储有关对象类型的完整信息比如类的类型描述符、偏移量到类型名称字符串等。
调用函数 对于虚函数
先通过对象开始八个字节得到虚表地址通过虚表地址和相关偏移得到函数地址调用函数 对于非虚函数直接调用再text段实现的函数
菱形继承
#includestdio.h
#includestdlib.h//间接基类
class A {
public:virtual void function() {printf(A virtual function\n);}int a;
};//直接基类
class B :virtual public A { //虚继承
public:virtual void func() {printf(B virtual func()\n);}int b;
};//直接基类
class C :virtual public A { //虚继承
public:virtual void func() {printf(C virtual func());}int c;
};//派生类
class D :public B, public C {
public:virtual void function() {printf(D virtual function());}int d;
};int main(int argc, char** argv) {A* A_ptr (A*)new D();A_ptr-function();return 0;
}B和C继承AD继承B和C
通过虚表地址减去24后的位置的内容是32然后再加上起始地址对应到的V4为D内的A的对象内存位置offset vbase应该是与虚基类的偏移也就是和A的偏移 这里给各个父类对象在本对象的空间的前八个字节赋值时用的是本对象虚表对应到的不同父类的虚函数的地址
此时对应的虚表地址所以**两次得到D::function的地址然后参数为对象自己