今天翻开曾经的课件,看到多态部分。而我的博客上也没有多态相关的文章,就拷贝点课件上来补充下吧。呵呵。
什么是多态?
定义:
多态性是指在一般类中定义的属性或服务被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。
作用:
这使得同一个属性或服务名在一般类及其各个特殊类中具有不同得语义。
Polymorphism allows a client to treat different objects in the same way even if they were created from different classes and exhibit different behaviors.
向上映射的危机
向上映射为什么会出现危机?
编译器的制造者不够聪明?
向上映射危机的解决之道:
class base
{
public:
virtual void print()
{
cout<<"base class"< }
};
class derived:public base
{
public:
void print()
{
cout<<"derived class"< }
};
void main()
{
derived d;
base* bp=&d;
bp->print(); //derived class
}
耶,现在是我们想要的结果哦。 嘿嘿。
我们继续探寻下位为什么能够多态。
动态绑定的实现机制(三步)
1. 为每一个包含虚函数的类设置一个虚表(VTABLE)
每当创建一个包含有虚函数的类或从包含虚函数的类派生一个类时,编
译器就会为这个类创建一个VTABLE。在VTABLE中,编译器放置了这个
类中,或者它的基类中所有已经声明为 virtual 的函数的地址。如果在这
个派生类中没有对基类中声明为 virtual 的函数进行重新定义,编译器就
使用基类的这个虚函数的地址。而且所有VTABLE中虚函数地址的顺序是
完全相同的。
2. 初始化虚指针(VPTR)
然后编译器在这个类的各个对象中放置VPTR。VPTR在对象的相同的位置(通常都
在对象的开头)。VPTR必须被初始化为指向相应的VTABLE。
3. 为虚函数调用插入代码
当通过基类的指针调用派生类的虚函数时,编译器将在调用处插入相应
的代码,以实现通过VPTR找到VTABLE,并根据VTABLE中存储的正确
的虚函数地址,访问到正确的函数。
class base{
int i;
public:
void virtual f1()
{
cout<<"base f1"< }
void virtual f2()
{
cout<<"base f2"< }
void virtual f3()
{
cout<<"base f3"< }
};
class derived:public base
{
int j;
public:
void f2()
{
cout<<"derived f2"< }
};
void main()
{
base b;
derived d;
base* bp=&d;
bp->f1();
bp->f2();
bp->f3();
cout << "b的大小:" < cout << "d的大小" << sizeof(d) <}
举例说明动态绑定的实现机制
1. 为每一个包含虚函数的类设置一个虚表(VTABLE)
2. 初始化虚指针(VPTR)
3. 为虚函数调用插入代码堆栈
为了验证上面说的基类或者派生类中指保存了一个虚表指针,我们可以通过sizeof()来查看,不管有多少个虚函数总是比变量的大小多4字节(这四字节即是虚表指针)。
纯虚函数的引入
很多时候,定义一个基类是确立其派生类的一个公共的接口,而这个基类自身派生出的对象并无意义。为了阻止用户直接派生基类对象,编译器提供了一种机制——纯虚函数。
语法: virtual void x( )=0
抽象基类:包含有纯虚函数的类称为抽象基类
定义纯虚函数就意味着告诉 编译器在VTABLE中为函数保留一个间隔,但是在这个间隔中不放地址。所以说抽象基类的VTABLE是不完全的,不可以派生对象。
阅读(642) | 评论(0) | 转发(0) |