48-同名覆盖引发的问题
父子间的赋值兼容
子类对象可以当作父类对象使用(兼容性):
1、子类对象可以直接赋值给父类对象
2、子类对象可以直接初始化父类对象
3、父类指针可以直接指向子类对象
4、父类引用可以直接引用子类对象
【范例代码】子类对象的兼容性
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Parent { 7 public: 8 int mi; 9 10 void add(int i) { 11 mi += i; 12 } 13 14 void add(int a, int b) { 15 mi += (a + b); 16 } 17 }; 18 19 class Child : public Parent { 20 public: 21 int mv; 22 23 void add(int x, int y, int z) { 24 mv += (x + y + z); 25 } 26 }; 27 28 int main(int argc, const char* argv[]) { 29 Parent p; 30 Child c; 31 32 p = c; 33 34 Parent p1(c); 35 36 Parent& rp = c; 37 Parent* pp = &c; 38 39 rp.mi = 100; 40 rp.add(5); // 没有发生同名覆盖? 41 rp.add(10, 10); // 没有发生同名覆盖? 42 43 /* 为什么编译不过? */ 44 // pp->mv = 1000; 45 // pp->add(1, 10, 100); 46 47 return 0; 48 }
当使用父类指针(引用)指向子类对象时:
1、子类对象退化父类对象
2、只能访问父类中定义的成员
3、可以直接访问被子类覆盖的同名成员
特殊的同名函数
1、子类中可以重定义父类中已经存在的成员函数
2、这种重定义发生在继承中,叫做函数重写
3、函数重写是同名覆盖的一种特殊情况
【思考】当函数重写遇上赋值兼容会发生什么?
【范例代码】赋值兼容的问题
1 #include <iostream> 2 #include <string> 3 4 using namespace std; 5 6 class Parent { 7 public: 8 int mi; 9 10 void add(int i) { 11 mi += i; 12 } 13 14 void add(int a, int b) { 15 mi += (a + b); 16 } 17 18 void print() { 19 cout << "I'm Parent." << endl; 20 } 21 }; 22 23 class Child : public Parent { 24 public: 25 int mv; 26 27 void add(int x, int y, int z) { 28 mv += (x + y + z); 29 } 30 31 void print() { 32 cout << "I'm Child." << endl; 33 } 34 }; 35 36 void how_to_print(Parent* p) { 37 p->print(); 38 } 39 40 int main(int argc, const char* argv[]) { 41 Parent p; 42 Child c; 43 44 how_to_print(&p); // Expected to print: I'm Parent. 45 how_to_print(&c); // Expected to print: I'm Child. 46 47 return 0; 48 }
问题分析:
1、编译期间,编译器只能根据指针的类型判断所指向的对象
2、根据赋值兼容,编译器认为父类指针指向的是父类对象
3、因此,编译结果只可能是调用父类中定义的同名函数
【问题】编译器的处理方法是合理的吗?是期望的吗?