Visual C++中函数的覆盖和函数的隐藏

微软技术分享 微软最有价值专家
全栈领域优质创作者
博客专家认证
2024-02-12 10:00:01

 我是荔园微风,作为一名在IT界整整25年的老兵,今天来聊聊Visual C++中函数的覆盖和函数的隐藏。

Visual C++中函数的覆盖和函数的隐藏与JAVA有很大不同,有些容易搞错的点和概念,我们要特别注意。

首先,先满足一下急性子的同学,因为有的同学是因为急于了解虚函数和纯虚函数才来看这篇帖子的,那你可以先这样理解:

C++中的虚函数就是JAVA中的普通函数, C++ 中的纯虚函数就是JAVA中的抽象函数, C++ 中的抽象类就是JAVA中的抽象类, C++ 中的虚基类就是JAVA中的接口。

这就是本人的学习方法和别人不一样的地方,我年轻时学C++始终不得要领,于是我把JAVA学会后再去学C++,就全都搞明白了。所以我的帖子都是用这种方法去学C++的。希望那些学C++很吃力的同学可以来借鉴我的这个学习方法。

好了,我们先来看一个程序,一个父亲和一个儿子,希望父亲的学习本领能被儿子继承下去。我们在儿子类中重新定义学习方法。我们希望如果对象是儿子,就调用 儿子类的学习方法,如果对象是父亲,那么就调用父亲类的学习方法。

#include <iostream>
using namespace std;
 
class Father
{
public:
  void eat()
  {
    cout<<"eat"<<endl;
  }
  void run()
  {
    cout<<"run"<<endl;
   }
  virtual void study()
  {
    cout<<"study"<<endl;
  }
};
 
class Son : public Father
{
public:
  void study()
   {
    cout<<"new study"<<endl;
  }
};
 
void fn(Father *p)
{
    p->study();
}
 
int main()
{
  Father *p;
  Son boy;
  p=&boy;
  fn(p);
  return 0;
}

在基类父亲类的study函数前添加了virtual关键字,声明该函数为虚函数。在派生类儿子类中重写了 study函数,我们注意到, 儿子类的study函数和父亲类的study函数完全一样,无论是函数名,还是参数列表都是一样的,这称为函数的覆盖(override)。

我们必须知道构成函数覆盖的条件为:(1)基类函数必须是虚函数(使用 virtual关键字进行声明)。(2)发生覆盖的两个函数要分别位于派生类和基类中。(3)函数名称与参数列表必须完全相同。由于C++的多态性是通过虚函数来实现的,所以函数的覆盖总和多态关联在一起(这一点和JAVA十分相似, 但是JAVA不需要virtual这种关键词)。在函数覆盖的情况下,编译器会在运行时根据对象的实际类型来确定要调用的函数。

我们再看代码:

#include <iostream>
using namespace std;
 
class Father
{
public:
  void eat()
  {
    cout<<"eat"<<endl;
  }
  void run()
  {
    cout<<"run"<<endl;
   }
  void study()
  {
    cout<<"study"<<endl;
  }
};
 
class Son : public Father
{
public:
  void study()
   {
    cout<<"new study"<<endl;
  }
};
 
void fn(Father *p)
{
    p->study();
}
 
int main()
{
  Father *p;
  Son boy;
  p=&boy;
  fn(p);
  return 0;
}

这个其实又回到我之前一个帖子的内容了,大家有兴趣可以看看那个帖子:

Visual C++中的虚函数和纯虚函数的原理

大家应该可以看出来这段代码前面代码的区别。在这段代码中,派生类儿子类中的study函数和基类父亲类中的study函数是完全一样的,不同的是study函数不是虚函数,这种情况称为函数的隐藏。所谓隐藏,是指派生类中具有与基类同名的函数(不考虑参数列表是否相同),从而在派生类中隐藏了基类的同名函数。

初学VC者很容易把函数的隐藏与函数的覆盖、重载相混淆,我们看下面两种函数隐藏的情况:

(1)派生类的函数与基类的函数完全相同(函数名和参数列表都相同),只是基类的函数没有使用virtual关键字。此时基类的函数将被隐藏,而不是被覆盖。

(2)派生类的函数与基类的函数同名,但参数列表不同,在这种情况下,不管基类的函数声明是否有 virtual关键字,基类的函数都将被隐藏。注意这种情况与函数重载的区别,重载发生在同一个类中。

下面我们给出一个例子,以帮助大家加深理解函数的覆盖和隐藏  

class Father
{
public:
  virtual void fn();
};

class Son:public Father
{
public:
  void fn(int);
};

class Grandson:public Son
{
public:
  void fn();
};

在上面代码中, 儿子类的 fn(int)函数隐藏了父亲类的fn()函数, 儿子类 fn(int)函数不是虚函数(注意和覆盖相区别)。 孙子类的 fn()函数隐藏了 儿子类的 fn(int)函数,由于 孙子类的 fn()函数与 父亲类的fn()函数具有同样的函数名和参数列表,因此 孙子类的 fn()函数是一个虚函数,覆盖了父亲 类的 fn()函数。注意,在孙子类中, 父亲类的 fn()函数是不可见的,但这并不影响 fn 函数的覆盖。

当隐藏发生时,如果在派生类的同名函数中想要调用基类的被隐藏函数,那么可以使用“基类名::函数名(参数)”的语法形式。例如,要在儿子类的fn(int)方法中调用父亲类的fn()方法,可以使用Father::fn()语句。

有的初学者可能会想,怎样才能更好地区分覆盖和隐藏呢?实际上只要记住一点:

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


文章来源: https://blog.csdn.net/wang2015cn/article/details/131451739
版权声明: 本文为博主原创文章,遵循CC 4.0 BY-SA 知识共享协议,转载请附上原文出处链接和本声明。


...全文
54 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

460

社区成员

发帖
与我相关
我的任务
社区描述
微软技术社区为中国的开发者们提供一个技术干货传播平台,传递微软全球的技术和产品最新动态,分享各大技术方向的学习资源,同时也涵盖针对不同行业和场景的实践案例,希望可以全方位地帮助你获取更多知识和技能。
windowsmicrosoft 企业社区
社区管理员
  • 微软技术分享
  • 郑子铭
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

微软技术社区为中国的开发者们提供一个技术干货传播平台,传递微软全球的技术和产品最新动态,分享各大技术方向的学习资源,同时也涵盖针对不同行业和场景的实践案例,希望可以全方位地帮助你获取更多知识和技能。

予力众生,成就不凡!微软致力于用技术改变世界,助力企业实现数字化转型。

试试用AI创作助手写篇文章吧