C++ 重载 覆盖 隐藏
- 格式:doc
- 大小:24.50 KB
- 文档页数:2
C++基类指针和派⽣类指针之间的转换⽅法讲解函数重载、函数隐藏、函数覆盖函数重载只会发⽣在同作⽤域中(或同⼀个类中),函数名称相同,但参数类型或参数个数不同。
函数重载不能通过函数的返回类型来区分,因为在函数返回之前我们并不知道函数的返回类型。
函数隐藏和函数覆盖只会发⽣在基类和派⽣类之间。
函数隐藏是指派⽣类中函数与基类中的函数同名,但是这个函数在基类中并没有被定义为虚函数,这种情况就是函数的隐藏。
所谓隐藏是指使⽤常规的调⽤⽅法,派⽣类对象访问这个函数时,会优先访问派⽣类中的这个函数,基类中的这个函数对派⽣类对象来说是隐藏起来的。
但是隐藏并不意味这不存在或完全不可访问。
通过 b->Base::func()访问基类中被隐藏的函数。
函数覆盖特指由基类中定义的虚函数引发的⼀种多态现象。
在某基类中声明为 virtual 并在⼀个或多个派⽣类中被重新定义的成员函数,⽤法格式为:virtual 函数返回类型函数名(参数表) {函数体};实现多态性,通过指向派⽣类的基类指针或引⽤,访问派⽣类中同名覆盖成员函数。
函数覆盖的条件:1:基类中的成员函数被virtual关键字声明为虚函数;2:派⽣类中该函数必须和基类中函数的名称、参数类型和个数等完全⼀致;3:将派⽣类的对象赋给基类指针或者引⽤,实现多态。
函数覆盖(多态)实现了⼀种基类访问(不同)派⽣类的⽅法。
我们把它称为基类的逆袭。
基类指针和派⽣类指针之间的转换1. 基类指针指向基类对象、派⽣类指针指向派⽣类对象这种情况是常⽤的,只需要通过对应类的指针直接调⽤对应类的功能就可以了。
#include<iostream>using namespace std;class Father{public:void print(){printf("Father's function!");}};class Son:public Father{public:void print(){printf("Son's function!");}};int main(){Father f1;Son s1;Father* f = &f1;Son* s = &s1;f->print();cout<<endl<<endl;s->print();}2. 基类指针指向派⽣类对象这种情况是允许的,通过定义⼀个基类指针和⼀个派⽣类对象,把基类指针指向派⽣类对象,但是需要注意,通常情况这时的指针调⽤的是基类的成员函数。
java的重载、覆盖和隐藏的区别重载:方法名相同,但参数不同的多个同名函数注意:1.参数不同的意思是参数类型、参数个数、参数顺序至少有一个不同2.返回值和异常以及访问修饰符,不能作为重载的条件(因为对于匿名调用,会出现歧义,例子:void a ()和int a() ,如果调用a(),是调用哪个a()不懂,出现歧义,编译出错)3.main方法也是可以被重载的覆盖:子类重写父类的方法,要求方法名和参数类型完全一样(参数不能是子类),返回值和异常比父类小或者相同(即为父类的子类),访问修饰符比父类大或者相同两同两小一大注意:子类实例方法不能覆盖父类的静态方法(This instance method cannot override the static method from Parent)编译时报错子类的静态方法也不能覆盖父类的实例方法(This static method cannot hide the instance method from Parent)(编译时报错),总结为方法不能交叉覆盖注:jdk解释为静态方法不能隐藏父类的实例方法隐藏:父类和子类拥有相同名字的属性或者方法时,父类的同名的属性或者方法形式上不见了,实际是还是存在的注意:当发生隐藏的时候,声明类型是什么类,就调用对应类的属性或者方法,而不会发生动态绑定方法隐藏只有一种形式,就是父类和子类存在相同的静态方法属性只能被隐藏,不能被覆盖子类实例变量/静态变量可以隐藏父类的实例/静态变量,总结为变量可以交叉隐藏隐藏和覆盖的区别:被隐藏的属性,在子类被强制转换成父类后,访问的是父类中的属性被覆盖的方法,在子类被强制转换成父类后,调用的还是子类自身的方法因为覆盖是动态绑定,是受RTTI(run time type identification,运行时类型检查)约束的,隐藏不受RTTI约束,总结为RTTI只针对覆盖,不针对隐藏特殊情况:1.final修饰的属性可以被隐藏,但是不能被赋值,即不能用=来赋值,网上说final 属性不能被修改,这个说法不准确,因为对于引用类型的变量用final修饰后,它只是不能被指向其他对象,但是可以改它自身的值,可以用ArrayList测试,final属性可以在运行的时候进行初始化,但是不能不出现初始化语句2.final修饰的方法不能被覆盖,可以被重载3.final修饰的类不能被继承4.private 方法隐式添加了final。
C++类成员函数的重写、重载和隐藏重载(overload)重载的定义为:在同⼀作⽤域中,同名函数的形式参数(参数个数、类型或者顺序)不同时,构成函数重载。
例如:class A{public: int func(int a); void func(int a, int b); void func(int a, int b, int c); int func(char* pstr, int a);};以上的四个函数均构成重载。
需要注意的是: 1.函数返回值类型与构成重载⽆任何关系 2.类的静态成员函数与普通成员函数可以形成重载 3.函数重载发⽣在同⼀作⽤域,如类成员函数之间的重载、全局函数之间的重载这⾥还需要注意⼀下 const重载:class D{public: void funcA(); //1 void funcA() const; //2 void funcB(int a); //3 void funcB(const int a); //4};在类D 中 funcA 与 const funcA是合法的重载,⽽两个 funcB 函数是⾮法的,不能通过编译。
原因是:顶层const不影响重载性,因为值传递的拷贝特性,想函数内传递的值类型形参的变化不会影响实参,所以有⽆const 对其⽽⾔是没有意义的。
调⽤规则:const对象默认调⽤const成员函数,⾮const对象默认调⽤⾮const成员函数;隐藏(hiding)隐藏定义:指不同作⽤域中定义的同名函数构成隐藏(不要求函数返回值和函数参数类型相同)。
⽐如派⽣类成员函数隐藏与其同名的基类成员函数、类成员函数隐藏全局外部函数。
例如:void hidefunc(char* pstr){ cout << "global function: " << pstr << endl;}class HideA{public: void hidefunc(){ cout << "HideA function" << endl; } void usehidefunc(){ //隐藏外部函数hidefunc,使⽤外部函数时要加作⽤域 hidefunc(); ::hidefunc("lvlv"); }};class HideB : public HideA{public: void hidefunc(){ cout << "HideB function" << endl; } void usehidefunc(){ //隐藏基类函数hidefunc,使⽤外部函数时要加作⽤域 hidefunc(); HideA::hidefunc(); }};隐藏的实质是;在函数查找时,名字查找先于类型检查。
1.override(重写)和overload(重载)的区别?答:override 表示重写,用于继承类对基类中虚成员的实现overload 表示重载,用于同一个类中同名方法不同参数(包括类型不同或个数不同)的实现示例:Codeusing System;using System.Collections.Generic;using System.Text;namespace Example07{class Program{class BaseClass{public virtual void F(){Console.WriteLine("BaseClass.F");}}class DeriveClass : BaseClass{public override void F(){base.F();Console.WriteLine("DeriveClass.F");}public void Add(int Left,int Right){Console.WriteLine("Add for Int: {0}", Left+ Right);}public void Add(double Left,double Right){Console.WriteLine("Add for int: {0}", Left+ Right);}}static void Main(string[] args){DeriveClass tmpObj= new DeriveClass();tmpObj.F();tmpObj.Add(1,2);tmpObj.Add(1.1,2.2);Console.ReadLine();}}}结果:BaseClass.FDeriveClass.FAdd for Int: 3Add for int: 3.32、类(class)和接口(interface)的区别?.Net提供了接口,这个不同于Class或者Struct的类型定义。
C++中重载、覆盖和隐藏的区别,以及适⽤场景⼀、重载、覆盖和隐藏的区别⼆、适⽤场景1、重载: 适⽤于不同的数据类型都需要使⽤到的功能函数。
以数据相加的函数为例,可以在同⼀个⽂件内提供以下的重载函数以⽀持同样的功能: int add(int, int);/*2个整数相加*/ int add(int, int, int);/*3个整数相加*/ double add(double, double);/*2个double型相加*/ 特别的,形参为指针或引⽤时,指向的对象分别const和⾮const的情况,可以重载。
⽐如下⽅的合并2个string的重置函数,根据实参的类型是否是const,编译器可以⾃动选择调⽤哪个: string &stringCat(string*, string*);/*指向⾮const的*/ const string &stringCat(const string*, const string*)/*指向const,编译通过,因为指针或引⽤指向的对象的类型不同*/ string &stringCat(string* const, string* const);/*编译报错。
因为⾮const的参数可以转换为const的,在传⼊⾮const实参时第1和第3个函数都适⽤,所以编译器认为1和3重复定义*/ 编译器会根据参数的类型、参数数量,⾃动选择匹配的函数。
注意参数相同、返回值类型不同的同名函数,不是重载的,编译时会报错。
2、覆盖: 只能在类的继承中使⽤。
适⽤于⽗类和⼦类都要实现的成员函数,且该函数需要在运⾏中动态绑定的,这个函数就是虚函数,在动态绑定中⼦类的虚函数把⽗类的覆盖了。
class Base{public: virtual func();};/*基类⽤virtual关键字定义了⼀个func()虚函数*/ class Child : public Base{public: func();};/*⼦类定义了⼀个同名、同参数、同返回值的函数,即是覆盖*/ Base *pB; Bash B; Child C; pB = &B; pB->func();/*动态绑定为Base对象,执⾏Base的func*/ pB = &C; pB->func();/*动态绑定为Child对象,执⾏Child的func*/ 程序在运⾏时动态解析指针或引⽤指向的对象属于哪个类,从⽽决定调⽤哪个类的成员函数。
C++中函数重载隐藏和覆盖的区别1.函数重载1.1函数重载的定义C++规定在同一作用域中,同名函数的形式参数(指参数的个数、类型或者顺序)不同时,构成函数重载(Function Overload)。
1.2函数重载的用法比如,要从两个变量中返回其中较大的一个值,可以编写如下两个构成重载的函数。
int max(int a,int b){return a>b?a:b;};double max(double a,double b){return a>b?a:b;}1.3函数重载的注意事项(1)函数返回值与构成函数重载无任何关系;(2)类的静态成员函数与与实例成员函数可以形成重载。
2.函数隐藏2.1函数隐藏的定义函数隐藏指不同作用域中定义的同名函数构成函数隐藏,比如派生类的成员函数屏蔽了与其同名的基类成员函数,类成员函数屏蔽了全局外部函数。
2.2用法用例请仔细研读以下代码。
#include<iostream>usingnamespace std;int max(int a,int b){return a>b?a:b;};class A{void func(){cout<<"member function of A"<<endl;}public:void useFunc(){//func("lvlv");//A::func()将外部函数func(char*)隐藏func();::func("lvlv");}virtualvoid print(){cout<<"A's print"<<endl;}};class B:public A{public:void useFunc(){cout<<"B's useFunc"<<endl;}void useFunc(int i){cout<<"In B's useFunc(),i="<<i<<endl;}virtualvoid print(char* a){cout<<"B's print:"<<a<<endl;}};int main(){A a;eFunc();B b;eFunc();//A::useFunc()被B::useFunc()隐藏b.A::useFunc();eFunc(2);//b.print();//编译出错,A::print()被B::print(char* a)隐藏b.A::print();b.print("jf");}程序执行结果:3.函数覆盖网上和很多书籍多都会涉及函数覆盖的概念,众说纷纭,加大了许多初学者的学习难度,甚至产生误导。
重载与覆盖的区别1、⽅法的覆盖是⼦类和⽗类之间的关系,是垂直关系;⽅法的重载是同⼀个类中⽅法之间的关系,是⽔平关系。
2、覆盖只能由⼀个⽅法,或只能由⼀对⽅法产⽣关系;⽅法的重载是多个⽅法之间的关系。
3、覆盖要求参数列表相同;重载要求参数列表不同。
4、覆盖关系中,调⽤那个⽅法体,是根据对象的类型(对象对应存储空间类型)来决定;重载关系,是根据调⽤时的实参表与形参表来选择⽅法体的。
override可以翻译为覆盖,从字⾯就可以知道,它是覆盖了⼀个⽅法并且对其重写,以求达到不同的作⽤。
对我们来说最熟悉的覆盖就是对接⼝⽅法的实现,在接⼝中⼀般只是对⽅法进⾏了声明,⽽我们在实现时,就需要实现接⼝声明的所有⽅法。
除了这个典型的⽤法以外,我们在继承中也可能会在⼦类覆盖⽗类中的⽅法。
在覆盖要注意以下的⼏点:1、覆盖的⽅法的标志必须要和被覆盖的⽅法的标志完全匹配,才能达到覆盖的效果;2、覆盖的⽅法的返回值必须和被覆盖的⽅法的返回⼀致;3、覆盖的⽅法所抛出的异常必须和被覆盖⽅法的所抛出的异常⼀致,或者是其⼦类;4、被覆盖的⽅法不能为private,否则在其⼦类中只是新定义了⼀个⽅法,并没有对其进⾏覆盖。
overload对我们来说可能⽐较熟悉,可以翻译为重载,它是指我们可以定义⼀些名称相同的⽅法,通过定义不同的输⼊参数来区分这些⽅法,然后再调⽤时,VM就会根据不同的参数样式,来选择合适的⽅法执⾏。
在使⽤重载要注意以下的⼏点:1、在使⽤重载时只能通过不同的参数样式。
例如,不同的参数类型,不同的参数个数,不同的参数顺序(当然,同⼀⽅法内的⼏个参数类型必须不⼀样,例如可以是fun(int, float),但是不能为fun(int, int));2、不能通过访问权限、返回类型、抛出的异常进⾏重载;3、⽅法的异常类型和数⽬不会对重载造成影响;overload编译时的多态override运⾏时的多态⾯向对象程序设计中的另外⼀个重要概念是多态性。
C++中的重载、覆盖、隐藏介绍前⼏天⾯试时被问及C++中的覆盖、隐藏,概念基本答不上来,只答了怎么⽤指针实现多态,也还有遗漏。
最终不欢⽽散。
回来后在⽹上查找学习了⼀番,做了这个总结。
其中部分⽂字借⽤了别⼈的博客,望不要见怪。
概念⼀、重载(overload)指函数名相同,但是它的参数表列个数或顺序,类型不同。
但是不能靠返回类型来判断。
(1)相同的范围(在同⼀个作⽤域中);(2)函数名字相同;(3)参数不同;(4)virtual 关键字可有可⽆。
(5)返回值可以不同;⼆、重写(也称为覆盖 override)是指派⽣类重新定义基类的虚函数,特征是:(1)不在同⼀个作⽤域(分别位于派⽣类与基类);(2)函数名字相同;(3)参数相同;(4)基类函数必须有 virtual 关键字,不能有 static 。
(5)返回值相同(或是协变),否则报错;<—-协变这个概念我也是第⼀次才知道…(6)重写函数的访问修饰符可以不同。
尽管 virtual 是 private 的,派⽣类中重写改写为 public,protected 也是可以的三、重定义(也成隐藏)(1)不在同⼀个作⽤域(分别位于派⽣类与基类);(2)函数名字相同;(3)返回值可以不同;(4)参数不同。
此时,不论有⽆ virtual 关键字,基类的函数将被隐藏(注意别与重载以及覆盖混淆)。
(5)参数相同,但是基类函数没有 virtual关键字。
此时,基类的函数被隐藏(注意别与覆盖混淆)。
例⼦#include <iostream>using namespace std;class SParent{public:SParent( ){};SParent( const SParent &p ){cout << "parent copy construct" << endl;}int add( int a,int b ){cout << "parent int add" << endl;return a + b;}double add( double a,double b ){cout << "parent double add" << endl;return a + b;}virtual int dec( int a,int b ){cout << "parent int dec" << endl;return a - b;}};class SChild : public SParent{public://using SParent::add;float add( float a,float b ){cout << "child float add" << endl;return a + b;}int dec(int a, int b){cout << "child int dec" << endl;return a - b;}};int main(){/* 测试重载 */SParent parent;parent.add( 3,5 );parent.add( (double)3,(double)5 );cout << endl;/* 测试覆盖 */SChild *pchild = (SChild *)new SParent();/* 基类强转为⼦类...危险...,⽤dynamic_cast转换也不⾏ */pchild->dec( 10,3 );SParent *pparent = new SChild();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 );int a = 0;((SChild *)&a)->add( 4,6 );cout << endl;/* 测试函数地址 */((SParent)child).add( (int)4,(int)8 );child.SParent::add( 3,5 );return 0;}输出结果:parent int addparent double addparent int decchild int decchild float addparent int addchild float addchild float addparent copy constructparent int addparent int add按 <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.重载测试,简单易懂,略过。
类成员函数的重载、覆盖和隐藏区别(C++)这是本⼈第⼀次写博客,主要是想记录⾃⼰的学习过程、⼼得体会,⼀是可以⽅便以后回顾相关知识,⼆是可以与⼤家相互学习交流。
1.成员函数被重载的特征:(1)相同的范围(在同⼀个类中);(2)函数名字相同;(3)参数不同;(4)virtual 关键字可有可⽆。
2.覆盖是指派⽣类函数覆盖基类函数,特征是:(1)不同的范围(分别位于派⽣类与基类);(2)函数名字相同;(3)参数相同;(4)基类函数必须有virtual 关键字。
3.“隐藏”是指派⽣类的函数屏蔽了与其同名的基类函数,规则如下:(1)如果派⽣类的函数与基类的函数同名,但是参数不同。
此时,不论有⽆virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。
(2)如果派⽣类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual 关键字。
此时,基类的函数被隐藏(注意别与覆盖混淆)。
有关重载,应该是很好理解的(在同⼀个类中,函数名相同,函数的参数类型和个数不同),此处不予更多的说明,对于覆盖和隐藏(主要在基类和派⽣类中体现),借助下⾯这个例⼦来直观的说明:#include<iostream>using namespace std;class People {public:// 隐藏:是指派⽣类的函数屏蔽基类函数// 隐藏规则1:// 1) 函数名相同 && 参数不同// 2) virtual不影响void getId_different_params() {cout << "People::getId_different_params" << endl;}virtual void getName_different_params() {cout << "People::getName_different_params" << endl;}// 隐藏规则2:// 1) 函数名相同 && 参数相同// 2) ⽆virtualvoid getPhone_same_params() {cout << "People::getPhone_same_params" << endl;}// 覆盖规则:// 1) 函数名相同 && 参数相同// 2) 有virtualvirtual void getAddress_same_params() {cout << "People::getAddress_same_params" << endl;}};class Children : public People {public:// 隐藏:是指派⽣类的函数屏蔽基类函数// 隐藏规则1:// 1) 函数名相同 && 参数不同// 2) virtual不影响void getId_different_params(int) {cout << "Children::getId_different_params(int)" << endl;}virtual void getName_different_params(int) {cout << "Children::getName_different_params(int)" << endl;}// 隐藏规则2:// 1) 函数名相同 && 参数相同// 2) ⽆virtualvoid getPhone_same_params() {cout << "Children::getPhone_same_params" << endl;}// 覆盖规则:// 1)函数名相同 && 参数相同// 2) 有virtualvirtual void getAddress_same_params() {cout << "Children::getAddress_same_params" << endl;}};void main(){Children *c = new Children();c->getId_different_params(1);c->getName_different_params(1);c->getPhone_same_params();c->getAddress_same_params();/*输出为:Children::getId_different_params(int)Children::getName_different_params(int)Children::getPhone_same_paramsChildren::getAddress_same_params*/People *p = new Children();p->getId_different_params();p->getName_different_params();p->getPhone_same_params();p->getAddress_same_params();/*输出为:People::getId_different_params //由于⼦类中的函数只是隐藏了基类中的函数⽽没有覆盖,因为指针为基类指针,故调⽤基类函数People::getName_different_params //由于⼦类中的函数只是隐藏了基类中的函数⽽没有覆盖,因为指针为基类指针,故调⽤基类函数People::getPhone_same_params //由于⼦类中的函数只是隐藏了基类中的函数⽽没有覆盖,因为指针为基类指针,故调⽤基类函数Children::getAddress_same_params // 由于⼦类中的函数覆盖了基类中的函数,虽然指针为基类指针,但是会调⽤⼦类函数*/}。
C++ 重载覆盖隐藏
1. 成员函数被重载的条件有:
1) 相同的范围(在同一个类中);//同一层次
2) 函数名字相同;
3) 参数不同;
4) virtual关键字可有可无。
注意:重载不关心函数的返回值类型
① double calculate(double);
② double calculate(double,double);
③ double calculate(double, int);
④ double calculate(int, double);
⑤ double calculate(int);
⑥ float calculate(float);
⑦ float calculate(double);
2. 覆盖的条件有:
子类函数名、参数列、返回值类型
1) 不同的范围(分别位于派生类与基类);//不同层次,子内父外
2) 函数名字相同;
3) 参数相同;
4)返回值类型相同;
注:派生类虚函数覆盖基类虚函数+隐藏基类中所有其他重载函数覆盖总包含了隐藏!!(满足前两点就能实现隐藏,再加后三点实现覆盖)
e.g., P264 8_4.cpp
3. 隐藏,非严格一致的覆盖。
指派生类的函数屏蔽了与其同名的基类函数,条件如下:
1) 不同的范围(分别位于派生类与基类);//不同层次,子内父外
2) 函数名字相同;
//以下三条有一条不符合者,皆为隐藏!
阻止了编译器继续向上查找函数的定义
e.g., p219, 7_4.cpp 隐藏非覆盖!父类指针作用域,相当于基类::display();
p228, 7_7.cpp。