C++中的重载、覆盖、隐藏介绍
前几天面试时被问及C中的覆盖、隐藏概念基本答不上来只答了怎么用指针实现多态也还有遗漏。最终不欢而散。回来后在网上查找学习了一番做了这个总结。其中部分文字借用了别人的博客望不要见怪。概念一、重载overload指函数名相同但是它的参数表列个数或顺序类型不同。但是不能靠返回类型来判断。1相同的范围在同一个作用域中 2函数名字相同3参数不同4virtual 关键字可有可无。5返回值可以不同二、重写也称为覆盖 override是指派生类重新定义基类的虚函数特征是1不在同一个作用域分别位于派生类与基类 2函数名字相同3参数相同4基类函数必须有 virtual 关键字不能有 static 。5返回值相同或是协变否则报错—-协变这个概念我也是第一次才知道…6重写函数的访问修饰符可以不同。尽管 virtual 是 private 的派生类中重写改写为 public,protected 也是可以的三、重定义也成隐藏1不在同一个作用域分别位于派生类与基类 2函数名字相同3返回值可以不同4参数不同。此时不论有无 virtual 关键字基类的函数将被隐藏注意别与重载以及覆盖混淆 。5参数相同但是基类函数没有 virtual关键字。此时基类的函数被隐藏注意别与覆盖混淆 。例子12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970#include iostreamusingnamespacestd;classSParent{public:SParent( ){};SParent(constSParent p ){cout parent copy construct endl;}intadd(inta,intb ){cout parent int add endl;returna b;}doubleadd(doublea,doubleb ){cout parent double add endl;returna b;}virtualintdec(inta,intb ){cout parent int dec endl;returna - b;}};classSChild :publicSParent{public://using SParent::add;floatadd(floata,floatb ){cout child float add endl;returna b;}intdec(inta,intb){cout child int dec endl;returna - b;}};intmain(){/* 测试重载 */SParent parent;parent.add( 3,5 );parent.add( (double)3,(double)5 );cout endl;/* 测试覆盖 */SChild *pchild (SChild *)newSParent();/* 基类强转为子类...危险...,用dynamic_cast转换也不行 */pchild-dec( 10,3 );SParent *pparent newSChild();pparent-dec( 11,3 );cout endl;/* 测试隐藏 */SChild child;child.add( (int)3,(int)5 );cout endl;/* 测试函数表 */((SParent *)NULL)-add( 4,6 );((SChild *)NULL)-add( 4,6 );inta 0;((SChild *)a)-add( 4,6 );cout endl;/* 测试函数地址 */((SParent)child).add( (int)4,(int)8 );child.SParent::add( 3,5 );return0;}输出结果12345678910111213141516parentintaddparentdoubleaddparentintdecchildintdecchildfloataddparentintaddchildfloataddchildfloataddparent copy constructparentintaddparentintadd按 RETURN 来关闭窗口...理解int SParent::add(int a,int b)与double SParent::add( double a,double b )是重载int SParent::add(int a,int b)与double SParent::add( double a,double b )都被子类SChild中的float SChild::add( float a,float b )隐藏int SParent::dec( int a,int b )被子类SChild中的int SChild::dec( int a,int b )覆盖测试1.重载测试简单易懂略过。2.覆盖测试。dec函数在基类、子类中同名同参为虚函数故称覆盖。SChild *pchild (SChild *)new SParent()创建的是一个基类对象其函数表应该为SParent *pparent new SChild();创建一个子类对象其函数表应该为由上面的函数表可见当发生覆盖时子类的函数名会把基类的同名函数覆盖(这也就是为什么叫覆盖的原因吧)。这样我们可以利用一个指向子类的基类指针实现多态。但重点只有一个就是函数表里到底指向谁(不管这个指针经过转换后是什么类型的).故输出分别为父类、子类。这是一个运行时多态。3.隐藏测试int SParent::add(int a,int b)与double SParent::add( double a,double b )都被子类SChild中的float SChild::add( float a,float b )覆盖是因为他们同名而且在不同的作用域中(基类、子类作用域是不同的)。child.add( (int)3,(int)5 );这行代码中编译器在子类中查找add函数只找到了一个(基类的add(int a,int b)会被编译根据隐藏规则略过再根据隐式类型转换发现该函数适用。如果无法隐式转换则编译不过。隐藏的原因防止隐式类型转换造成错误。比如int也是可以转换成char的假如基类有一函数add(char a,char b)子类也有一函数add(double a,double b)。程序员想着在子类隐式把int转换为double但编译器可能调的是基类的。这也防止了一些库或封装好的基类对程序员造成困扰。像上面的代码如果你确实需要基类的函数可以用using SParent:add。则把基类的add函数域扩大到了子类构成重载。4.函数表测试上面我们说到函数表这个是在编译时定好的程序运行时加载到内存中。这意味着我们可以直接通过地址去调用函数。所以((SChild *)NULL)-add( 4,6 );这种代码也是能运行通过的。网上还有人通过计算直接取到了函数表的地址直接调用了。但这种代码不安全不规范不说还有个更大的问题。当成员函数里需要调用成员变量时通过这种假的对象指针肯定找不到成员变量表直接访问了非法内存。5.函数地址测试有了隐藏、覆盖哪么我们要怎么调用被隐藏、覆盖的函数呢。下面有两种方法((SParent)child).add( (int)4,(int)8 );child.SParent::add( 3,5 );第一种是比较低效的方法。事实上它是通过拷贝构造函数生成一个临时的基类变量去调用基类的add函数。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2623084.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!