重载虚函数的相关问题

简介:

我们先看以下三个共同的术语来区分:

①要正常f()进行重载(overload)是表示,在同样的作用域中定义还有一个同样的名字(f)的函数,而且这个函数与f()有着不同的參数个数和參数类型。当程序调用函数f()时。编译器将会依据实际提供的參数来选择最匹配的函数。

②对虚函数f()进行覆盖(override)是表示,在派生类中定义一个同样的名字(f)的函数。而且这个函数的參数个数和參数类型与f()是同样的。

③对外层作用域(基类、外部类或者名字空间)中的函数f()进行隐藏(hide)是表示在内层作用域(派生类、嵌套类或者嵌套名字空间)中定义还有一个同样名字(f)的函数,这将隐藏外层作用域中同样名字的函数。

以下看一个样例:

class Base

{

public:

   virtual void f(int);

   virtual void f(double);

   virtual void g(int i = 10);

};

void Base::f(int)

{

   cout << "Base::f(int)" << endl;

}

void Base::f(double)

{

   cout << "Base::f(double)" << endl;

}

void Base::g(int i)

{

   cout << i << endl;

}

class Derived:public Base

{

public:

   void f(complex<double>);

   void g(int i = 20);

};

void Derived::f(complex<double> a)

{

   cout << "Derived::f(complex)" << endl;

}

void Derived::g(int i)

{

   cout << "Derived::g()" << i << endl;

}

int main()

{

   Base b;

   Derived d;

   Base* pb = new Derived;

   b.f(1.0);

   d.f(1.0);

   pb->f(1.0);

   b.g();

   d.g();

   pb->g();

   delete pb;

   return 0;

}

①“delete pb;”是不安全的

我们通常应该将基类的析构函数定义为虚函数。

在上面的代码中,我们是通过指向基类的指针来删除派生类的对象,而在基类中并未定义虚析构函数,那么这就会产生问题,上面代码将调用错误的析构函数。

②Derived::f不是重载函数

在Derived类中并非对Base::f进行重载,而是隐藏了这个函数。

这个差别是非常重要的。由于它意味着在Derived的作用域中,Base::f(int)和Base::f(double)将是不可见的。假设要将Base::f这个名字引入到Derived的作用域中。正确地方法是使用using声明语句------“using Base::f"。

③我们永远都不要去改变所覆盖的基类函数中的默认參数值

函数Derived::g覆盖了Base::g,但却改变了默认參数值void g(int i = 20);

以下分析上面的程序的输出结果:

b.f(1.0);调用Base::f(double),这与程序猿所期望的是一致的。

d.f(1.0);将调用Derived::f(complex<double>).由于Base::f(int)和Base::f(double)被Derived::f(complex<double>)隐藏了。

我们可能希望这行代码会去调用Base::f(double),但在这样的情况下是不会的,并且编译器甚至不会报错。由于幸运的是,complex<double>可以提供从double来的隐式转换,因此编译器会将这个调用解释为Derived::f(complex<double>(1.0)).

pb->f(1.0);尽管指针Base  * pb指向的是一个Derived对象,但上面这行代码调用的却是Base::f(double),这是由于重载解析仅仅是作用于静态类型(这里是Base),而不是动态类型(这里是Derived)。同理,函数调用”pb->f(complex<double>(1.0))“将无法通过编译,这是由于在Base的接口中没有符合要求的函数。

b.g();将输出”10“,调用了Base::g(int).

d.g();将输出”Derived::g()20"。由于这仅仅是调用了Derived::g(int),而这个函数的默认參数值是20.

pb->g();这将输出“Derived::g()10"。我们要记住的是,,在相同的函数重载。默认参数是静态类型的对象从(这是Base)。由此得到的默认值它是10.然而。因为该功能是一个虚函数,因此,该函数的实际动态类型由对象称为(这是Derived)决定。






本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5028693.html,如需转载请自行联系原作者


相关文章
|
缓存
Autojs4.1.0实战教程---快手极速版清理缓存
Autojs4.1.0实战教程---快手极速版清理缓存
626 1
|
数据中心
openstack的亲和组
在OpenStack中,亲和性组(Affinity Groups)是用于定义虚拟机(VM)实例之间关系的一种机制。亲和性组允许你指定一组虚拟机实例,并规定它们应该在同一主机上运行(亲和性),或者应该在不同主机上运行(反亲和性)。这有助于优化性能、提高可用性和确保一些特定的资源隔离。 亲和性组可以通过OpenStack的Orchestration服务(Heat)来定义和管理。以下是一些关键概念和步骤: 1. **亲和性策略(Affinity Policy):** 定义了虚拟机实例之间的关系。有两种主要的策略,即亲和性(affinity)和反亲和性(anti-affinity)。 2.
663 0
|
数据采集 SQL 存储
DataWorks数据质量介绍及实践 | 《一站式大数据开发治理DataWorks使用宝典》
数据质量问题虽然从数据工程师的角度来看是个简单问题,但是从业务的角度来看是个很严重的问题。所以数据质量是数据开发和治理全生命周期中,非常重要的一个环节。在DataWorks产品版图里,数据质量也是非常重要的模块之一。
4846 0
DataWorks数据质量介绍及实践 | 《一站式大数据开发治理DataWorks使用宝典》
|
XML 编解码 前端开发
svg和canvas的区别
【10月更文挑战第24天】SVG和Canvas各有优缺点,在实际应用中需要根据具体的需求和场景来选择合适的技术来实现图形绘制和交互效果。
386 62
|
10月前
|
运维 关系型数据库 MySQL
体验领礼啦!体验自建数据库迁移到阿里云数据库RDS,领取桌面置物架!
「技术解决方案【Cloud Up 挑战赛】」上线!本方案介绍如何将自建数据库平滑迁移至云数据库RDS,解决业务增长带来的运维难题。通过使用RDS MySQL,您可获得稳定、可靠和安全的企业级数据库服务,专注于核心业务发展。完成任务即可领取桌面置物架,每个工作日限量50个,先到先得。
|
自然语言处理 Python
通义灵码个人使用体验
我是一位Python初学者,使用通义灵码进行代码生成与解析,学习更便捷高效。具体流程包括:1. 安装与配置插件;2. 输入需求,描述代码功能或优化目标;3. 点击生成,自动获得代码片段或优化建议。
|
传感器 自动驾驶 算法
智能无人机:物流配送与环境监测
【10月更文挑战第25天】智能无人机技术正深刻改变物流配送与环境监测领域。通过先进的自动驾驶、飞行控制及精确定位技术,智能无人机在物流配送中实现快速、准确的货物送达,显著提高配送效率。在环境监测中,无人机凭借高空监测能力和实时数据传输技术,为大气、水质等环境要素提供全面、高效的监测服务。未来,随着技术升级和应用场景拓展,智能无人机将在更多领域发挥重要作用。
|
调度
DOS操作系统具有以下特点
【10月更文挑战第15天】DOS操作系统具有以下特点
446 2
|
机器学习/深度学习 人工智能 自然语言处理
人工智能与模型知识库在移动医疗产品中的落地应用
在现代医疗体系中,通义千问大模型与MaxKB知识库的结合,为医生和患者提供了前所未有的支持与便利。该系统通过实时问答、临床决策辅助、个性化学习和患者教育等功能,显著提升了诊疗效率和患者满意度。实际应用如乐问医学APP展示了其强大优势,但数据隐私和安全问题仍需关注。
714 0
|
安全 网络安全 网络架构
私有IP地址详解:概念、分类与应用
私有IP地址详解:概念、分类与应用
1153 0