博览网:C++面向对象高级编程(下)第二周笔记

一、虚指正(vptr)和虚表(vtbl)

我们以下图介绍上述两者:

1、当类中存在虚函数就会出现虚指针vpt,无论虚函数有多少个,有且仅有一个虚函数,指向虚表(rvtbl)的地址;

2、虚表是什么呢??

我们可以将它理解为一种表格,每个表格的位置存放一个虚函数对应内存的地址;

例如:基类A中包含两个虚函数vfunc1()、vfunc2(),那么类A的对象在在内存中表现如上图a(A object),其存储类的两个基本数据:m_data1、2m_data2以及两个虚函数对应的虚指针vptr,而虚指针指向虚表的地址,虚表存放虚函数内存的两个地址:0x401ED0、0x401FD0;同理,A类的子类B,B类的子类C也有类似的原理;

将vptr实现vtbl内容翻译为C:

(*p->vptr)n;

(* p->vptr[n])(p);

3、动态绑定: 虚机制

动态绑定(dynamic binding):动态绑定是指在执行期间(非编译期)判断所引用对象的实际类型,根据其实际的类型调用其相应的方法。

C++中,通过基类的引用或指针调用虚函数时,发生动态绑定。引用(或指针)既可以指向基类对象也可以指向派生类对象,这一事实是动态绑定的关键。用引用(或指针)调用的虚函数在运行时确定,被调用的函数是引用(或指针)所指对象的实际类型所定义的;

C++中动态绑定条件发生需要满足2个条件:

(1)只有指定为虚函数的成员函数才能进行动态绑定,成员函数默认为非虚函数,非虚函数不能进行动态绑定

(2)必须通过基类类型的引用或指针进行函数调用

所谓的动态类型,当引用或指针调用了虚函数时,它就是动态类型,它的行为要到程序运行时才能定义 ;

当我们用派生类去初始化基类的引用或指针后,假如调用的是非虚函数,那么这时实际调用的函数是基类的函数;假如调用的是虚函数,那么这是调用的是派生类自己定义的虚函数  下面是具体的例子来说明静态类型和动态类型

class A{

public:

virtual void show(){cout<<"j基类的show()"<

void get(){cout<<"基类的get()"<

};

class B:public A{

public:

virtual void show(){cout<<“派生类的show()”<

void get(){cout<<"派生类的get()"<

};

main:

A a;

B b;

A &c=b;

c.show();//show函数是虚函数,并且此时使用派生类的对象去初始化基类的引用,发生了动态绑定,调用的是实际类        型B的show()----"派生类的show"

c.get();//此时不满足动态绑定的条件,c是静态类型,结果是-------基类的get()

二、this指针

1、C++this指针,一个对象的this指针并不是对象本身的一部分,不会影响sizeof(对象)的结果。this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。this指针是类的一个自动生成、自动隐藏的私有成员,它存在于类的非静态成员函数中,指向被调用函数所在的对象。全局仅有一个this指针,当一个对象被创建时,this指针就存放指向对象数据的首地址;

注:简单点说,通过一个对象调用函数时,函数的地址就是this;

举例:

父类CDocument

子类CMyDoc,子类对虚函数Serialise()进行了重新定义;

通过语句myDoc.OnFileOpen()调用父类函数时,子类对象myDoc的地址即为this,上述语句可表述为:CDocument::OnFileOpen(&myDoc),&myDoc就是this,this调用虚函数,进行动态绑定,通过this->Serialize()调用了子类的虚函数,而不是父类的虚函数,this->Serialize()也可以表达为虚指针、虚表的形式,即:*(this->vptr)[n](this),这样我们就可以更好的理解this以及虚机制;

三.动态绑定

再第一章节已介绍过动态绑定,这里就不再赘述;

四、const

课件中已做了详细的介绍,我这里简单总结下,并做些衍生:

1、常数对象可以调用常函数;

非常数对象可以调用常函数;

常数对象不可以调用非常函数;

非常数对象可以调用非常函数;

注:当成员函数的常数版本和非常版本同时存在时(以函数重载形式出现),常数对象只可以调用常函数;非常数对象只可以调用非常函数。

2、注意的几点:

1)const一般放在成员函数后头,不放在全局函数后头, 例:void function() const { return data;} ;

2)在成员函数后面加const是属于签名, 就是当两个成员函数传参相同,那么加不加const也会被区分成两个函数. ;

3、const的其他使用方法:

1)定义常量

(1)const修饰变量,以下两种定义形式在本质上是一样的。

它的含义是:const修饰的类型为TYPE的变量value是不可变的。

TYPE const ValueName = value;

const TYPE ValueName = value;

(2)将const改为外部连接,作用于扩大至全局,编译时会分配内存,并且可以不进行初始化,仅仅作为声明,编译器认为在程序其他地方进行了定义.

extend const int ValueName = value;

2)指针使用CONST

(1)指针本身是常量不可变

char* const pContent;

(2)指针所指向的内容是常量不可变

const char *pContent;

(3)两者都不可变

const char* const pContent;

(4)还有其中区别方法,沿着*号划一条线: 如果const位于*的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量; 如果const位于*的右侧,const就是修饰指针本身,即指针本身是常量。

五、关于New,Delete

new对象的流程不能更改,但是实现过程中的函数可以被更改.

operator new

operator delete

array new一定要array delete;

回忆前边的内容:delete 某个对象,其实质是先调用析构函数,再释放内存

六、重载::operator new, ::operator new[],::operator delete ,::operator delete[]

在全局当中:

Note: 如果你重载了全局的操作符, 所以要额外小心.

这些重载不可以被声明在一个namespace中.

//这里的函数是编译器去调用, 所以size是编译器给出.

void* operator new( size_t size )

{ return malloc(size);}

void* operator new[]( size_t size )

{ return malloc(size);}

void* operator delete(void* ptr )

{ free(ptr);}

void* operator delete[](void* ptr )

{ free(ptr);}

重载 member new , delete

在class里面重载new, delete

class foo{

public:

void* operator new(size_t size);

void operator delete(void *, size_t size); //size为可选

…….

};

那么你在:

foo *a = new foo;

delete a;

就会调用上面重载的函数.

new[] , delete[] 也如此.

七、实例

当类中重载了new , delete , 而又想调用全局的new , delete

可以这样写:

::delete a;

string类内其实是一个指针.

当创建一个数组的时候, 内存当中就会多分配一个指针,该指针用于保存当前数组个数.

八、重载new(),delete()示例

允许重载成员函数new(….) 其中参数中,必须有第一个且第一个必须是size_t size. 其余参数以new所指定的placement argument为初值.

Foo* p = new(300,’c’)Foo; //这里是三个参数

我们也可以重载类成员函数 operator delete() ,写出多个版本. 但他们绝不会被 通常所使用的delete调用.只有当new所调用的ctor抛出 异常,才会调用这些重载版的operator delete(). 它们只能这样被调用,主要用来归还未能完全创建成功的对象所占用的内存.

九、Basic_String使用new(extra)扩充申请量

Basic_String在重载new()过后,传递了一个extra参数, 用于后台自动多申请extra空间。

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

推荐阅读更多精彩内容