C++类包含两种数据成员:静态数据成员和非静态数据成员;同时包含成员函数,静态函数和虚函数三种成员函数
在此模型中,Nonstatic data members
被配置于每一个 class object
之内,static data members
则被存放在所有的 class object
之外. static
和 nonstatic function members
也被放在所有的class object
之外. Virtual functions
则由虚表机制实现,class 里保存着一个指向虚表的指针,虚表中存放着指向虚函数的函数指针。
每一个class所关联的type_info object(用以支持 runtime type identification,RTTI)也经由 virtual table 被指出来,通常是放在表格的第一个slot处。
这个模型的主要优点在于它的空间和存取时间的效率;主要缺点则是,如果应用程序代码本身未曾改变,但所用到的 class objects
的 nonstatic data members
有所修改(可能是增加、移除或更改),那么那些应用程序代码同样得重新编译,关于这点,前述的双表格模型就提供了较大的弹性,因为它多提供了一层间接性,不过它也因此付出空间和执行效率两方面的代价就是了。
class ZooAnimal {
public:
ZooAnimal();
virtual ~ZooAnimal();
virtual void rotate();
protected:
int loc;
String name;
};
在32位计算机上所占内存为16字节:int四字节,String8字节(一个表示长度的整形,一个指向字符串的指针),以及一个指向虚函数表的指针vptr。对于继承类则为基类的内存大小加上本身数据成员的大小。
“指针类型”会教导编译器如何解释某个特定地址中的内存内容及其大小:
所以,转型(cast)其实是一种编译器指令。大部分情况下它并不改变一个指针所含的真正地址,它只影响“被指出之内存的大小和其内容”的解释方式。
好,假设我们的 Bear object
放在地址1000处,一个Bear指针和一个ZooAnimal 指针有什么不同?
Bear b;
ZooAnimal *pz = &b; //Bear继承自ZooAnimal
Bear *pb = &b;
它们每个都指向Bear object
的第一个byte.其间的差别是,pb所涵盖的地址包含整个 Bear object
,而pz所涵盖的地址只包含 Bear object
中的 ZooAnimal subobject
.
自己编写的例子
#include <iostream>;
using namespace std;
class base {
public:
virtual void o()
{
cout << "base" << endl;
}
};
class A : public base {
public:
int a = 1;
virtual void o()
{
cout << "a" << endl;
}
};
class B : public base {
public:
virtual void o()
{
cout << "b" << endl;
}
};
int main()
{
A se;
base& b = se;
b.o();
cout << b.a; //此处报错: 类 "base" 没有成员 "a"
}
所以多态的应用重点在于虚函数上,因为只要有虚函数的类,就有虚指针。
1、经由一组隐式的转化操作,比如将派生类指针转化为指向其基类的指针 shape *ps =new circle();
2、经由virtual function机制 ps->rotate()
3、经由dynamic_cast 和typeid运算符
if(circle _pc = dynamic_cast