[C++杂谈]C++的多态

来源:互联网 发布:美军软件人机界面标准 编辑:程序博客网 时间:2024/06/03 23:49

C++的多态实现了“一种接口,多种方法”,即当给一个对象发送一个通用的信号时,该对象能够调用正确的方法来响应。多态可以引用多个类的实例,医用多态,程序员可以给一个对象发送消息来完成一系列操作,而不用关心软件系统在系统设计阶段是如何实现这些操作的。

多态的三个基本条件:
1.由一个类继承的层次结构
2.在类中定义虚函数
3.指向对象的指针或引用
函数的静态绑定和动态绑定:

#include <iostream>  using namespace std;  class base{  public:   void print()const {cout << "调用基类的print方法!"<<endl;}  };  class derived:public base{  public:   void print() const {cout << "调用子类的print方法!"<< endl;}  };  void main(){   base *pObj = new base();   pObj->print();   delete pObj;   pObj = new derived();   pObj->print();   delete pObj;   return;  }  

//运行结果
//调用基类的print方法!
//调用基类的print方法!

结果解析:
derived类继承于base类,每个类中定义了一个打印函数。main函数中定义了base类型的指针pObj,然后实例化了一个基类对象,并通过指针调用了这个
对象的打印函数。释放内存后,又实例化了这个对象的打印函数,结果还是调用了基类的打印函数。并没有因为基类指针pObj指向子类对象的调用函数而调用子类的打印函数。这就是所谓的静态绑定。

静态绑定:这个函数在编译的时候被静态的绑定到了这个指针上,尽管它所指向的对象是在运行的时候动态创建的,指针的函数调用却已经被固定了。

动态绑定和虚函数:
例子:

#include <iostream>  using namespace std;  class base{  public:   virtual void print()const {cout << "调用基类的print方法!"<<endl;}  };  class derived:public base{  public:   void print() const {cout << "调用子类的print方法!"<< endl;}  };  void main(){   base *pObj = new base();   pObj->print();   delete pObj;   pObj = new derived();   pObj->print();   delete pObj;   return;  }  

本例中,在base中定义了虚函数print,并且在子类derived中重载了这个虚函数。在第一次调用的是基类的函数,第二次调用的是子类的函数。这样根据指向不同的对象类型的不同动态的调用不同的函数的过程称为动态绑定。虽然使用同一个接口,却可以根据需要调用不同的方法以满足不同的需要。

在面向对象的程序设计中,多态允许在基类和子类中声明共有的函数,也允许子类对基类的某些或全部函数进行覆盖。因此,我们可以设计抽象的基类,在该类中的函数时没有实现的,然后在各个子类中定义这些函数,并在派生类中定义各自的具体实现,从而实现抽象基类这个通用的接口。、

构造函数不能是虚函数。析构函数可以是虚函数。原因:
虚析构的作用:保证在销毁子类丢向时,动态删除在此对象中动态的内存。因为,如果基类成员和子类成员动态的分配了内存,就需要确保在销毁子类对象时,
子类析构函数存在并且首先被调用。
例子:

//运行结果:
//base
//derived
//base

分析:pObj第一次delete时调用了base的析构,第二次delete pObj时,先调用了子类的析构,然后又调用了基类的析构

一般在实际的使用过程中,将有差异的函数定义为虚函数,由子类自由的去覆盖重写。而对于统一通用的接口,则无需定义为virtual,这样即使子类覆盖了基类的实现,使用子类实例化的基类指针调用该接口时,也是调用的基类的实现,不必担心调用子类的实现。

多态实现的方法,实际上是,被声明为virtual的类维护了指针(这也是为什么虚类的大小比普通的类要大4个字节的原因。),指向一个虚函数列表,被声明为虚函数的函数指针被存放到了这个虚表中。当使用子类实例化基类指针时,如果一个函数在基类中被声明为了virtual,并且在子类中被覆盖了,此时虚表中原来填充的基类函数地址将被子类的函数地址所替换,以达到多态的目的。

0 0
原创粉丝点击