一、虚函数表
对C++
虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样,指明了实际所应该调用的函数。
这里我们着重看一下这张虚函数表。C++的编译器应该是保证虚函数表的指针存在于对象实例中最前面的位置(这是为了保证取到虚函数表的有最高的性能——如果有多层继承或是多重继承的情况下)。 这意味着我们通过对象实例的地址得到这张虚函数表,然后就可以遍历其中函数指针,并调用相应的函数。
例子:
假设我们有这样的一个类:
class Base
{
public:
virtual void f() { cout << "Base::f" << endl; }
virtual void g() { cout << "Base::g" << endl; }
virtual void h() { cout << "Base::h" << endl; }
};
按照上面的说法,我们可以通过Base的实例来得到虚函数表。
实际例程:
typedef void(*Fun)(void);
Base b;
Fun pFun = NULL;
cout << "虚函数表地址:" << (int*)(&b) << endl;
cout << "虚函数表 — 第一个函数地址:" << (int*)*(int*)(&b) << endl;
// Invoke the first virtual function
pFun = (Fun)*((int*)*(int*)(&b));
pFun();
实际运行经果如下:
虚函数表地址:0012FED4
虚函数表 — 第一个函数地址:0044F148
Base::f
通过这个示例,我们可以看到,我们可以通过强行把&b
转成int ,取得虚函数表的地址,然后,再次取址就可以得到第一个虚函数的地址了,也就是Base::f(),这在上面的程序中得到了验证(把int强制转成了函数指针)。通过这个示例,我们就可以知道如果要调用Base::g()和Base::h()
,其代码如下:
(Fun)*((int*)*(int*)(&b)+0); // Base::f()
(Fun)*((int*)*(int*)(&b)+1); // Base::g()
(Fun)*((int*)*(int*)(&b)+2); // Base::h()
可以看到下面几点:
1)
虚函数按照其声明顺序放于表中。
2)
父类的虚函数在子类的虚函数前面。
1.C++虚基类表指针字节对齐模型
二、大纲
1.Conversion Function 转换函数
2.non-explicit-one-argument ctor 可隐式转换单一形参构造函数
3.explicit-one-argument ctor 非隐式转换单一形参构造函数
4.两种特殊的类
5.模板
5.1. 类模板
5.2. 函数模板
5.3. 成员模板
5.4. 模板特化
5.5.模板模板参数
6.关于C++标准库
7.reference 引用
7.1转换函数的基本规则:-转换函数只能是成员函数,无返回值,空参数。-不能定义到void的转换,也不允许转换成数组或者函数类型。-转换常定义为const形式,原因是它并不改变数据成员的值。
7.2可隐式转换一形参构造函数
这部分内容还有待消化下,后续补齐
7.3非隐式转换单一形参构造函数
总结一下就是explicit关键字 只对构造函数起作用,用来抑制隐式转换。
7.4两种特殊的类
7.4.1pointer-like class智能指针智能指针实际上就是传统普通指针的扩展,所以究其本质,其内 部还是必须有一个普通指针,然后再拓展其功能。
7.4.2pointer_like_class迭代器
迭代器本身就是一种指针,所以当用的时候,实际上是对该迭代器进行解引用,相当于读取它所指的对象的值,所以可以看到重载运算符函数里面是返回data的。
三、参考资料
1.http://blog.csdn.net/haoel/article/details/1948051/
2.http://blog.csdn.net/chengonghao/article/details/51679743(C++虚基类表指针字节对齐模型)