首页 > 代码库 > C++中虚函数的动态绑定和多态性

C++中虚函数的动态绑定和多态性

目录

    • 静态类型VS动态类型,静态绑定VS动态绑定两组概念
    • 虚函数的实现机制
    • 多态性

一.静态 vs 动态

  静态类型 VS 动态类型。静态类型指的是对象声明的类型,在编译器确定的。动态类型指的是对象的所指向的类型,动态类型是可以更改的,静态类型无法更改。继承关系会导致对象的指针和引用具有静态类型和动态类型,因为继承关系的存在中可能会存在类型之间的向上向下类型转换。静态绑定 VS 动态绑定。某特性(函数)依赖与对象的静态类型,在编译期确定,某特性(函数)依赖于对象的动态类型,在运行期确定。只有通过基类的引用或者指针调用虚函数时,才能发生动态绑定,如果使用对象来操作虚函数的话,仍然会采用静态绑定的方式。因为引用或者指针既可以指向基类对象,也可以指向派生类对象的基类部分,用引用或者指针调用的虚函数例如下面的例子中,pd的静态类型是D*,pb的静态类型是B*,是在编译器确定的;pd和pb的动态类型都是D*。DoSomething()普通的成员函数是在编译器静态绑定的,调用各自的静态类型中的方法。vfun()是虚成员函数,虚函数是动态绑定的,因此调用动态类型的方法,也就是D类型中vfun。

 1 #include <iostream> 2 using namespace std; 3  4 class B 5 { 6 public: 7     void DoSomething(){ 8         std::cout << "B::DoSomething()" << endl; 9     }10     virtual void vfun(){11         std::cout << "B::vfun()" << endl;12     }13 };14 15 class D : public B16 {17 public:18     void DoSomething(){19         std::cout << "D::DoSomething()" << endl;20     }21     virtual void vfun(){22         std::cout << "D::vfun()" << endl;23 24     }25 };26 27 int main()28 {29     D* pd = new D();       //指针存在注意静态类型和动态类型30     B* pb = pd;            //指正注意静态类型和动态类型31     pd->DoSomething();     //普通成员函数,静态绑定静态类型中的方法32     pb->DoSomething();     //普通成员函数,静态绑定静态类型中的方法3334     pd->vfun();            //虚成员函数,动态绑定到动态类型中的方法35     pb->vfun();        //虚成员函数,动态绑定到动态类型中的方法36     return 0;37 }

二.虚函数的的实现机制

 

二、C++多态性

1.多态性的定义:同一操作作用于不同的对象,可以有不同的解释,即产生不同的执行效果。多态性有两种,编译时的多态,也就是函数重载;运行时多态,在系统运行时确定,是通过虚成员实现的。一般指的是后者

2.典型用例

技术分享
 1 #include <iostream> 2 using namespace std; 3  4 class Person 5 { 6 public: 7     virtual void print(){ 8         std::cout << "I‘m a person" << endl; 9     }10    11 };12 13 class Chinese : public Person14 {15 public:16     virtual void print(){17         std::cout << "I‘m as Chinese" << endl;18     }19    20 };21 22 class American : public Person23 {24 public:25     virtual void print(){26         std::cout << "I‘m as American" << endl;27     }28    29 };30 31 32 //reference 33 void printPerson(Person& person){34     person.print();35 }36 //pointer 37 void printPerson(Person* p){38     p->print();39 }40 int main()41 {42     Person p;43     Chinese c;44     American a;45     printPerson(p);46     printPerson(c);47     printPerson(a);48 49     printPerson(&p);50     printPerson(&c);51     printPerson(&a);52     53     return 0;54 }
View Code

4.多态的实现:多态是由继承和虚函数实现的,因为虚函数是动态绑定的,依赖于调用对象(静态类型为基类的指针和引用)的动态类型,所以根据动态类型的不同,而导致操作不同,也就是多态性。

3.虚函数的实现:简单的说虚函数是通过虚函数表来实现的。

   每个带有虚函数的类,都会有一个虚函数表(vtbl),表中的每一项记录它一个的虚函数的地址。实际上一个函数指针的数组。类的对象的最前面存储虚函数表的地址。

   虚函数表在类的继承中也会继承和重写,当有重写发生时,就会产生多态性。

 1 #include <iostream> 2 using namespace std; 3 class Person 4 { 5 public: 6     virtual void print(){ 7         std::cout << "I‘m a person" << endl; 8     } 9     virtual void foo(){}  11 };12 13 class Chinese : public Person14 {15 public:16     virtual void print(){17         std::cout << "I‘m as Chinese" << endl;18     }19     virtual void foo2(){} 20 };21 class American : public Person22 {23 public:24     virtual void print(){25         std::cout << "I‘m as American" << endl;26     }  27 };28 //reference29 void printPerson(Person& person){30     person.print();31 }32 //pointer 33 void printPerson(Person* p){34     p->print();35 }36 int main()37 {38     Person p;39     Chinese c;40     American a;41     printPerson(&p);42     printPerson(&c);43     printPerson(&a);    44     return 0;45 }

 

Person 类的vtbl : Person::print()的地址,Person::foo()的地址

Chinese类的地址:Chinese::print()的地址,Person::foo()的地址,Person::foo1()的地址

American类的地址:American::print()的地址,Person::foo()的地址

三、总结

  多态是C++的三大特性之一,非常重要,产生的条件是继承关系,基类中存在虚成员函数,派生类override(重写覆盖)基类的的虚成员函数,在代码上表现为基类对象的指针或引用调用虚成员函数,运行结果表现为实际调用各自派生类重写的函数。

多态的核心虚成员函数是动态绑定的,即依赖于对象的动态类型。理解多态的难点是虚函数的实现机制,即虚函数表。

 

参考:http://blog.csdn.net/chgaowei/article/details/6427731

 

C++中虚函数的动态绑定和多态性