多态(virtual)– 真正的面向对象编程

1)          多态的重要性 真正的面向对象编程

C++的编程模式:

l       C++代替C,面向过程的编程

l       基于对象的编程,利用了封装和继承重用代码

l       面向对象的编程,利用多态实现接口编程

 

2)          多态的本质

l       早捆绑

编译时刻就在函数调用处决定了函数所在的地址。没有利用多态的C/C++函数调用都是早捆绑。

l       晚捆绑

编译时刻在函数调用时插入一些代码,能根据对象的类型去调用它的函数。这是通过虚函数表VTable来实现的。

l       每个包含virtual函数的类含有一个VTable,在这个表里放置这个类的所有virtual函数的地址。每个函数地址只占2个字节,这一点比较特殊,也就是说,一个类中至多只能有65536个虚函数。

注意:每个类只有一个VTable,供所有本类对象使用。

l       每个类对象包含一个指针VPTR(一般为首地址this),指向VTable,晚捆绑时,就是通过VPTR找到VTable,将查找函数的代码插入调用处。

l       所以,虚函数会比普通函数多两到三条指令,会影响效率,且每个对象多出4个字节指针。

一个提示:为了提高效率,寻找系统中不需定义虚函数的地方。

l       一个virtual函数编译时刻的处理例子

A* p;

p->Func();

编译时,变成:

push si; //寄存器保存p

mov bx, word ptr[si]; //取出this指针放入bx

call word ptr[bx+n]; //n0,1,2…nvirtual函数。

l       inline函数不能是virtual的,原因是没有函数地址。

 

3)          多态的使用

l       在函数的声明前加上virtual,没有必要在函数定义时加、也没有必要在类前加、或者每一个派生类函数前加。

l       纯虚函数

1)      virtual void Func() = 0;

如果不实现,则只是告诉编译器在VTable里预留一个位置,但是不放函数地址。所以VTable是不完全的,不能创建类实例

2)      纯虚函数也是可以实现的,但是,这时VTable也是不完全的,子类必须实现它,否则VTable也是不完全的。在父类实现纯虚函数的作用在于为所有子类共享代码,仅此而已。

class A

{

             public:

     virtual void Func() = 0;

     //不能在这实现,因为inline函数不能是

   虚的。

};

                     void A::Func()

{

//逻辑
}

                          

                     class B : public A

{

public:

void Func(){A::Func();} 

//必须实现,否则B也是不能实例化的。

};

 

3)      一般把析构函数声明为纯虚的就可实现不让创建对象的目的。

 

l       抽象类

如果一个类所有函数都是纯虚函数,那么称这个类为抽象类。

l       纯虚函数/抽象类的作用

只能通过引用或指针访问抽象类的方法,接口编程的一个体现。

 

l       只能通过指针或引用实现多态

假设B继承于A,

A a;

B b;

a = b;

a.Func(); //这时候调用的是A的函数,因为,a = b时,调用的是A的拷贝构造函数,它会初始化VPTRa的地址。

l       派生类实现基类的虚函数时,必须保证参数和返回值都一致

如果参数不一样,那么就是自定义的重载函数;如果参数和函数名一样,返回值不一样,则编译出错。编译器必须保证用基类的指针可以访问到子类的同一函数。

l       多态在构造函数里不起作用

1)      如果在构造函数里调用虚函数,调用的是本类的版本

所以,不要在构造函数里调用虚函数。

2)      原因

构造函数是用来构建对象的,如果调用的是后面子类的方法,这时候它还没构建呢。

 

l       多态在析构函数里也不起作用

1)      如果在析构函数里调用虚函数,调用的是本类的版本

所以,不要在析构函数里调用虚函数。

2)      原因

构造函数不行是因为对象没构建完,类型信息还不可用;而析构函数是为什么呢?是因为所要调用的对象方法可能已经释放了(比如,调用子类的虚方法)

l       析构函数一般都是虚的(前提是基类有虚函数)

析构函数不像构造函数,这时候,VPTR已经构建 起来了。如果析构函数不是虚的,那么通过delete基类指针不能析构子类的对象。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值