经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
c++继承关系中成员函数的重载、重写、重定义之间的区别
来源:cnblogs  作者:半耳聆听  时间:2021/3/8 12:08:38  对本文有异议

1、Override、Overload、Redefine

  • Overload
    重载只能发生在类内部,不能发生在子类和父类的继承中。具体来说,如果子类中有父类同名、同返回值类型,但是不同参数列表,这两个在不同类的函数是不能发生重载的。

  • Override
    重写即就是子类将父类中的方法进行改写。在实例化Parent *p = new Son(),即创建指针类型为父类,指向子类空间的指针,能看到重写和重定义的区别。

  • Redefine
    重定义亦是发生在在继承的过程中,这个和重写容易发生混淆。主要区别根据父类中被重写或重定义的成员函数有无virtual关键字来讨论。如果没有virtual关键字,只要函数名相同,都会发生函数的重定义,或者说隐藏,即子类成员函数隐藏父类同名的成员函数;如果有virtual关键字,首先要保证返回值类型要相同(个人在测试中发现,在子类中,只有将保持返回值类型、函数名相同,才能进行下一步的重写或重定义),再判断是发生重载还是重定义,如果参数列表相同,则发生重写,如果不相同,则是重定义。


2、三者之间的区别

  • 重载 overload

    • 发生在相同的作用域(子类和父类不在同一个作用域)
    • 函数名要相同
    • 参数列表不同,包括参数类型、参数个数、参数的顺序
    • 有无virtual关键字都可以发生
    • 返回值可以不同
  • 重写 override

    • 不同的作用域(两个同名函数分别在父类和子类)
    • 相同的函数名
    • 相同的参数列表
    • 被重写父类中的成员函数必须有关键字'virtual'
    • 相同的返回值类型
    • 被重写的成员函数访问权限可以被修改,publicprotect 或者其他。
  • 重定义 redefine

    • 不同的作用域
    • 函数名相同
    • 返回值类型可以不同(没有关键字virtual的情况),但是如果有virtual关键字,必须保证返回类型相同,否则编译报错。
    • 父类函数没有关键字virtual,参数列表可同可不同;父类函数有关键字virtual,参数列表必须不同。

举个例子说明一下:

  1. class Base{
  2. public:
  3. int param3 = 0;
  4. void func1(){cout<<"This is Base::func1()"<<endl;}
  5. void func2(int a){cout<<"This is Base::func2(int a)"<<endl;}
  6. void func2(char c){cout<<"This is Base::func2(char c)"<<endl;}
  7. void func3(){cout<<"This is Base::func3()"<<endl;}
  8. virtual void func4(){cout<<"This is Base::func4()"<<endl;}
  9. virtual void func5(){cout<<"This is Base::func5()"<<endl;}
  10. virtual int func6(){cout<<"This is int Base::func6()"<<endl;}
  11. };
  12. class Son: public Base
  13. {
  14. public:
  15. int param = 1;
  16. int func1(){cout<<"This is Son::func1()"<<endl;}
  17. void func2(double e){cout<<"This is Son::func2()"<<endl;}
  18. void func3(){cout<<"This is Son::func3()"<<endl;}
  19. void func4(){cout<<"This is Son::func4()"<<endl;}
  20. void func5(int a){cout<<"This is Son::func5(int a)"<<endl;}
  21. // double func6(){cout<<"This is Son::func6()"<<endl;}
  22. };
  23. int main() {
  24. Son s;
  25. Base b;
  26. Base *bp = new Son();
  27. s.func1();
  28. s.func2(1.1);
  29. s.func2('c');
  30. s.func4();
  31. s.func5(2);
  32. cout<<"--------------------------------"<<endl;
  33. b.func1();
  34. b.func2(1);
  35. b.func2('c');
  36. b.func3();
  37. cout<<"--------------------------------"<<endl;
  38. bp->func1();
  39. bp->func2(1);
  40. bp->func2('e');
  41. bp->func3();
  42. bp->func4();
  43. bp->func5();
  44. return 0;
  45. }

输出如下:

  1. This is Son::func1()
  2. This is Son::func2()
  3. This is Son::func2()
  4. This is Son::func4()
  5. This is Son::func5(int a)
  6. --------------------------------
  7. This is Base::func1()
  8. This is Base::func2(int a)
  9. This is Base::func2(char c)
  10. This is Base::func3()
  11. --------------------------------
  12. This is Base::func1()
  13. This is Base::func2(int a)
  14. This is Base::func2(char c)
  15. This is Base::func3()
  16. This is Son::func4()
  17. This is Base::func5()

分别创建子类、父类、指针类型为父类指向子类空间的指针。(1)父类中的func2发生重载,主要在父类内部产生(应该说相同作用域),因为给s.func2('c')传入字符的时候,只会调用子类函数,不会调用父类的func2(char c)。而子类中的func2对父类的func2发生了重定义,并对其做了隐藏,所以调用的时候才会调用到子类的func2(double )。从s.func1()s.func2()s.func3()都发生了重定义,所以在继承的过程中,如果没有virtual关键字,只要函数名相同,不管参数类型、返回值类型,都会发生重定义。(2)针对有virtual关键字的情况,在函数名相同的情况下,首先要保证返回值类型相同,否则编译不过,如果参数列表相同,则发生重写,不同则发生重定义,例如bp->func4()bp->func5(),这里bp调用函数的处理取决于是否重写的函数(虚函数的特性)。


参考文献

原文链接:http://www.cnblogs.com/seasons2021/p/14477537.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号