C++继承中的同名覆盖
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,父类名加上作用域分辨符;
下一篇: 十天学会php(1)