C++对象模型(2)

本文预览:

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

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

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

关于vptr和vtbl

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

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

typedef void(*Fun)(void);

class Base {
private:
    virtual void f() {cout<<"Base::f()"<<endl;}
    virtual void g() {cout<<"Base::g()"<<endl;}
    virtual void h() {cout<<"Base::h()"<<endl;}

}

int main()
{
  Base b;
  Fun fp = nullprt;
  for(int i = 0; i < 3; i++)
  {
      fp = (Fun)*((long*)*(long*)(&b) + i);
      fp();
  }
}
运行结果:
Base::f()
Base::g()
Base::h()

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

关于this指针

上一张很久之前的图了:

关于this指针

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

关于Dynamic Binding(动态绑定)

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

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

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

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

静态绑定

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

再看第二张:

动态绑定

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()"<<std::endl;
    return p;
}

void myFree(void* ptr)
{
    free(ptr);
    std::cout<<"myFree()"<<std::endl;
}

//会覆盖掉前面,影响范围是全局的
void* operator new(size_t size){return myMalloc(size);}
void operator delete(void* ptr) { myFree(ptr);}

class Apple{
public:
    Apple(){std::cout<<"Apple::Apple()"<<std::endl;}
    void* operator new(size_t size){std::cout<<"+++++++"<<std::endl; return myMalloc(size);}
    void operator delete(void* ptr) {std::cout<<"-------"<<std::endl;return myFree(ptr);}
};
int main(int argc, const char * argv[]) {
    
    //调用class重载的
    Apple* apple = new Apple;
    
    delete apple;
    
    //强制调用全局的
    Apple* app = ::new Apple;
    
    ::delete app;

    return 0;
}

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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342

推荐阅读更多精彩内容