C++面向对象高级编程学习笔记(四)


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

最右边的是A、B、C三个class的继承关系,左边的是A,B,C三个类的三个对象a,b,c的对象模型(表示在内存中的结构);

在对象模型中,会有虚函数表指针和数据,虚函数表指针是内存头,即对象的地址也是虚函数表的地址;

虚函数表指针vptr是指向虚函数表vtbl的,vtbl内会有类里面所有虚函数的地址,并且是按在类里面声明的顺序,按数组方式排列(表头是0);

如果有一个指针p指向对象c,那么我们就可以通过这个指针和地址,直接调用对象内的虚函数(而不用通过函数名),上面的便有它的调用方法(通过指针p,找到虚表指针vptr,再找出它的虚表vtbl取出其中的第n个,把它当函数指针,去调用p,因为p是调用者所以this就是指向p)

当一个函数调用,同时满足下面的3个条件时,(1)对象通过指针被调用的,(2)对象是向上转型的(它定义的是自己的类型,但其实是父类的类型,这就叫做向上转型),(3)调用的是对象的虚函数,编译器就会把这个调用动作编译为上面所说的调用方式,称为动态绑定(相对的是,不通过指针调用的静态绑定,)。

关于this

在调用流程图中,子类对象调用了父类的函数,调用者是子类对象,所以this是指向类子对象;

这样,被调用的函数里面的每一个函数都会写成通过this指针调用的形式,上面便是;

接着如果被调用的函数是虚函数,就会被写成动态绑定,上面便是;

这就是之前所说的,满足三个条件的函数调用,会被编译器写成动态绑定形式。

关于Dynamic Binding

静态绑定,在编译成汇编时,会有直接的地址给出;

而通过指针的动态绑定,则没有。

关于const

成员函数的名称后面,可以加上const,表示它不打算改变class的data。

之前有提及成员函数不加const的,可能使数据发生改变;也提及过加与不加const的成员函数的签名是不一样的;解释如下:

const object是不能调用non-const

member functions的,前者说不能改变,但后者则可能改变,后者不能包容前者。

而且,当成员函数的const和non-const版本同时存在,const object只能调用const版本,non-const object也只会调用non-const版本。

如果当初设计String中的print()时未指明const,那么上行便是经由const object调用non-const member function,这不符合上面所以的规则显然是会出错的。

(对于加不加const,其实在函数起名的时候就已经可以确定了,因为名称代表着它的动作,从动作就可以知道是不是要加const)

关于new和delete

如何重载new和delete?

new和delete是表达式,表达式的行为是不能变的;

之前我们学过,new和delete是会被分解多个步骤的;

据此,我们可以通过重载它分解步骤里所调用的函数,实现对new和delete的重载。

上面便是重载的接口。

operator new( new [ ] )和operator delete( delete [ ] )的重载

operator new和operator delete的实现:

operator new[]和operator delete[]的实现:

为什么要加4?下面有解释。

调用示例

在示例中上面的是无虚函数时的情况,下面的是有虚函数时的情况。

我们已经把重载写好,重载里面还会用cout打印出调用数据。

调用测试,分别用1,2,3,4行进行;

第1,2行的调用数据显示,有虚函数的比无虚函数的多4,因为多了虚函数表指针(在32位环境下,指针占4);

第3,4行,动态分配array时,会顺序调用5次构造函数,array

delete则是逆顺序调用析构函数;它在数据包之前会有一块大小为4的内存块,作为计数器counter,记录数据的个数(这里counter的是5,表示有5个元素,这能使编译器很快知道要调用5次构造和析构函数),所以它的大小是每个object的大小之和,加上4(注,每个object都会有自己的虚函数表指针,不要理解错了)

如果调用时采用下行的方式,那么将不会进入刚才重载的函数,而是调用原有的全局函数。

关于class member operator new()的更多重载:

之前我们已经重载成员函数的operator new()(成员函数的调用者一定是这种class的对象),如果我们要重载更多的版本,那么要在它原来的基础上增加参数列(原来的只有一个size_t类型的形参),并且它的第一个参数必须是size_t类型(代表某块内存的大小的类型,size type),每个版本的重载也必须有不同的参数列,上面便是声明和调用形式,调用时要在new()的小括号里写上除了第一参数之外的其余参数,这些小括号里额外的参数叫做placement

new。

我们也可以重载与上面有额外参数的相对应的class member operator

delete(),但它并不能被delete语句调用,它只有在当对应的operator new()所调用的ctor抛出异常时,才会被调用,去delete未完成创建的内存块。

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

推荐阅读更多精彩内容