C++中继承技术引发的问题:重载(overload),覆盖(override)和隐藏(hide)的区别

本文详细解析了C++中函数的重载、覆盖与隐藏等概念的区别与联系,通过具体实例展示了这些特性的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.重载(overload)的特征:

a).几个函数如果是重载,那么他们的作用域相同,即在同一个范围内。【例如:在同一个类中,或者在同一个全局中】

b).函数名字必须相同,但是参数必须不同【个数可以不同,类型也可以不同】

c).virtual关键字可有可无.

【重载的作用就是同一个函数有不同的行为】

2.覆盖(override)的特征:

a).覆盖指的是派生类的函数覆盖基类的函数,因此范围不同,一个是在基类,一个是在派生类中。

b).函数名字和参数都必须完全相同。

c).virtual关键字必须出现在基类的函数中。

【所谓的覆盖指的是:用基类对象的指针或者引用访问虚函数时会根据实际的类型决定所调用的函数】

3.隐藏(hide)的特征:

a).派生类的函数隐藏(或者说是屏蔽)了与其同名的基类的函数。隐藏的理解:在调用一个类的成员函数的时候,编译器会沿着类的继承链逐级的向上查找函数的定义,如果找到了,那么就停止查找了。所以如果一个派生类和他的基类都有同一个同名(且不论其参数)的函数,而编译器最终选择了派生类中的函数,那么就说派生类中的成员函数隐藏了基类中的成员函数,也就是说它阻止了编译器继续向上查找的行为。

b).因为覆盖中说到了基类中的函数存在了virtual关键字,且名字和参数都相同的情况下是覆盖了,那么隐藏的特点就是如下了:

    1).在派生类和基类中函数名相同,但参数不同(因为参数不同就不会构成了覆盖的特点),所以,virtual关键字已经显得不重要了,此时就只能构成隐藏了

    2).在派生类和基类中的函数名相同,参数相同,此时就要看virtual关键字了,要是没有此关键字就构成隐藏了,有此关键字就是前面所说的覆盖了。

总结:函数的覆盖是发生在派生类与基类之间,两个函数必须完全相同,并且都是虚函数。那么不属于这种情况的,就是隐藏了。

【覆盖的函数是多态的,是存在vbtl中的函数才能构成覆盖的关系;而隐藏的函数都是一般的函数,不支持多态,是在编译阶段就确定了的】

 

 

 

 

成员函数的重载,覆盖(改写)和隐藏成员函数被重载的特征是:1、具有相同的作用域,即在同一个类申明中。2、返回值相同,函数的参数不同。3、同名const方法和非const方法之间的重载不受到2的约束,同类重载受到2的约束。4、不需要virutal 关键字。

 

覆盖(也叫做多态)或者改写是指派生类重新实现或者改写了基类的成员函数,其特征是:1、不同的作用域(分别位于派生类和基类中)。2、函数名称相同。3、函数的参数也完全相同。4、基类必须有virtual关键字,子类则可有可无。5、若虚函数存在重载的情况,遵循基类而不遵循子类。6、构造函数中虚函数无效,总是调用本类型方法不会调用覆盖方法。

 

 隐藏1、不同的作用域(分别位于派生类和基类)。2、函数名称相同。3、函数的参数也完全相同。4、不需要virtual关键字。5、总是调用引用类型对应的方法。

 

 

重载好理解:

这个好理解,在同个作用域同名的。

参数必须不同,有无virtual无关。

#include<iostream>
#include<vector>
#include<iterator>
#include<string>
#include<sstream>
using namespace std;
class  Base
{
public:
 virtual void fun()
 {
 cout<<"Base:fun()"<<endl;
 }
 virtual void fun(int a)//重载
 {
 cout<<"Base:fun(重载)"<<a<<endl;
 }

 

};

class D:public Base
{
public:
 
 virtual void fun(int a)
 {
 cout<<"D:fun():"<<endl;
 }


};

 

void main()

{
  Base b;
  b.fun(3);//ok
  b.fun();//ok

}

 

覆盖(override)

覆盖好理解比如fun()函数

A派生了B

如果B中的fun()覆盖了A中的fun()

