C++对象模型(2)

本文预览:

  • 关于vptr(虚函数表指针)和vtbl(虚函数表)
  • 关于this指针
  • 关于Dynamic Binding(动态绑定)
  • new delete操作符重载

关于vptr(虚函数表指针)和vtbl(虚函数表)

虚函数表指针和虚函数表是C++实现多态的核心机制,理解vtbl和vptr的原理是理解C++对象模型的重要前提。
class里面method分为两类:virtual 和non-virtual。非虚函数在编译器编译是静态绑定的,所谓静态绑定,就是编译器直接生成JMP汇编代码,对象在调用的时候直接跳转到JMP汇编代码执行,既然是汇编代码,那么就是不能在运行时更改的了;虚函数的实现是通过虚函数表,虚函数表是一块连续的内存,每个内存单元中记录一个JMP指令的地址,通过虚函数表在调用的时候才最终确定调用的是哪一个函数,这个就是动态绑定。

C++对象模型(2)_第1张图片
关于vptr和vtbl

class的内部有一个virtual函数,其对象的首个地址就是vptr,指向虚函数表,虚函数表是连续的内存空间,也就是说,可以通过类似数组的计算,就可以取到多个虚函数的地址,还有一点,虚函数的顺序和其声明的顺序是一直的。

通过虚函数表来调用虚函数,绕过private的限制:

typedef void(*Fun)(void);

class Base {
private:
    virtual void f() {cout<<"Base::f()"<
运行结果:
Base::f()
Base::g()
Base::h()

需要注意的是,由于我的电脑是64位的系统,vptr转成long,八个字节,32位的int就可以了,这个根据自己的环境去修改就可以了。&b取vptr,转成long*,取出来是vtbl ,同样需要转成八字节,不然在指针偏移的时候肯定就错了,也就是+i,虚函数地址取出来要转换成可执行的函数指针,这样即使在class声明的时候做了private限制,在指针面前直接就绕过去了。

关于this指针

上一张很久之前的图了:

C++对象模型(2)_第2张图片
关于this指针

每一个成员函数都有一个默认参数,那就是this,this代表对象本身,但是this究竟是什么呢?this就是对象的地址。

关于Dynamic Binding(动态绑定)

怎么理解动态绑定和静态绑定,一般来说,对于类成员函数(不论是静态还是非静态的成员函数)都不需要创建一个在运行时的函数表来保存,他们直接被编译器编译成汇编代码,这就是所谓的静态绑定;所谓动态绑定就是对象在被创建的时候,在它运行的时候,其所携带的虚函数表,决定了需要调用的函数,也就是说,程序在编译完之后是不知道的,要在运行时才能决定到底是调用哪一个函数。这就是所谓的静态绑定和动态绑定。
参考: C++this指针-百度百科

动态绑定需要三个条件同时成立:

1 指针调用
2 up-cast (有向上转型,父类指针指向子类对象)
3 调用的是虚函数

通过两张图看看汇编代码:

C++对象模型(2)_第3张图片
静态绑定

a.vfunc1()调用虚函数,那么a调用的是A的虚函数,还是B的虚函数?对象调用不会发生动态绑定,只有指针调用才会发生动态绑定。120行下面发生的call是汇编指令,call后面是一个地址,也就是函数编译完成之后的地址了。

再看第二张:

C++对象模型(2)_第4张图片
动态绑定

up-cast、指针调用、虚函数三个条件都满足动态调用,call指令后面不再是静态绑定简单的地址,翻译成C语言大概就是(*(p->vptr)[n](p)),通过虚函数表来调用函数。

new delete操作符重载

举个例子:

String* s = new String("hello world");

new 操作符主要干了两件事

  • 调用operator new分配内存空间
  • 调用构造函数

这个在之前的文章中C++如何设计一个类2(含指针的类)将过,这里写的就简单一些了。

这里我们要重载operator new,需要注意的是我们可以重载全局和成员操作符,两个影响范围是不一样的。

void* myMalloc(size_t size)
{
    void* p = malloc(size);
    std::cout<<"myMalloc()"<
int main(int argc, const char * argv[]) {
    
    //调用class重载的
    Apple* apple = new Apple;
    
    delete apple;
    
    //强制调用全局的
    Apple* app = ::new Apple;
    
    ::delete app;

    return 0;
}

new[] 和delete[]是一个道理。

你可能感兴趣的:(C++对象模型(2))