目录
-
- 静态类型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 B 16 { 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(); //普通成员函数,静态绑定静态类型中的方法 33 34 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 Person 14 { 15 public: 16 virtual void print(){ 17 std::cout << "I‘m as Chinese" << endl; 18 } 19 20 }; 21 22 class American : public Person 23 { 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 }
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 Person 14 { 15 public: 16 virtual void print(){ 17 std::cout << "I‘m as Chinese" << endl; 18 } 19 virtual void foo2(){} 20 }; 21 class American : public Person 22 { 23 public: 24 virtual void print(){ 25 std::cout << "I‘m as American" << endl; 26 } 27 }; 28 //reference 29 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