但B中仍然有两个fun(),而不管是A类指针或引用也好,B类对象调用也好,都只能调用B类自己的那个sfun();

而从A类继承过来的fun()函数真的就被覆盖了,没有了吗? 答应是不对的。这时可以在B类对象显示的调用A类继承过来的show()

 

#include<iostream>
#include<vector>
#include<iterator>
#include<string>
#include<sstream>
using namespace std;
class  Base
{
public:
 virtual void fun()
 {
 cout<<"Base:fun()"<<endl;
 }
 //virtual void fun(int a)//重载
 //{
 //cout<<"Base:fun(重载)"<<a<<endl;
 //}

 

};

class D:public Base
{
public:
 
 virtual void fun()
 {
 cout<<"D:fun():"<<endl;
 }


};

 

void main()

{ D d;
  Base &b=d;
 
  d.fun();
  b.fun();
}

 

隐藏(hide)

3.隐藏(hide)的特征:

a).派生类的函数隐藏(或者说是屏蔽)了与其同名的基类的函数。隐藏的理解:在调用一个类的成员函数的时候,编译器会沿着类的继承链逐级的向上查找函数的定义,如果找到了,那么就停止查找了。所以如果一个派生类和他的基类都有同一个同名(且不论其参数)的函数,而编译器最终选择了派生类中的函数,那么就说派生类中的成员函数隐藏了基类中的成员函数,也就是说它阻止了编译器继续向上查找的行为。

b).因为覆盖中说到了基类中的函数存在了virtual关键字,且名字和参数都相同的情况下是覆盖了,那么隐藏的特点就是如下了:

    1).在派生类和基类中函数名相同,但参数不同(因为参数不同就不会构成了覆盖的特点),所以,virtual关键字已经显得不重要了,此时就只能构成隐藏了

    2).在派生类和基类中的函数名相同,参数相同,此时就要看virtual关键字了,要是没有此关键字就构成隐藏了,有此关键字就是前面所说的覆盖了。

总结:函数的覆盖是发生在派生类与基类之间,两个函数必须完全相同,并且都是虚函数。那么不属于这种情况的,就是隐藏了。

【覆盖的函数是多态的,是存在vbtl中的函数才能构成覆盖的关系;而隐藏的函数都是一般的函数,不支持多态,是在编译阶段就确定了的】

#include<iostream>
#include<vector>
#include<iterator>
#include<string>
#include<sstream>
using namespace std;
class  Base
{
public:
 virtual void fun()
 {
 cout<<"Base:fun()"<<endl;
 }
 //virtual void fun(int a)//重载
 //{
 //cout<<"Base:fun(重载)"<<a<<endl;
 //}

 

};

class D:public Base
{
public:
 
 virtual void fun(int a)//这时有无virtual都是隐藏
 {
 cout<<"D:fun():"<<endl;
 }


};

 

void main()

{ D d;
  Base &b=d;
 
  d.fun();//现在就是隐藏了,error,因为在子类已经屏蔽掉了父类的fun()方法,注意不是fun(int a),解决方案两个:见下面的例子
  b.fun();
}

改进方案1:

#include<iostream>
#include<vector>
#include<iterator>
#include<string>
#include<sstream>
using namespace std;
class  Base
{
public:
 virtual void fun()
 {
 cout<<"Base:fun()"<<endl;
 }
 //virtual void fun(int a)//重载
 //{
 //cout<<"Base:fun(重载)"<<a<<endl;
 //}

 

};

class D:public Base
{
public:
 
 virtual void fun(int a=2)//注意在这里加默认参数,d.fun()其结果是输出子类的默认值
 {
 cout<<"D:fun():"<<a<<endl;
 }


};

 

void main()

{ D d;
  Base &b=d;
 
  d.fun();
  b.fun();
}

改进二

#include<iostream>
#include<vector>
#include<iterator>
#include<string>
#include<sstream>
using namespace std;
class  Base
{
public:
 virtual void fun()
 {
 cout<<"Base:fun()"<<endl;
 }
 //virtual void fun(int a)//重载
 //{
 //cout<<"Base:fun(重载)"<<a<<endl;
 //}

 

};

