C++虚函数与多态

多态性是面向对象程序设计的关键技术之一。利用多态性技术,可以调用同一个函数名的函数,实现完全不同的功能。若程序设计语言不支持多态性,不能称为面向对象的语言。

在C++中有两种多态性:

  • 编译时的多态性:通过函数的重载和运算符的重载来实现的。
  • 运行时的多态性:在程序执行前,无法根据函数名和参数来确定该调用哪一个函数,必须在程序执行过程中,根据具体情况来动态地确定。它是通过类继承关系和虚函数来实现的。

 

运行时的多态示例代码如下:

#include <iostream>
using namespace std;
class Animal
{
public:
      virtual void display() { cout << "I am a animal" << endl; }
};
class Duck : public Animal
{
public:    
     void display() { cout << "I am a duck" << endl; }
};
class Tiger : public Animal
{
public:
     void display() { cout << "I am a tiger" << endl; }
};

int main(int argc, char* argv[])
{
    Animal *animal = new Animal();
    Animal *duck = new Duck();;
    Animal *tiger = new Tiger();
    
    animal->display();    
    duck->display();
    tiger->display();
    
    getchar();
    delete animal;
    delete duck;
    delete tiger;
    return 0;
}
        运行结果如下:

 原理

为了达到动态绑定(后期绑定)的目的,C++ 编译器透过虚拟函数表(常被称为vtable)。每一个「内含虚拟函数的类别」,编译器都会为它做出一个虚拟函数表,中的每一笔元素都指向一个虚拟函数的地址。此外,编译器当然也会为类别加上一项成员变量,是一个指向该虚拟函数表的指针(常被称为vptr)。

        如下图所示:

 

明白了虚函数的工作原理,我突然想到关于非虚函数的问题。为什么指向子类的父类指针在调用非虚函数时,调用的全是父类的方法?

我查阅了《c++ Primer》,书中这样说:

因为可以使用基类类型的指针或引用来引用派生类型对象,所以,使用基类
类型的引用或指针时,不知道指针或引用所绑定的对象的类型:基类类型的引用
或指针可以引用基类类型对象,也可以引用派生类型对象。无论实际对象具有哪
种类型,编译器都将它当作基类类型对象。将派生类对象当作基类对象是安全的,
因为每个派生类对象都拥有基类子对象。而且,派生类继承基类的操作,即,任
何可以在基类对象上执行的操作也可以通过派生类对象使用。

 

posted @ 2014-04-09 17:59  wangke1020  阅读(382)  评论(0编辑  收藏  举报