欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C++继承中的同名覆盖

程序员文章站 2022-04-09 09:21:16
1,父子间的冲突是由继承带来的,两个类之间存在了继承的关系,必然的会带来一 些问题,本文要讨论的是父子之间成员变量或成员函数的命名问题; 2,思考: 1,子类中是否可以定义父类中的同名成员? 1,可以,本文先编程解决这个问题; 2,这个问题就是同名覆盖问题; 2,如果可以,如何区分?如果不可以,为什 ......

1,父子间的冲突是由继承带来的,两个类之间存在了继承的关系,必然的会带来一 些问题,本文要讨论的是父子之间成员变量或成员函数的命名问题;

 

2,思考:

    1,子类中是否可以定义父类中的同名成员?

       1,可以,本文先编程解决这个问题;

       2,这个问题就是同名覆盖问题;

    2,如果可以,如何区分?如果不可以,为什么?

   

3,同名成员变量编程实验:

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class parent
 7 {
 8 public:
 9     int mi;
10 };
11 
12 class child : public parent
13 {
14 public:
15     int mi;  // 编译结果通过,子类可以定义父类里面的同名变量;
16 };
17 
18 int main()
19 {
20     child c;
21     
22     c.mi = 100;    // mi 究竟是子类自定义的,还是从父类继承得到的?
23     
24     return 0;
25 }

   

4,父子间的冲突(同名覆盖):

    1,子类可以定义父类中的同名成员;

    2,子类中的成员将隐藏父类中的同名成员;

       1,编译器认为已经从父类中继承得到这个成员了,又自定义了一个同名成员,目的只有一个,就是你想要自己自定义的同名成员、而不想要从父类那里继承得到的同名成员,因此会产生同名覆盖现象;

    3,父类中的同名成员依然存在于子类中;

       1,隐藏、不是销毁;

    4,通过作用域分辨符(::)访问父类中的同名成员;

   

5,访问父类中的同名成员方式:

    1,child c;

    2,c.mi = 100;  // 子类中的 mi;

    3,c.parent::mi = 1000;  // 父类中的 mi;

   

6,同名成员变量深度分析编程实验:

 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 namespace a
 7 {
 8     int g_i = 0;
 9 }
10 
11 namespace b
12 {
13     int g_i = 1;  // 同名的全局变量,但是位于两个不同的命名空间;
14 }
15 
16 class parent
17 {
18 public:
19     int mi;
20     
21     parent()
22     {
23         cout << "parent() : " << "&mi = " << &mi << endl;
24     }
25 };
26 
27 class child : public parent
28 {
29 public:
30     int mi;  // 编译器没有简单的对同名成员报错,是因为作用域,虽然两个成员的名字相同,但是出于不同的作用域当中;同命名空间的本质是一样的;
31     
32     child()
33     {
34         cout << "child() : " << "&mi = " << &mi << endl;
35     }
36 };
37 
38 int main()
39 {
40     child c;  // parent() : &mi = 0xbfb43a08    child() : &mi = 0xbfb43a0c
41     
42     c.mi = 100;    
43     
44     c.parent::mi = 1000;
45     
46     cout << "&c.mi = " << &c.mi << endl;  // &c.mi = 0xbfb43a0c,证明直接访问的是子类的 mi;  
47     cout << "c.mi = " << c.mi << endl;  // c.mi = 100;
48     
49     cout << "&c.parent::mi = " << &c.parent::mi << endl;  // &c.parent::mi = 0xbfb43a08;  作用域分辨符访问父类 mi;
50     cout << "c.parent::mi = " << c.parent::mi << endl;  // c.parent::mi = 1000;
51     
52     return 0;
53 }

    1,父类和子类可以产生同名覆盖冲突,但是通过作用域分辨符可以解决这个问     题;

   

7,再论重载:

    1,类中的成员函数可以进行重载:

       1,重载函数的本质为多个不同的函数;

       2,函数名和参数列表是唯一的标识;

       3,函数重载必须发生在同一个作用域中;

      

8,问题:

    1,子类中定义的函数是否能重载父类中的同名函数?

       1,将父子间的冲突问题上升到成员函数了;

   

9,父子间的函数重载编程实验:

    1,继承父类成员函数,累加父类的同名成员;

 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 v)
