第48课 同名覆盖引发的问题

Posted wanmeishenghuo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第48课 同名覆盖引发的问题相关的知识,希望对你有一定的参考价值。

父子间的赋值兼容:

技术分享图片

子类对象兼容性实验:

技术分享图片

第40行我们可以直接使用子类对象来初始化父类对象。这就是赋值兼容性。

 

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Parent
 7 {
 8 public:
 9     int mi;
10     
11     void add(int i)
12     {
13         mi += i;
14     }
15     
16     void add(int a, int b)
17     {
18         mi += (a + b);
19     }
20 };
21 
22 class Child : public Parent
23 {
24 public:
25     int mv;
26     
27     void add(int x, int y, int z)
28     {
29         mv += (x + y + z);
30     }
31 };
32 
33 int main()
34 {
35     Parent p;
36     Child c;
37     
38     p = c;
39     
40     Parent p1(c);
41     
42     
43     Parent& rp = c;
44     Parent* pp = &c;
45     
46     rp.mi = 100;
47     rp.add(5);             // 没有发生同名覆盖?
48     rp.add(10, 10);        // 没有发生同名覆盖?
49     
50     /* 为什么编译不过? */
51     // pp->mv = 1000;
52     // pp->add(1, 10, 100);
53     
54     return 0;
55 }

 47、48不会发生同名覆盖,因为rp本身就是父类类型的引用,只不过引用的对象是子类对象。47、48行会直接去父类中找add函数,所以不会报错。

51、52行同时找不到mv和带三个参数的函数。这是因为pp是父类指针,它只会去父类中找对应的成员和函数。

技术分享图片

使用父类指针或者引用绝对不能访问子类中的成员和函数。

 

特殊的同名函数:

技术分享图片

 

 

 在子类中重定义父类中已经存在的函数(名字和参数都一样),这叫函数重写,是特殊的同名覆盖。

函数重写是有必要的,因为对同一个函数,子类和父类可能表现出不同的动作。

思考:

当函数重写遇到赋值兼容会发生什么?

示例:

技术分享图片

第47行的函数,如果子类中定义了print,如37行所示,则会打印39行的语句。将子类中的print函数注释掉,这时47行的函数调用的就是父类中的print,打印输出就如上图。

父类对象调用print就会打印父类中的print:

技术分享图片

完善程序,添加全局打印函数:

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Parent
 7 {
 8 public:
 9     int mi;
10     
11     void add(int i)
12     {
13         mi += i;
14     }
15     
16     void add(int a, int b)
17     {
18         mi += (a + b);
19     }
20     
21     void print()
22     {
23         cout << "I‘m Parent." << endl;
24     }
25 };
26 
27 class Child : public Parent
28 {
29 public:
30     int mv;
31     
32     void add(int x, int y, int z)
33     {
34         mv += (x + y + z);
35     }
36     
37     void print()
38     {
39         cout << "I‘m Child." << endl;
40     }
41 };
42 
43 void how_to_print(Parent* p)
44 {
45     p->print();
46 }
47 
48 int main()
49 {
50     Parent p;
51     Child c;
52     
53     how_to_print(&p);    // Expected to print: I‘m Parent.
54     how_to_print(&c);    // Expected to print: I‘m Child.
55     
56     return 0;
57 }

 

 结果如下:

技术分享图片

我们期望53、54行一个打印父类信息、一个打印子类信息,但是结果并不是这样,而是全部打印的是父类信息。

问题分析:

技术分享图片

技术分享图片

编译器的这种处理方法是合理的,但不是我们期望的,我们之所以在子类中重定义一个同名的函数版本,就是因为父类中的这个函数满足不了我们的需求。但是,运行发现,实际调用的还是父类中的版本。也就是当函数重写遇上赋值兼容就出现了问题。下一节我们探究解决方案。

小结:

技术分享图片

 

以上是关于第48课 同名覆盖引发的问题的主要内容,如果未能解决你的问题,请参考以下文章

第48课 同名覆盖引发的问题------子类中函数重写遇上赋值兼容

第47课 父子间的冲突

第47课 父子间的冲突

同名覆盖引发的问题(四十一)

C++--同名覆盖多态

第15课 - make的隐式规则(上)