如何确定C++继承层次中的函数调用
1 ```cpp 2 3 4 //============================================================================ 5 // Name : TS.cpp 6 // Author : jiudianren 7 // Version : 8 // Copyright : Your copyright notice 9 // Description : Hello World in C++, Ansi-style 10 //============================================================================ 11 12 #include <iostream> 13 #include <functional> 14 15 using namespace std; 16 17 18 class A 19 { 20 protected: 21 int m_data; 22 public: 23 A(int data = 0) 24 { 25 m_data = data; 26 } 27 int GetData() 28 { 29 return doGetData(); 30 } 31 virtual int doGetData() 32 { 33 return m_data; 34 } 35 }; 36 37 38 39 class B: public A 40 { 41 protected: 42 int m_data; 43 public: 44 B(int data = 1) 45 { 46 m_data = data; 47 } 48 int doGetData() 49 { 50 return m_data; 51 } 52 }; 53 54 55 class C: public B 56 { 57 protected: 58 int m_data; 59 public: 60 C(int data = 2) 61 { 62 m_data = data; 63 } 64 65 int doGetData() 66 { 67 return m_data; 68 } 69 }; 70 71 void ref(C* & d) 72 { 73 cout<<d->GetData()<<endl; //题1 74 cout<<d->A::GetData()<<endl; //题2 75 cout<<d->B::GetData()<<endl; //题3 76 cout<<d->C::GetData()<<endl; //题4 77 78 cout<<d->doGetData()<<endl; //题5 79 cout<<d->A::doGetData()<<endl; //题6 80 cout<<d->B::doGetData()<<endl; //题7 81 cout<<d->C::doGetData()<<endl; //题8 82 } 83 int main() 84 { 85 C c(10); 86 cout<<c.GetData()<<endl; //题1 87 cout<<c.A::GetData()<<endl; //题2 88 cout<<c.B::GetData()<<endl; //题3 89 cout<<c.C::GetData()<<endl; //题4 90 91 cout<<c.doGetData()<<endl; //题5 92 cout<<c.A::doGetData()<<endl; //题6 93 cout<<c.B::doGetData()<<endl; //题7 94 cout<<c.C::doGetData()<<endl; //题8 95 96 cout<<"sssssssssss"<<endl; //题8 97 C *f=new C(11); 98 C *d=f; 99 cout<<d->GetData()<<endl; //题1 100 cout<<d->A::GetData()<<endl; //题2 101 cout<<d->B::GetData()<<endl; //题3 102 cout<<d->C::GetData()<<endl; //题4 103 104 cout<<d->doGetData()<<endl; //题5 105 cout<<d->A::doGetData()<<endl; //题6 106 cout<<d->B::doGetData()<<endl; //题7 107 cout<<d->C::doGetData()<<endl; //题8 108 109 cout<<"sssssssssss"<<endl; //题8 110 ref(f); 111 return 0; 112 } 113 114 115 ```
理解C++中继承层次的关键在于理解如何确定函数调用。确定函数调用遵循以下四个步骤:
(1) 首先确定进行函数调用的对象、引用或指针的静态类型。
(2) 在该类中查找函数,如果找不到,就在直接基类中查找,如此循着类的继承链往上找,直到找到该函数或者查找完最后一个类。如果不能在类或其相关类中找到该名字,则调用是错误的。
(3) 一旦找到了该名字,就进行常规类型检查,查看该函数调用是否合法。
(4) <i>若函数调用合法,编译器就生成代码。如果函数是虚函数且通过引用或指针调用,则编译器生成代码以确定根据对象的动态类型运行哪个函数版本,否则,编译器生成代码直接调用函数。
<ii>若函数调用不合法,则调用是错误的,且不再像(2)一样循着继承链往上找。
题1----题8
构造函数从最上层的基类开始构造,各个类的同名变量没有形成覆盖,都是单独的变量。
题1:
静态类型为C类,故在C类中找GetData()函数,C类中没有GetData()函数,由步骤(2),在其直接基类B类中查找,B类中也没有,再在A类中找,在A类中找到,且常规类型检查无误,调用合法,运行之。在其函数体类调用的doGetData()是虚函数,但不是通过引用或指针调用,故没有动态绑定,则由静态类型决定调用哪一个版本的doGetData(),静态类型为C类,C类中没有doGetData(),在其基类B类中找,找到,运行之,返回的是B::m_data,其值为默认实参值1。故本行输出1。
其他题类似,答案为1,1,1,1,1,0,1,1。