C++学习笔记----9、发现继承的技巧(一)---- 使用继承构建类(3)

devtools/2024/10/19 1:03:05/

2、重载成员函数

        从一个类继承的主要原因是添加或替换功能。Derived的定义通过添加了另外的成员函数someOtherFunction()增加了父类的功能。其它的成员函数someFunction(),从Base继承,在继承类中的表现与在基类中完全一致。在许多情况下,你会想通过修改,或者说重载成员函数来修改类的行为。

2.1、virtual关键字

        简单地从基类的继承类中定义一个成员函数并不会恰当地重载该成员函数。为了正确地重载一个成员函数,我们需要一个新的c++关键字叫做virtual。只有在基类中声明成员函数为virtual才能恰当地被继承类重载。该关键字会在成员函数声明的开始,修改后的Base类展示如下:

class Base
{
public:virtual void someFunction();// Remainder omitted for brevity.
};

        对于Derived类也一样。如果继续在继承类中进行重载的话也要将成员函数标记为virtual:

class Derived : public Base
{
public:virtual void someOtherFunction();
};

        virtual关键字不会在成员函数定义前重复,例如:

void Base::someFunction()
{println("This is Base's version of someFunction().");
}

        警告:尝试重载基类中的non-virtual成员函数会隐藏基类定义,只会在继承类的上下文中使用。

2.2、重载成员函数语法

        为了重载成员函数,与在基类中的声明一样重新在继承类中再声明一次,但是要加上override关键字并且 移除virtural关键字。例如,如果想要在Derived类中提供一个新的someFunction()的定义,必须首先将它添加到Derived类定义中,如下:

class Derived : public Base
{
public:void someFunction() override; // Overrides Base's someFunction()virtual void someOtherFunction();
};

        新的someFunction()的定义给出了与Derived的成员函数一致的其余部分。与virtual关键字一样,不需要在成员函数中重复override关键字:

void Derived::someFunction()
{println("This is Derived's version of someFunction().");
}

        如果你想的话,是允许在重载的成员函数前添加virtual关键字的,但是它是冗余的。举例如下:

class Derived : public Base
{
public:virtual void someFunction() override;
};

        一旦成员函数或析构函数被标记为virtual,对于所有的继承类它都是virtual的,即使在继承类中移除virtual关键字也改变不了。

2.3、重载成员函数的客户观点

        有了前面的修改,其它代码仍然用以前同样的方式调用someFunction()。与以前一样,Base类的对象或者Derived类的对象上也可以调用成员函数。然而,现在someFunction()的行为基于对象的类的不同而不同了。

        例如,下面的代码与以前一样,调用了Base的someFunction()版本:

Base myBase;
myBase.someFunction();
// Calls Base's version of someFunction().

代码的输出如下:

This is Base's version of someFunction().

        如果代码声明了一个Derived类的对象,另外一个版本自动调用:

Derived myDerived;
myDerived.someFunction();
// Calls Derived's version of someFunction()

        这次输出如下:

This is Derived's version of someFunction().

        Derived类的对象的另外的所有东东保持不变。其他可能从Base继承的成员函数仍然是Base提供的定义,除非在Derived中显式地进行了重载。

        我们前面学到过,指针与引用可以指向一个类的对象或者任何继承的类。对象自身是“知道”实际是哪个类的成员,所以只要它被声明成virtual,就会调用恰当的成员函数。例如,如果你有一个Base引用指向了一个实际是Derived的对象,调用了someFunction()实际上调用了继承类的版本,下面会展示。如果在基类中省略掉virtual关键字重载的特性就不会好好工作了。

Derived myDerived;
Base& ref { myDerived };
ref.someFunction();
// Calls Derived's version of someFunction()

        记住即使Base引用或指针知道它是指向的一个Derived实例,你也不能访问没有在Base中定义的Derived类成员。下面的代码编译不成功,因为Base引用没有叫做someOtherFunction()的成员函数:

