多态是指使用相同的函数名来访问函数不同的实现方法,可以简单概括为“一种接口,多种方法”。
最常见的用法是:父类(基类)指针,基类指针可以指向任何子类(派生类)对象(实例),然后通过基类的指针调用实际派生类的成员函数,示例如下:
#include <iostream> using namespace std; class Base { public: void f(int x){ cout << "Base::f(int) " << x << endl; } void f(float x){ cout << "Base::f(float) " << x << endl; } // 必须有virtual关键字,此为虚函数 virtual void g(void){ cout << "Base::g(void)" << endl;} }; class Derive: public Base { public: // virtual关键字,可有可无,此为虚函数 virtual void g(void){ cout << "Derived::g(void)" << endl;} }; int main(void) { Derive d; Base *pb = &d; pb->f(42); // 运行结果: Base::f(int) 42 pb->f(3.14f); // 运行结果: Base::f(float) 3.14 pb->g(); // 运行结果: Derived::g(void) return 0; }
C++ 中的虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的,简称为V-Table。每个含有虚函数的类有一张虚函数表,表中每一项是一个虚函数的地址, 也就是说,虚函数表的每一项是一个虚函数的指针。 没有虚函数的C++类,是不会有虚函数表的。
下面通过一些示例简单介绍虚函数表:
#include <iostream> using namespace std; class Base { public: virtual void f() { cout << "Base::f" << endl; } virtual void g() { cout << "Base::g" << endl; } virtual void h() { cout << "Base::h" << endl; } }; int main(void) { Base b; b.f(); //"Base::f" b.g(); //"Base::g" b.h(); //"Base::h" return 0; }
注意:在上面这个图中,虚函数表的最后多加了一个结点,这是虚函数表的结束结点,就像字符串的结束符“\0”一样,其标志了虚函数表的结束。这个结束标志的值在不同的编译器下是不同的。
下面,再让我们来看看继承时的虚函数表是什么样的。
假设有如下所示的一个继承关系:
#include <iostream> using namespace std; class Base { public: virtual void f() { cout << "Base::f" << endl; } virtual void g() { cout << "Base::g" << endl; } virtual void h() { cout << "Base::h" << endl; } }; class Derive:public Base { public: virtual void f1() { cout << "Derive::f1" << endl; } virtual void g1() { cout << "Derive::g1" << endl; } virtual void h1() { cout << "Derive::h1" << endl; } }; int main(void) { Derive d; //派生类对象 return 0; }
无虚函数覆盖的虚函数表特点如下:
1)虚函数按照其声明顺序放于表中。
2)父类(派生类)的虚函数在子类(基类)的虚函数前面。
没有覆盖父类的虚函数是毫无意义的。之所以要讲述没有覆盖的情况,主要目的是为了给一个对比。在比较之下,我们可以更加清楚地知道其内部的具体实现。
下面,我们来看一下,如果子类中有重载了父类的虚函数,会是一个什么样子?
#include <iostream> using namespace std; class Base { public: virtual void f() { cout << "Base::f" << endl; } virtual void g() { cout << "Base::g" << endl; } virtual void h() { cout << "Base::h" << endl; } }; class Derive:public Base { public: //重写父类的f()虚函数 virtual void f() { cout << "Derive::f" << endl; } virtual void g1() { cout << "Derive::g1" << endl; } virtual void h1() { cout << "Derive::h1" << endl; } }; int main(void) { Base *p = NULL; //父类指针 Base b; //父类对象 Derive d; //子类对象 p = &b; //父类指针指向父类对象 p->f(); //运行结果:"Base::f" p = &d; //父类指针指向子类对象 p->f(); //运行结果:"Derive::f" return 0; }
有虚函数覆盖的虚函数表特点如下:
1)覆盖的f()函数被放到了虚表中原来父类虚函数的位置。
2)没有被覆盖的函数依旧。
本例中:
Base *p = NULL; //父类指针
p = &d; //父类指针指向子类对象
p->f(); //运行结果:"Derive::f"
由 p(即 &d)所指的内存中的父类虚函数表的 f() 的位置已经被实际子类Derive::f()函数地址所取代,于是在实际调用发生时,是 Derive::f() 被调用了。这就实现了多态。
更多操作实例,请点此链接:http://blog.csdn.net/tennysonsky/article/details/8264255
本教程示例代码下载请点此链接:http://download.csdn.net/detail/tennysonsky
本文转自:http://blog.csdn.net/haoel
版权声明:本博客文章,大多是本人整理编写,或在网络中收集,转载请注明出处!!
原文地址:http://blog.csdn.net/tennysonsky/article/details/49252679