12     {
13         mi += v;
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 mi;
26 };
27 
28 int main()
29 {
30     child c;
31     
32     c.mi = 100;    
33     
34     c.parent::mi = 1000;
35     
36     cout << "c.mi = " << c.mi << endl;  // c.mi = 100;
37     
38     cout << "c.parent::mi = " << c.parent::mi << endl;  // c.parent::mi = 1000;
39     
40     c.add(1);  // 继承自父类的成员函数;这个函数得到的 mi 不知道后面还要定义一个子类,它知道的 mi 只是父类中的,这个时候 mi 的作用域在父类中,所以给了父类中的 mi 做累加;
41     c.add(2, 3);  // 继承自父类的成员函数;
42     
43     cout << "c.mi = " << c.mi << endl;  // c.mi = 100;
44     
45     cout << "c.parent::mi = " << c.parent::mi << endl;  // c.parent::mi = 1006;累加到父类中的 mi 了;
46     
47     return 0;
48 }

    2,函数的同名覆盖:

 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 v)
12     {
13         mi += v;
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 mi;
26     
27     void add(int x, int y, int z)
28     {
29         mi += (x + y + z);
30     }
31 };
32 
33 int main()
34 {
35     child c;
36     
37     c.mi = 100;    
38     
39     c.parent::mi = 1000;
40     
41     cout << "c.mi = " << c.mi << endl;  // c.mi = 100;
42     
43     cout << "c.parent::mi = " << c.parent::mi << endl;  // c.parent::mi = 1000;
44     
45     // c.add(1);  // 编译器显示没有匹配的函数调用 child::add(int);同名成员函数覆盖,并没有重载,作用域不同;
46     // c.add(2, 3);  // 编译器显示没有匹配的函数调用 child::add(int, int);同名成员函数覆盖,并没有重载,作用域不同;
47     
48     c.parent::add(1);  // 作用域分辨符解决同名成员函数覆盖问题;
49     c.parent::add(2, 3);  // 作用域分辨符解决同名成员函数覆盖问题;累加父类中的 mi
50     
51     c.add(4, 5, 6);  // 调用子类中的 add(),默认情况下访问的就是子类中的 mi,这个地方发生了同名覆盖;
52     
53     cout << "c.mi = " << c.mi << endl;  // c.mi = 115;默认访问的 mi 是子类中的 mi;
54     
55     cout << "c.parent::mi = " << c.parent::mi << endl;  // c.parent::mi = 1006;前两次累加的是父类中的 mi;
56     
57     return 0;
58 }

   

10,父子间的冲突:

    1,子类中的函数将隐藏父类的同名函数;

    2,子类无法重载父类中的成员函数;

       1,因为它们处于不同的作用域;

    3,使用作用域分辨符访问父类中的同名函数;

       1,类名加上作用域分辨符;

    4,子类可以定义父类中完全相同的成员函数;

 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 v)
12     {
13         mi += v;
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 mi;
26     
27     void add(int v)  // 同名覆盖;函数重写;
28     {
29         mi += v;
30     }
31     
32     void add(int a, int b)  // 同名覆盖;函数重写;
33     {
34         mi += (a + b);
35     }
36     
37     void add(int x, int y, int z)  // 重载;
38     {
39         mi += (x + y + z);
40     }
41 };
42 
43 int main()
44 {
45     child c;
46     
47     c.mi = 100;    
48     
49     c.parent::mi = 1000;
50     
51     cout << "c.mi = " << c.mi << endl;  // c.mi = 100;
52     
53     cout << "c.parent::mi = " << c.parent::mi << endl;  // c.parent::mi = 1000;
54     
55     c.add(1);  // 同名覆盖;
56     c.add(2, 3);  // 同名覆盖;
57     c.add(4, 5, 6);  // 函数重载;
58     
59     cout << "c.mi = " << c.mi << endl;  // c.mi = 121;函数同名覆盖和重载,都是默认访问的子类的 mi;
60     
61     cout << "c.parent::mi = " << c.parent::mi << endl;  // 父类中的函数被同名覆盖,未有访问父类中的 mi;
62     
63     return 0;
64 }

   

11,小结:

    1,子类可以定义父类中的同名成员;

    2,子类中的成员将隐藏父类中的同名成员;

       1,包括同名成员变量和同名成员函数;

       2,重写的依据;

       3,这就是同名覆盖;

    3,子类和父类中的函数不能构成重载关系;

       1,作用域不同;

    4,子类可以定义父类中完全相同的成员函数;

       1,作用域不同;

    5,使用作用域分辨符访问父类中的同名成员;

       1,父类名加上作用域分辨符;