设为首页 加入收藏

TOP

C++面向对象编程之对象模型(objectmodel)关于vptr和vtbl的讲解
2018-02-06 13:12:59 】 浏览:115
Tags:面向 对象 编程 模型 objectmodel 关于 vptr vtbl 讲解

1. 对象模型(objectmodel):关于vptr和vtbl

注意:

1)C++编译器一旦发现类中有虚函数,就会为该类生成虚函数表,并在该类型的每一个实例中添加一个指向虚函数表的指针(即从内存角度上看,含有虚函数的对象里头会多一个指针)。在32为机器上,一个指针占4字节的内存空间,所以sizeof值为4,。在64位机器上,一个指针占8字节内存,所以sizeof值为8。

2)虚函数表放的是指针(地址)。虚指针关联虚函数,和一般函数无关。

3)C是以静态绑定的方式调用函数的。而C++是以动态绑定的方式调用函数的,C++调用虚函数若以C的风格来写,应该为:

(*(p->vptr)[n])(p);   // 或 (* p->vptr[n])(p); 
4)继承的是函数调用权,父类有虚函数,则子类一定有虚函数。例子:
class A{
public:
	virtual void vfunc1();
	virtual void vfunc2();
	        void func1();
	        void func();
private:
	int m_data1, m_data2;
};

class B:public A {
public:
	virtual void vfunc1();
	        void func2();
private:
	int m_data3;
};

class C:public B{
public:
	virtual void vfunc1();
	        void func2();
private:
	int m_data1, m_data4;
};

5)前面提到C++绑定函数有两个做法,一个是静态绑定call。一个是动态绑定,动态绑定的三个条件是:通过指针调用;向上转型;调用的是虚函数。

6)声明一个容器,里面放指针,指向父类(声明为指向父类的指针,但绑定的(new)是子类)。当子类都有修改某个虚函数,通过遍历容器对象,调用这个虚函数,就能依次调用各自的版本,如下图。(再C里面实现这个行为靠if else else …)。

\

虚函数的这种做法就是“多态”,同样是point toA,但是却实际上指向不同的东西。下面的例子可以解释这个行为(注意这里的this pointer。简单的说,通过对象来调用一个函数,那个对象的地址就是this pointer。所有成员函数都有隐藏参数this

7)关于动态绑定(Dynamic Binding):

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

意思是:通过指针找到它的虚指针,再找到它的虚函数表,取出第n个,把它当成函数指针去调用。由于是通过p去调用,因而p是this pointer。(这句话也解释了上面的多态行为)

2.谈谈const

const member functions (常量成员函数)

当对象调用成员函数的时候,对象可能是const也可能不是const,成员函数可能是const也可能不是const,这样就存在两种情况。

规则:当成员函数的const和non-const版本同时存在,const object只会(只能)调用const版本,non-const object只会(只能)调用non-const版本。(而当只有一者存在时,const object也只能调用const的版本。但是non-const object却可能调用const 或non-const 版本。)

下面这个例子是设计的比较不好的:

const String str("hello world");
str.print();    
// 如果当初设计 Srting::print()时未指明 const,
// 那么就是由 const object调用 non-const member function,会出错。 

3.关于new,deete

0)在C++中,设计size_t就是为了适应多个平台的。size_t的引入增强了程序在不同平台上的可移植性。

1)new和delete是表达式,可以分解进去(编译器转化)。

2)重载::operator new, ::operatordelete, ::operator new[], ::operator delete[]

即重载全局函数。没有重载就用全局的。注意delete要接受指针。

3)重载member operator new/delete

接管了内存分配要做什么?做一个内存池。

4)重载member operator new[]/delete[]

接管使用者的行为

示例,接口。。。。。。

如果使用者想绕过设计者的设计,可以加全局的作用域。(写上global scope operator :: 会绕过前述所有overloaded functions,强迫使用global version)

5)重载new(), delete()

placement new:

我们可以重载class member operatornew(), 写出多个版本,前提是每一版本的声明都必须有独特的参数列,其中第一参数必须是size_t, 其余参数以new所指定的placemnet arguments 为初值。出现于new (……) 小括号内的便是所谓的placement arguments。

我们也可以重载class member operatordelete() (或称此为placement operator delete),写出多个版本。但他们绝不会被delete调用。只有当new所调用的ctor抛出exception,才会调用这些重载版的operatordelete()。它只可能这样被调用,主要用来归还未能完全创建成功的object所占用的memory。

这些对应的delete被调用的时机只有一个,那就是对应的new分配内存之后,如果构造函数发挥异常(表示构造对象时失败),那就把刚刚分配的内存释放掉。

6)basic_string 使用new(extra)扩充申请量

(这部分不太理解,后面补上。)

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇C++ Part8 MFC中的AfxBeginThread.. 下一篇memcpy内存拷贝函数的写法c++代码..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目