Derived myDerived;
Base& ref { myDerived };
myDerived.someOtherFunction();// This is fine.
ref.someOtherFunction();// Error

        而这个继承类的知识特点对于非指针或非引用的对象是不正确的。歪打正着一次,还想着一直歪下去啊!可以转换或者将Derived赋值给Base,因为Derived是Base。然而,对象在这一点上丢掉了Derived类的所有知识。

Derived myDerived;
Base assignedObject { myDerived };// Assigns a Derived to a Base.
assignedObject.someFunction();// Calls Base's version of someFunction()

        记住这个看起来奇怪的行为的一个方法就是想像一下对象在内存中是什么样的。把Base对象想像成一个占用了一定量内存的盒子。Derived对象是一个稍微大一点的盒子,因为它有Base的一切还加了一点儿东西。不管你是有一个Derived或Base引用或者是指向Derived的指针,盒子是不会变的--只是有了一个新的访问的方式。然而,当你将Derived转换成Base时,你会把Derived的所有“独特性”扔掉来满足小的盒子。

        注意:当用基类的指针或引用访问时,继承类保持所有的数据成员与成员函数。当转换成基类对象时会丢掉它们的独特性。继承类的数据成员与成员函数的丢失叫做分片。


http://www.ppmy.cn/devtools/126870.html

相关文章

桂林旅游攻略:SpringBoot平台全面指南

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统,它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等,非常…

智慧健康生活:SpringBoot智能推荐系统

3系统分析 3.1可行性分析 通过对本基于智能推荐的卫生健康系统实行的目的初步调查和分析,提出可行性方案并对其一一进行论证。我们在这里主要从技术可行性、经济可行性、操作可行性等方面进行分析。 3.1.1技术可行性 本基于智能推荐的卫生健康系统采用SSM框架&#…

CPO:隐含于CoT与ToT两者间的推理平衡

自OpenAI推出o1以来,随着reasoning scaling law的大行其道‌,很多研究者都将目光聚焦在“reasoning”之上,而在仅reasoning维度上,确实存在着非常深邃且让人着迷的可探索空间,毕竟这意味着围绕system2展开的下一轮认知…

ubuntu中多cuda版本兼容问题

当ubuntu中已经有老版本的cuda时,按正常步骤直接下载新的cuda和cudnn,只需要注意在下载新的cuda版本时,出现“A symlink already exists at /usr/local/cuda. Update to this installation?”,选择“no”,之后按如下的…

Pwn---学习之路

前言:入门开始 ,一步一脚印。 解释有错,见谅。因为,作者也是初学者。 现阶段,准备工具。 IDA Pro pwndbg pwntools checksec (pwntools自带) 知识:6个 函数 process() —— 本地 remote() —— 远程…

UE5 猎户座漂浮小岛 04 声音 材质

UE5 猎户座漂浮小岛 04 声音 材质 1.声音 1.1 导入 wav格式 1.2 循环播放 1.3 mp3转wav 1.4 新手包素材(火焰 ) particle:颗粒 2.材质 2.1 基本颜色 M_Yellow 2.2 混合模式与双面材质 2.3 金属感、高光、粗糙度 M_AluminumAlloy 2.4 自…

C++多款质量游戏及开发建议[OIER建议]

前言 其实C不适合开发大型高质量游戏。 但是,很多人信息学竞赛生(博主)为了竞赛都学习了C,但自小就认为编程就是开发游戏的我们,肯定想着开发一个游戏,但发现C的局限性以及无法和windows非常好的兼容&…

UE小:UE5的Pixelstreaming在捕获画面的时候没办法显示非Viewport的Slate区域按钮的ToolTip

原始代码 首先&#xff0c;让我们看看原始代码片段&#xff1a; // Some widgets might want to provide an alternative Tooltip Handler. if (bCanSpawnNewTooltip || !NewTooltip) {TSharedPtr<SWidget> NewTooltipWidget NewTooltip ? NewTooltip->AsWidget()…