• 【C++基础入门】41.C++中父子间的冲突


    一、思考

            子类中是否可以定义父类中的同名成员?如果可以,如何区分?如果不可以,为什么?

            下面看一段代码:

    1. #include
    2. using namespace std;
    3. class Parent
    4. {
    5. public:
    6. int mi;
    7. };
    8. class Child
    9. {
    10. public:
    11. int mi;
    12. };
    13. int main()
    14. {
    15. Child c;
    16. c.mi = 100; //mi究竟是子类定义的,还是从父类继承得到的?
    17. return 0;
    18. }

            编译也可以正常通过,只是引出一个问题, mi究竟是子类定义的,还是从父类继承得到的?

    二、父子间的冲突

    • 子类可以定义父类中的同名成员
    • 子类的成员将隐藏父类中的同名成员
    • 父类中的同名成员依然存在于子类中
    • 通过作用域分辨符( :: )访问父类中的同名成员
    • 访问父类中的同名成员

            下面看一段代码:

    1. #include
    2. using namespace std;
    3. class Parent
    4. {
    5. public:
    6. int mi;
    7. Parent()
    8. {
    9. cout << "Parent() : " << "&mi = " << &mi << endl;
    10. }
    11. };
    12. class Child : public Parent
    13. {
    14. public:
    15. int mi;
    16. Child()
    17. {
    18. cout << "Child() : " << "&mi = " << &mi << endl;
    19. }
    20. };
    21. int main()
    22. {
    23. Child c;
    24. c.mi = 100;
    25. c.Parent::mi = 1000;
    26. cout << "&c.mi = " << &c.mi << endl;
    27. cout << "c.mi" << c.mi << endl;
    28. cout << "&c.Parent::mi = " << &c.Parent::mi << endl;
    29. cout << "c.mi = " << c.Parent::mi << endl;
    30. return 0;
    31. }

             输出结果如下:

            通过打印信息中父类和子类中 mi 的地址可以看出,通过直接访问的方式访问的 mi 是子类中的 mi , 使用父类的作用域分辨符访问的 mi 是父类中的 mi

    三、再论重载

            下面看一段代码:

    1. #include
    2. using namespace std;
    3. class Parent
    4. {
    5. public:
    6. int mi;
    7. void add(int v)
    8. {
    9. mi += v;
    10. }
    11. void add(int a, int b)
    12. {
    13. mi += (a + b);
    14. }
    15. };
    16. class Child : public Parent
    17. {
    18. public:
    19. int mi;
    20. void add(int x, int y, int z)
    21. {
    22. mi += (x + y + z);
    23. }
    24. };
    25. int main()
    26. {
    27. Child c;
    28. c.mi = 100;
    29. c.Parent::mi = 100;
    30. cout << "c.mi = " << c.mi << endl;
    31. cout << "c.Parent:: mi = " << c.Parent::mi << endl;
    32. c.add(1);
    33. c.add(2, 3);
    34. c.add(4, 5, 6);
    35. cout << "c.mi = " << c.mi << endl;
    36. cout << "c.Parent::mi = " << c.Parent::mi << endl;
    37. return 0;
    38. }

            编译后报错,输出如下: 

    • 这是因为子类中定义的同名成员函数会覆盖父类中的同名成员函数, 产生的效果是父类中的两个add函数被隐藏,无法通过子类对象访问调用
    • 这也不是重载,因为函数重载必须发生在同一个作用域中,因此这里发生的是同名覆盖
    •  类中的成员函数可以进行重载
      • 重载函数的本质为多个不同的函数
      • 函数名参数列表是唯一的标识
      • 函数重载必须发生在同一个作用域中

            问题:子类中定义的函数是否能重载父类中的同名函数?(答案是不能,因为子类和父类不在同一作用域)

           要想代码能够正常编译通过,解决方法就是加上作用域分辨符,如下:

    1. #include
    2. using namespace std;
    3. class Parent
    4. {
    5. public:
    6. int mi;
    7. void add(int v)
    8. {
    9. mi += v;
    10. }
    11. void add(int a, int b)
    12. {
    13. mi += (a + b);
    14. }
    15. };
    16. class Child : public Parent
    17. {
    18. public:
    19. int mi;
    20. void add(int x, int y, int z)
    21. {
    22. mi += (x + y + z);
    23. }
    24. };
    25. int main()
    26. {
    27. Child c;
    28. c.mi = 100;
    29. c.Parent::mi = 1000;
    30. cout << "c.mi = " << c.mi << endl;
    31. cout << "c.Parent:: mi = " << c.Parent::mi << endl;
    32. c.Parent::add(1);
    33. c.Parent::add(2, 3);
    34. c.add(4, 5, 6);
    35. cout << "c.mi = " << c.mi << endl;
    36. cout << "c.Parent::mi = " << c.Parent::mi << endl;
    37. return 0;
    38. }

            输出结果如下:


    四、结论

    • 子类中的函数将隐藏父类的同名函数
    • 子类无法重载父类中的成员函数
    • 使用作用域分辨符访问父类中的同名函数
    • 子类可以定义父类中完全相同的成员函数

            对于子类可以定义父类中完全相同的成员函数,可以通过下面的代码表示:

    1. #include
    2. using namespace std;
    3. class Parent
    4. {
    5. public:
    6. int mi;
    7. void add(int v)
    8. {
    9. mi += v;
    10. }
    11. void add(int a, int b)
    12. {
    13. mi += (a + b);
    14. }
    15. };
    16. class Child : public Parent
    17. {
    18. public:
    19. int mi;
    20. void add(int v)
    21. {
    22. mi += v;
    23. }
    24. void add(int a, int b)
    25. {
    26. mi += (a + b);
    27. }
    28. void add(int x, int y, int z)
    29. {
    30. mi += (x + y + z);
    31. }
    32. };
    33. int main()
    34. {
    35. Child c;
    36. c.mi = 100;
    37. c.Parent::mi = 1000;
    38. cout << "c.mi = " << c.mi << endl;
    39. cout << "c.Parent:: mi = " << c.Parent::mi << endl;
    40. c.add(1);
    41. c.add(2, 3);
    42. c.add(4, 5, 6);
    43. cout << "c.mi = " << c.mi << endl;
    44. cout << "c.Parent::mi = " << c.Parent::mi << endl;
    45. return 0;
    46. }

            输出结果如下: 

    五、小结

    • 子类可以定义父类中的同名成员
    • 子类中的成员将隐藏父类中的同名成员
    • 子类和父类中的函数不能构成重载关系
    • 子类可以定义父类中完全相同的成员函数
    • 使用作用域分辨符访问父类中的同名成员
       
  • 相关阅读:
    report | 使用 Docker版的 gitbook 把 markdown 转为 html 报告 (静态站点)
    FFMPEG命令
    7-7 温度转换v1.02
    SpringMVC之前端增删改查实现
    L16.linux命令每日一练 -- 第三章 文件过滤及内容编辑处理命令 -- cat和tac命令
    Transformer-2. 注意力分数
    SpringBoot框架分层(View层、Controller层、Service层、Mapper层、pojo层)
    Arc length
    TLS指纹校验原理和绕过
    Python 常用的开源爬虫库介绍
  • 原文地址:https://blog.csdn.net/weixin_43129713/article/details/133504392