多态性和虚函数

《C++编程思想》

第十五章 多态性和虚函数


     多态性改善了代码的组织性和可读性,同时也使创建的程序具有可扩展性。访问控制通过使细节数据设为private,将接口从具体实现中分离开来。虚函数则根据类型来解耦。

       向上类型转换。取一个对象的地址,并将其作为基类的地址来处理,这称为向上类型转换。如下代码:

Class A{

Public:

Void play() const{。。。};

};

 

Class B:public A{

Public:

Void play() const{…};

};

 

Class C:public A{

Public:

Void play() const{…};

};

 

Void func(A & a)

{

a.play();

};

int main()

{

C c;

Func(c)

Func()接受一个A,但也不拒绝任何A派生的类,无需类型转换就能将对象传给func。

把函数体与函数调用相联系称为捆绑。当捆绑在程序运行之前完成时,这称为早捆绑。使用virtual可以实现晚捆绑。在派生类中virtual函数的重定义通常称为重写。注意,仅需要在基类中声明一个函数为virtual,调用所有匹配基类声明行为的派生类函数都将使用虚机制。

抽象基类和纯虚函数:只是想对基类进行向上类型转换,使用它的接口,不希望用户实际地创建一个基类的对象。要做到这一点,可以在基类中加入至少一个纯虚函数,使其基类称为抽象类。纯虚函数使用关键字virtual,并且在其后面加上=0。编译器会保证不能生成抽象类的对象。当继承一个抽象类时,必须实现所有的纯虚函数,否则继承出来的类也将是抽象。

纯虚函数禁止对抽象类的函数以传值方式调用。通过抽象类,保证在向上类型转换期间总是使用指针或引用。

编译器对新类创建一个新VTABLE表,并且插入新函数的地址,对于没有重新定义的虚函数使用基类函数的地址。

虚函数和构造函数:当创建一个包含有虚函数的对象时,必须初始化它的VPTR以指向相应的VTABLE。因为生成一个对象是构造函数的工作,所以设置VPTR也是构造函数的工作。编译器在构造函数的开头部分秘密地插入能初始化VPTR的代码。

构造函数有一个专门的工作:确保对象被正确地建立。在构造函数内,必须想办法保证所有成员都已经建立,保证它的唯一方法是让基类构造函数首先被调用。这样,当在派生类构造函数中,在基类中能访问的所有成员都已经被初始化。

对于在构造函数中调用一个虚函数的情况,被调用的只是这个函数的本地版本虚机制在构造函数中不工作

当这一系列构造函数调用正发生时,每个构造函数都已经设置VPTR指向它自己的VTABLE。如果函数调用使用虚机制,它将只产生通过他自己的VTABLE的调用,而不是最后派生的VTABLE(所有构造函数被调用后才会有最后派生的VTABLE)。

析构函数和虚拟析构函数:构造函数是不能为虚函数的,但析构函数能够且常常必须是虚的。析构函数的析构顺序是由最晚派生的类开始,并向上到基类。每个析构函数知道它所在类从哪一个派生而来,但不知道它派生出哪些类。

#include<iostream>

using namespacestd;

class Base1{

public:

       ~Base1(){cout <<"~Base1()\n";}

};

 

classDerived1:public Base1{

public:

       ~Derived1(){cout <<"~Derived1()\n";}

};

 

class Base2{

public:

       virtual ~Base2(){cout <<"~Base2()\n";}

};

 

classDerived2:public Base2{

public:

       ~Derived2(){cout <<"~Derived2()\n";}

};

 

int main(intargc,char *argv[])

{

       Base1* bp= new Derived1;

       delete bp;

       Base2* b2p= new Derived2;

       delete b2p;

       system("pause");

}

不把析构函数设置为虚函数是一个隐匿的错误,因为它常常不会对程序有直接的影响,但某些情况下会存在内存泄露。

作为一个准则,任何时候我们的类中都要有一个虚函数,我们应当立即增加一个虚析构函数,即使它什么也不做。

析构函数中的虚机制:在析构函数中,只有成员函数的“本地”版本被调用;虚机制被忽略。(就是说,在析构函数中,不会调用派生类里的虚函数。因为在析构到本类时,派生类的析构函数已经被调用,派生类的成员变量已被析构,不能再调用派生类中的函数)。

 

posted on 2015-03-17 16:03  qinguanri  阅读(172)  评论(0编辑  收藏  举报

导航