C++的类和new和delete和菱形继承机制

参考

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__1311=n4%2BxnD07itGQ%3DD54AKDsA3xCuU%3DwQNY4D&alichlgref=https%3A%2F%2Fxz.aliyun.com%2Fu%2F15779#toc-3

虚函数

在C++中,虚函数(virtual function)是一种特殊的成员函数,它允许在派生类中重写或覆盖基类中定义的函数,从而实现多态性(polymorphism)。虚函数的关键特征和用途可以概括如下:

  1. 声明与定义
    要声明一个虚函数,需要在基类的成员函数声明前加上virtual关键字。例如:

    class Base {
    public:
        virtual void someFunction() {
            // 基类的实现
        }
    };
    

    派生类可以重写该函数,也可以不重写,如果重写,则在派生类中提供新的实现:

    class Derived : public Base {
    public:
        void someFunction() override {
            // 派生类的实现
        }
    };
    
  2. 虚函数表(VTable)
    实现虚函数的机制通常涉及到虚函数表(Virtual Table,简称vtable)。每个含有虚函数的类都会有一个虚函数表,表中存储着该类所有虚函数的地址。每个对象都有一个指向相应类虚函数表的指针(称为vptr)。当通过基类指针或引用调用虚函数时,程序会根据对象的vptr查找到正确的虚函数表,从而调用实际对象类型的函数实现。

  3. 纯虚函数与抽象类
    如果基类中的虚函数没有提供实现,并且在声明时被= 0初始化,那么这个函数被称为纯虚函数。含有纯虚函数的类不能实例化,只能作为基类被继承,这样的类称为抽象类。

使用虚函数的class结构

在这里插入图片描述

相关实现

在这里插入图片描述

  • new的本质,实际上就是malloc+构造函数
  • delete的本质就是析构函数+free
    在这里插入图片描述

源码

#include <iostream>
#include <string>

using 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_virtual,student类虚表分别有各自实现的虚函数,虚表上面是该类的typeinfo的地址
在这里插入图片描述

  • RTTI (Run-Time Type Information) 是C++的一项特性,允许程序在运行时识别对象的类型。
  • typeid运算符和dynamic_cast都是基于RTTI实现的。
  • 每个包含虚函数的类实例,在内存中都有一个隐藏的指针(称为vptr,虚函数指针),指向该类的虚函数表(vtable)。这个vptr是在对象创建时由编译器自动初始化的。
  • RTTI信息通常与vtable一起管理,其中可能包括类型描述信息和继承链信息等。
  1. Aclass* ptra = new Bclass;:这行代码创建了一个指向Bclass实例的指针,但这个指针被声明为Aclass*类型。因为BclassAclass的子类(假设如此),所以这是向上转型,是多态的基础。

  2. int ** ptrvf = (int**)(ptra);:这里进行了一次不安全的类型转换,将Aclass指针转换为了int**。这种转换通常是为了直接访问虚函数指针(vptr),因为在许多系统上,vptr是对象内存布局的第一个元素,可以被视为一个指针的指针。但是,请注意,这种做法非常危险且非标准,违反了类型安全原则。

  3. *((int*)ptrvf[0]-1):这一部分是为了找到RTTI信息的位置。ptrvf[0]访问的是第一个虚函数(按指针算起),减1则是尝试访问vptr前的一个位置,期望那里存放着RTTI相关数据的指针。这一步同样非常危险,依赖于特定编译器和平台的实现细节。

  4. *((RTTICompleteObjectLocator*)(...)):这里进一步将找到的地址强制转换为RTTICompleteObjectLocator指针,并解引用它。RTTICompleteObjectLocator是一个内部使用的结构(非标准公开接口),用于存储有关对象类型的完整信息,比如类的类型描述符、偏移量到类型名称字符串等。

调用函数

在这里插入图片描述
对于虚函数

  1. 先通过对象开始八个字节得到虚表地址
  2. 通过虚表地址和相关偏移得到函数地址
  3. 调用函数
    对于非虚函数
  4. 直接调用再text段实现的函数

菱形继承

#include<stdio.h>
#include<stdlib.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继承A,D继承B和C

在这里插入图片描述通过虚表地址减去24后的位置的内容是32,然后再加上起始地址,对应到的V4为D内的A的对象内存位置,offset vbase应该是与虚基类的偏移也就是和A的偏移
在这里插入图片描述
在这里插入图片描述
这里给各个父类对象在本对象的空间的前八个字节赋值时,用的是本对象虚表对应到的不同父类的虚函数的地址
在这里插入图片描述

此时对应的虚表地址,所以**两次得到D::function的地址,然后参数为对象自己
在这里插入图片描述

  • 21
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

看星猩的柴狗

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值