class D:public Base
{
public:
 using Base::fun;//改进二使用关键字using 显示指出调用父类的函数fun,但是结果适合改进一的不同,他是调用父类的fun()函数
 virtual void fun(int a)
 {
 cout<<"D:fun():"<<a<<endl;
 }


};

 

void main()

{ D d;
  Base &b=d;
 
  d.fun(3);
  b.fun();
}

又如


 

#include<iostream>
#include<vector>
#include<iterator>
#include<string>
#include<sstream>
using namespace std;
class  Base
{
public:
 virtual void fun()
 {
 cout<<"Base:fun()"<<endl;
 }
 virtual void fun(int a)
 {
 cout<<"Base:fun(重载)"<<a<<endl;
 }

 

};

class D:public Base
{
public:
 using Base::fun;
 virtual void fun()
 {
 cout<<"D:fun():"<<endl;
 }


};

 

void main()

{ D d;
  Base &b=d;
 
  d.fun(3);//如果不使用using Base::fun;编译不错,隐藏情况
  b.fun(4);
}

又如

#include<iostream>
#include<vector>
#include<iterator>
#include<string>
#include<sstream>
using namespace std;
class  Base
{
public:
  void fun()
 {
 cout<<"Base:fun()"<<endl;
 }
 //virtual void fun(int a)
 //{
 //cout<<"Base:fun(重载)"<<a<<endl;
 //}

 

};

class D:public Base
{
public:
 //using Base::fun;
  void fun(int a)
 {
 cout<<"D:fun():"<<a<<endl;
 }


};

 

void main()

{ D d;
  Base &b=d;
 
  d.fun(3);
  d.fun();//编译报错,隐藏或屏蔽了父类的fun()
}

 

 也可以覆盖掉父类的private和protected方法

#include<iostream>
#include<vector>
#include<iterator>
#include<string>
#include<sstream>
#include<Windows.h>

using namespace std;
class  Base
{
public:
  void fun()
 {
 cout<<"Base:fun():"<<endl;
  int b=foo();
  cout<<b<<endl;
 }
private:
 virtual int foo()
 {
 cout<<"Base:foo():"<<endl;
  return 2;
 }
 int a;


};

class D:public Base
{
public:
 //using Base::fun;
 // void fun()
 //{
 //cout<<"D:fun():"<<endl;
 //}
private:
virtual  int foo()//覆盖掉了父类的private方法
 {
 cout<<"D:foo():"<<endl;
  return 3;
 }

};

 

void main()
{
 D d;
 d.fun();

 
}

 

注意哟看一个很奇怪的问题:

看看使用默认参数的情况

#include<iostream>
#include<vector>
#include<iterator>
#include<string>
#include<sstream>
#include<Windows.h>

using namespace std;
class  Base
{
public:
 virtual void fun( int a=2)
 {
 cout<<"Base:fun():"<<a<<endl;
 
 }

 

};

class D:public Base
{
public:
 
 virtual  void fun( int a=6)
 {
 cout<<"D:fun():"<<a<<endl;
 
 }


};

 

void main()
{
 D d;
 
 d.fun();
 Base &b=d;
 b.fun();
 
}

结果:

D:fun():6

D:fun(():2

为什么对b.fun()调用使用的是子类的fun()函数,而使用的默认参数却是基类的默认参数?

造成这样的原因是c++编译器把默认参数和指示对象的变量类型绑定在一起,而不是与对象本身

所以c++在覆盖默认参数的方法时,不仅提供默认参数,而且参数参数值也相同

但是当去掉上面的例子中的virtual关键后:

 

#include<iostream>
#include<vector>
#include<iterator>
#include<string>
#include<sstream>
#include<Windows.h>

using namespace std;
class  Base
{
public:
  void fun( int a=2)
 {
 cout<<"Base:fun():"<<a<<endl;
 
 }

 

};

class D:public Base
{
public:
 
  void fun( int a=6)
 {
 cout<<"D:fun():"<<a<<endl;
 
 }


};

 

void main()
{
 D d;
 
 d.fun();
 Base &b=d;
 b.fun();

}

 

结果:

D:fun():6

Base:fun():2

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值