C++_04

1、继承

1.1 基本概念

        继承是面向对象编程(OOP)中的一个核心概念,特别是在C++中。它允许一个类(称为派生类或子类)继承另一个类(称为基类或父类)的属性和方法。继承的主要目的是实现代码重用,以及建立一种类型之间的层次关系。

        特点:

        (1)代码重用:子类继承了父类的属性和方法,减少了代码的重复编写。

        (2)扩展性:子类可以扩展父类的功能,添加新的属性和方法,或者重写(覆盖)现有的方法。

        (3)多态性:通过继承和虚函数,C++支持多态,允许在运行时决定调用哪个函数。

        在C++中,继承可以是公有(public)、保护(protected)或私有(private)的,这决定了基类成员在派生类中的访问权限。

#include <iostream>using namespace std;//基类,父类
class Vehicle{ //交通工具,车,抽象的概念
public:string type;string contry;string color;double price;int numOfWheel;void run(){cout << "车跑起来了" << endl;}void stop();
};//派生类,子类
class Bickle : public Vehicle{};//派生类,子类
class Roadster : public Vehicle{ //跑车,也是抽象,比父类感觉上范围缩小了点
public:int stateOfTop;void openTopped();void pdrifting();
};int main()
{Roadster ftype;ftype.type = "捷豹Ftype";ftype.run();Bickle bike;bike.type = "死飞";bike.run();return 0;
}

        在这个例子中, Vehicle 类公有地继承自 Vehicle 类,这意味着所有 Vehicle 类的公有成员在

Vehicle 类中也是公有的。

1.2 权限对继承的影响

        在C++中,访问控制符对继承的影响可以通过下表来清晰地展示。这个表格展示了不同类型的继承( public protected private )如何影响基类的不同类型成员( public protected 、private )在派生类中的访问级别。

基类成员类型
public 继承
protected 继承
private 继承
public
publicprotectedprivate
protected
protectedprotectedprivate
private
不可访问不可访问不可访问

        通过上表可知:

        (1)public 继承:基类的 public 成员在派生类中仍然是 public 的, protected 成员仍然是protected 的。基类的 private 成员在派生类中不可访问。

        (2)protected 继承:基类的 public protected 成员在派生类中都变成 protected 的。基类的 private 成员在派生类中不可访问。

        (3)private 继承:基类的 public protected 成员在派生类中都变成 private 的。基类的private 成员在派生类中不可访问。

        访问权限回顾

访问权限
类内部
同一个类的对象
派生类(子类)
类外部
public
✔️ 可访问
✔️ 可访问
✔️ 可访问
✔️ 可访问
private
✔️ 可访问
不可访问
不可访问
不可访问
protected
✔️ 可访问
不可访问
✔️ 可访问
不可访问

 1.3 基类构造函数

         在C++中,派生类可以通过其构造函数的初始化列表来调用基类的构造函数。这是在构造派生类对象时初始化基类部分的标准做法

        当创建派生类的对象时,基类的构造函数总是在派生类的构造函数之前被调用。如果没有明确指定,将调用基类的默认构造函数。如果基类没有默认构造函数,或者需要调用一个特定的基类构造函数,就需要在派生类构造函数的初始化列表中明确指定。 

class Base {
public:int data;Base(int x) {std::cout << "Base constructor with x = " << x << std::endl;}
};class Derived : public Base {
public:double ydata;Derived(int x, double y) : Base(x) { // 调用 Base 类的构造函数std::cout << "Derived constructor with y = " << y << std::endl;}
};int main() {Derived obj(10, 3.14); // 首先调用 Base(10),然后调用 Derived 的构造函数return 0;
}

        在上述例子中:Base 类有一个接受一个整数参数的构造函数。Derived 类继承自 Base ,它的构造函数接受一个整数和一个双精度浮点数。在其初始化列表中,它调用 Base 类的构造函数,并传递整数参数。当 Derived 类的对象被创建时,首先调用 Base 类的构造函数,然后调用 Derived 类的构造函数。

        通过这种方式,派生类能够确保其基类部分被正确初始化。在继承层次结构中,这是非常重要的,特别是当基类需要一些特定的初始化操作时。

#include <iostream>using namespace std;//基类,父类
class Vehicle{ //交通工具,车,抽象的概念
public:string contry;double price;Vehicle(string contry, double price){cout << "基类的构造函数被调用" << endl;this->contry = contry;this->price = price;};void run(){cout << "车跑起来了" << endl;}void stop();
};//派生类,子类
class Roadster : public Vehicle{ //跑车,也是抽象,比父类感觉上范围缩小了点
public:int stateOfTop;Roadster(string contry, double price, int state) : Vehicle(contry, price){cout << "派生类的构造函数被调用" << endl;stateOfTop = state;}void openTopped();void pdrifting();
};int main()
{Roadster FTYPE("法国",70,0);return 0;
}

1.4 虚函数

        在C++中, virtual override 关键字用于支持多态,尤其是在涉及类继承和方法重写的情况下。正确地理解和使用这两个关键字对于编写可维护和易于理解的面向对象代码至关重要。

1.4.1 virtual 关键字

        使用场景:在基类中声明虚函数。

        目的:允许派生类重写该函数,实现多态。

        行为:当通过基类的指针或引用调用一个虚函数时,调用的是对象实际类型的函数版本。

class Base {
public:virtual void func() {std::cout << "Function in Base" << std::endl;}
};

 1.4.2 override 关键字

        使用场景:在派生类中重写虚函数。

        目的:明确指示函数意图重写基类的虚函数。

        行为:确保派生类的函数确实重写了基类中的一个虚函数。如果没有匹配的虚函数,编译器会报错。

class Derived : public Base {
public:void func() override {std::cout << "Function in Derived" << std::endl;}
};

        注:(1)只在派生类中使用 overrideoverride 应仅用于派生类中重写基类的虚函数。

        (2)虚析构函数:如果类中有虚函数,通常应该将析构函数也声明为虚的。

        (3)默认情况下,成员函数不是虚的:在C++中,成员函数默认不是虚函数。只有显式地使用 virtual 关键字才会成为虚函数。

        (4)继承中的虚函数:一旦在基类中声明为虚函数,该函数在所有派生类中自动成为虚函数,无论是否使用 virtual 关键字。

1.5 多重继承

        在C++中,多重继承是一种允许一个类同时继承多个基类的特性。这意味着派生类可以继承多个基类的属性和方法。多重继承增加了语言的灵活性,但同时也引入了额外的复杂性,特别是当多个基类具有相同的成员时。

        在多重继承中,派生类继承了所有基类的特性。这包括成员变量和成员函数。如果不同的基类有相同名称的成员,则必须明确指出所引用的是哪个基类的成员。

        假设假设有两个基类 ClassA ClassB ,以及一个同时从这两个类继承的派生类 Derived

class ClassA {
public:void displayA() {std::cout << "Displaying ClassA" << std::endl;}
};class ClassB {
public:void displayB() {std::cout << "Displaying ClassB" << std::endl;}
};class Derived : public ClassA, public ClassB {
public:void display() {displayA(); // 调用 ClassA 的 displayAdisplayB(); // 调用 ClassB 的 displayB}
};int main() {Derived obj;obj.displayA(); // 调用 ClassA 的 displayAobj.displayB(); // 调用 ClassB 的 displayBobj.display(); // 调用 Derived 的 displayreturn 0;
}

        在这个示例中, Derived 类同时继承了 ClassA ClassB 。因此,它可以使用这两个类中定义的方法。

        注:(1)菱形继承问题:如果两个基类继承自同一个更高层的基类,这可能导致派生类中存在两份基类的副本,称为菱形继承(或钻石继承)问题。这可以通过虚继承来解决。

        (2)复杂性:多重继承可能会使类的结构变得复杂,尤其是当继承层次较深或类中有多个基类时。

        (3)设计考虑:虽然多重继承提供了很大的灵活性,但过度使用可能导致代码难以理解和维护。在一些情况下,使用组合或接口(纯虚类)可能是更好的设计选择。

        多重继承是C++的一个强大特性,但应谨慎使用。合理地应用多重继承可以使代码更加灵活和强大,但不当的使用可能导致设计上的问题和维护困难。

1.6 虚继承

        虚继承C++中一种特殊的继承方式,主要用来解决多重继承中的菱形继承问题。在菱形继承结构中,一个类继承自两个具有共同基类的类时,会导致共同基类的成员在派生类中存在两份拷贝,这不仅会导致资源浪费,还可能引起数据不一致的问题。虚继承通过确保共同基类的单一实例存在于继承层次中,来解决这一问题。

1.6.1 菱形继承

class Base {
public:int data;
};class Derived1 : public Base {// 继承自 Base
};class Derived2 : public Base {// 继承自 Base
};class FinalDerived : public Derived1, public Derived2 {// 继承自 Derived1 和 Derived2
};

        在这个例子中, FinalDerived 类通过 Derived1 Derived2 间接地继承自 Base 类两次。因此,它包含了两份 Base 的成员拷贝。

1.6.2 使用虚继承解决菱形继承问题

class Base {
public:int data;
};class Derived1 : virtual public Base {// 虚继承 Base
};class Derived2 : virtual public Base {// 虚继承 Base
};class FinalDerived : public Derived1, public Derived2 {// 继承自 Derived1 和 Derived2
};

        通过将 Derived1 Derived2 Base 的继承声明为虚继承( virtual public Base ),FinalDerived 类中只会有一份 Base 类的成员。无论通过 Derived1 还是 Derived2 的路径,访问的都是同一个 Base 类的成员。

        注:(1)初始化虚基类:在使用虚继承时,虚基类(如上例中的 Base 类)只能由最派生的类(如FinalDerived )初始化。

        (2)内存布局:虚继承可能会改变类的内存布局,通常会增加额外的开销,比如虚基类指针。

        (3)设计考虑:虚继承应谨慎使用,因为它增加了复杂性。在实际应用中,如果可以通过其他设计(如组合或接口)避免菱形继承,那通常是更好的选择。

1.7 小结

学习内容
描述
继承的基础
理解基类和派生类的概念,以及如何通过继承扩展类功能。了解不同继承类型(公有、私有、保护)及其影响。
构造函数和析构函数在继承中的行为
学习派生类如何调用基类的构造函数和析构函数,以及它们的调用顺序。
访问控制和继承
理解公有、私有和保护继承对成员访问权限的影响。掌握继承中的访问修饰符(public, protected, private )。
函数重写和多态
学习多态和如何通过虚函数实现它,了解如何重写基类方法,以及纯虚函数和抽象类的概念。
虚继承和解决菱形问题
理解菱形继承问题及其解决方式,学习如何使用虚继承。
C++11 新特性中的继承相关内容
理解和应用 override final 关键字,了解移动语义在继承中的应用。
设计原则与最佳实践
学习正确使用继承的方法,区分何时使用继承,何时使用组合,以及面向对象设计原则的应用。
实际案例分析
通过分析和编写实际代码示例加深理解,研究设计模式中继承的应用。

2、多态

        举个例子,假如你有一个遥控器(这就像是一个基类的指针),这个遥控器可以控制不同的电子设备(这些设备就像是派生类)。无论是电视、音响还是灯光,遥控器上的“/按钮(这个按钮就像是一个虚函数)都能控制它们,但具体的操作(打开电视、播放音乐、开灯)则取决于你指向的设备。

2.1 如何实现多态

        (1)使用虚函数(Virtual Function: 在基类中定义一个虚函数,这个函数可以在任何派生类中被“重写或者说定制。使用关键字 virtual 来声明。

        (2)创建派生类并重写虚函数:在派生类中,我们提供该虚函数的具体实现。这就像是告诉遥控器,“当你控制我的这个设备时,这个按钮应该这样工作”。

        (3)通过基类的引用或指针调用虚函数:当我们使用基类类型的指针或引用来调用虚函数时,实际调用的是对象的实际类型(派生类)中的函数版本。

#include <iostream>using namespace std;class RemoteCon{
public:virtual void openUtils(){cout << "遥控器的开被按下" << endl;}
};class TvRemoteCon : public RemoteCon{
public:void openUtils() override{cout << "电视遥控器的开被按下" << endl;}void testFunc(){}
};class RoundspeakerCon : public RemoteCon{
public:void openUtils() override{cout << "音响遥控器的开被按下" << endl;}
};class LightCon : public RemoteCon{
public:void openUtils() override{cout << "灯光遥控器的开被按下" << endl;}
};void test(RemoteCon& r)//引用的方式
{r.openUtils();
}int main()
{RemoteCon *remoteCon = new TvRemoteCon; //多态remoteCon->openUtils();RemoteCon *remoteCon2 = new TvRemoteCon; //多态remoteCon2->openUtils();RemoteCon *remoteCon3 = new LightCon; //多态remoteCon3->openUtils();TvRemoteCon tvRemote;test(tvRemote);return 0;
}

2.2 抽象类

        在 C++ 中,抽象类就像是这样的一个抽象概念。它定义了一组方法(比如移动),但这些方法可能没有具体的实现。这意味着,抽象类定义了派生类应该具有的功能,但不完全实现这些功能。

        抽象类的特点:

        ( 1)包含至少一个纯虚函数:抽象类至少有一个纯虚函数。这是一种特殊的虚函数,在抽象类中没有具体实现,而是留给派生类去实现。纯虚函数的声明方式是在函数声明的末尾加上 = 0 。

        (2)不能直接实例化:由于抽象类不完整,所以不能直接创建它的对象。就像你不能直接使用“交通工具”的概念去任何地方,你需要一个具体的交通工具。

        (3)用于提供基础结构:抽象类的主 要目的是为派生类提供一个共同的基础结构,确保所有派生类都有一致的接口和行为。

#include <iostream>using namespace std;class Teacher{
public:string name;string shool;string major;virtual void goInClass() = 0;virtual void startTeaching() = 0;virtual void afterTeaching() = 0;
};class EnglishTeacher : public Teacher{
public:void goInClass() override{cout << "英语老师开始进入教室" << endl;}void startTeaching() override{cout << "英语老师开始教学" << endl;}void afterTeaching() override{};
};class ProTeacher : public Teacher{
public:void goInClass() override{cout << "编程老师开始进入教室" << endl;}void startTeaching() override{cout << "编程老师开始撸代码了,拒绝读PPT" << endl;}void afterTeaching() override{cout << "编程老师下课后手把手教x学员写代码" << endl;};
};int main()
{// Teacher t;//抽象类,不支持被实例化EnglishTeacher e;e.goInClass();ProTeacher t;t.startTeaching();t.afterTeaching();//抽象类,多态Teacher *teacher = new ProTeacher;teacher->startTeaching();return 0;
}

2.3 纯虚函数-接口

        在 C++ 中,虽然没有像其他编程语言(比如 Java 中的接口Interface)一样直接定义接口的关键字,但可以通过抽象类和纯虚函数的方式来实现接口的概念。

        接口通常用于定义类应该实现的方法,但不提供具体实现。这样的实现方式允许多个类共享相同的接口,同时让每个类根据需要去实现这些接口。

        一个类作为接口可以通过以下步骤来实现:

        (1)定义抽象类:创建一个包含纯虚函数的抽象类,这些函数构成了接口的一部分。这些函数在抽象类中只有声明而没有具体的实现。

        (2)派生类实现接口:派生类继承抽象类,并实现其中的纯虚函数,以具体实现接口定义的方法。

#include <iostream>using namespace std;class BasketBallMove{
public:virtual void passTheBall() = 0;
};class LiveMove{
public:virtual void eat() = 0;virtual void bite() = 0;virtual void drink() = 0;virtual void la() = 0;
};class Human : public LiveMove,BasketBallMove{
public:void eat() override{};void bite() override{};void drink() override{};void la() override{};void passTheBall() override{};
};class Dog : public LiveMove{
public:void eat() override{};void bite() override{};void drink() override{};void la() override{};
};int main()
{Human h;Dog g;// LiveMove *l = new LiveMove;return 0;
}

        通过这种方式,可以在 C++ 中模拟出类似接口的行为,允许多个类共享相同的接口并提供各自的实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/39663.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

康姿百德磁性床垫好不好,效果怎么样靠谱吗

康姿百德典雅款床垫&#xff0c;打造舒适睡眠新体验 康姿百德床垫是打造舒适睡眠新体验的首选&#xff0c;其设计能够保护脊椎健康&#xff0c;舒展脊椎&#xff0c;让您享受一夜好眠。康姿百德床垫的面料选择也非常重要&#xff0c;其细腻亲肤的针织面料给您带来柔软舒适的触…

如何在操作使用ufw设置防火墙

UFW&#xff08;简单防火墙&#xff09;是用于管理iptables防火墙规则的用户友好型前端。它的主要目标是使iptables的管理更容易。 在学习Linux的时候大家一般都会关心命令&#xff0c;Posix API和桌面等&#xff0c;很少会去了解防护墙。其实除了一些网络安全厂商提供的付费防…

交互案例:5大经典交互效果

文件格式&#xff1a;.rp&#xff08;请与班主任联系获取原型文档&#xff09; 文件名称&#xff1a;Axure交互案例&#xff1a;5大经典交互实现 文件大小&#xff1a;78.5 MB 文档内容介绍 五大经典交互包括&#xff1a; 图片手风琴 图片悬浮放大 详细说明切换 图片全屏查…

上位机GUI 第三弹

&#x1f60a; &#x1f60a; &#x1f60a; 从协议层面讲&#xff0c;地质单元相当重要&#xff0c;调试模式,我只能义命令发送的索引码作为,每个设备的区分方式,调试的情况&#xff0c;不在设备上设置任何东西&#xff0c;开机访问地址和端口就能用 因为懒&#xff0c;直接将…

【代码随想录】【算法训练营】【第55天】 [42]接雨水 [84]柱状图中最大的矩形

前言 思路及算法思维&#xff0c;指路 代码随想录。 题目来自 LeetCode。 day 55&#xff0c;又是一个周一&#xff0c;不能再坚持~ 题目详情 [42] 接雨水 题目描述 42 接雨水 解题思路 前提&#xff1a;雨水形成的情况是凹的, 需要前中后3个元素&#xff0c;计算该元…

专业的TPM管理咨询公司有哪些特点?

专业的TPM管理咨询公司&#xff0c;作为现代企业管理和设备维护的重要合作伙伴&#xff0c;其特点不仅体现在技术能力和服务质量上&#xff0c;更在于其独特的经营理念和方法论。以下是专业TPM管理咨询公司所具备的显著特点&#xff1a; 一、全面的技术实力与深厚的行业经验 专…

word 转pdf 中图片不被压缩的方法

word 转pdf 中图片不被压缩的方法 法1&#xff1a; 调节word 选项中的图片格式为不压缩、高保真 法2&#xff1a; 1: word 中的图片尽可能使用高的分辨率&#xff0c;图片存为pnd或者 tif 格式&#xff08;最高清&#xff09; 2: 转化为pdf使用打印机器&#xff0c;参数如下…

分子AI预测赛笔记

#AI夏令营 #Datawhale #夏令营 Taks1 跑通baseline 根据task1跑通baseline 注册账号 直接注册或登录百度账号&#xff0c;etc fork 项目 零基础入门 Ai 数据挖掘竞赛-速通 Baseline - 飞桨AI Studio星河社区 启动项目 选择运行环境&#xff0c;并点击确定&#xff0c;没…

台灯学生用哪个牌子最好?学生用台灯品牌排行榜分析

台灯学生用哪个牌子最好&#xff1f;护眼台灯在近年来成为家长和长时间使用电子设备人群关注的家电/学生产品。对于家中有孩子或经常面对电子屏幕的人士来说&#xff0c;很多人可能已经对这类产品有所了解并进行了购买。然而&#xff0c;部分家长对护眼台灯的认识还不够深入&am…

FFT 简单基础(matlab

使用 fs 进行采样&#xff0c;进行 N点FFT 选择显示0~N/21点的幅值 横坐标对应频率计算公式&#xff1a; fs * n / N 举个梨子&#xff1a; 频率2kHz采样1s&#xff0c;得到2000个点的序列y(n) 对序列y(n)做4096点的FFT 幅值响应对应的横坐标频率…

机器人控制系列教程之Stewart平台简介和运动学分析

Stewart平台简介及应用场景 六自由度 Stewart 并联机器人结构简图如下图所示&#xff0c;主要有一个固定平台和一个移动平台以及六个可伸缩的推杆组成&#xff0c;通常情况下&#xff0c;固定平台与底座连接&#xff0c;移动平台在空间具有六个自由度&#xff0c;通过六个推杆…

价格很实惠,希喂、爱立方、生生不息主食冻干抗得住实测吗?

在挑选主食冻干时&#xff0c;许多宠物主人都会感到头疼。尽管主食冻干相较于普通猫粮具有诸多优势&#xff0c;但其价格也相对高昂。这导致许多宠物主人担心高价购买的主食冻干可能营养价值并不理想。然而&#xff0c;在选择时&#xff0c;我们还需要考虑其他重要因素&#xf…

Spring MVC 中 使用 RESTFul 实现用户管理系统

1. Spring MVC 中 使用 RESTFul 实现用户管理系统 文章目录 1. Spring MVC 中 使用 RESTFul 实现用户管理系统2. 静态页面准备2.1 user.css2.2 user_index.html2.3 user_list.html2.4 user_add.html2.5 user_edit.html 3. SpringMVC环境搭建3.1 创建module&#xff1a;usermgt3…

tapd 与国内外主流的8大项目管理软件大对比

对比Tapd与8大项目管理工具&#xff1a;PingCode、Worktile、Redmine、Teambition、广联达、Jira、禅道、飞书。 Tapd 是腾讯推出的一款敏捷开发管理工具&#xff0c;特别适合那些需要高效协作和快速迭代的敏捷开发团队。它支持多种敏捷方法论&#xff0c;包括Scrum和Kanban&am…

数学建模------Matlab数据可视化

目录 1.plot函数 &#xff08;1&#xff09;函数介绍 &#xff08;2&#xff09;参数介绍 &#xff08;3&#xff09;图形美化 &#xff08;4&#xff09;背景更改 &#xff08;5&#xff09;多组绘制 &#xff08;6&#xff09;图形叠加 &#xff08;7&#xff09;添加…

Elasticsearch备份数据到本地,并导入到新的服务 es 服务中

文章目录 使用elasticsearch-dump工具备份安装node.js(二进制安装)解压设置环境变量安装elasticsearch-dump docker安装使用ES备份文件到本地 使用elasticsearch-dump工具备份 这个工具备份时间比较长 安装node.js(二进制安装) wget https://nodejs.org/dist/v16.18.0/node-…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 英文单词联想(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆学长 ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 💻 ACM银牌🥈| 多次AK大厂笔试 | 编程一对一辅导 👏 感谢大家的订阅➕ 和 喜欢💗 📎在线评测链接 https://app5938.acapp.acwing.com.cn/contest/2/problem/OD…

如何利用小程序容器技术搭建小程序生态?

小程序&#xff0c;作为现代移动互联网生态中的重要基础设施&#xff0c;正以其独特的创新性和便捷性展现出勃勃生机。截至2021年&#xff0c;全网小程序的数量已经突破了700万&#xff0c;其中微信小程序的开发者达到了300万之多。这一数字不仅代表了小程序在技术层面的成熟度…

7.4总结

今天写了几道题目 最近&#xff0c;一年级学生马克西姆学习了科拉兹猜想&#xff0c;但他在讲课时没有太注意&#xff0c;所以他认为猜想中提到了以下过程&#xff1a; 有一个变量 $$$x$$$ 和一个常数 $$$y$$$ 。下面的操作要执行 $$$k$$$ 次&#xff1a; - 将 $$$x$$$ 增加…

Studying-代码随想录训练营day29| 134. 加油站、135. 分发糖果、860.柠檬水找零、406.根据身高重建队列

第29天&#xff0c;贪心part03&#xff0c;快过半了(ง •_•)ง&#x1f4aa;&#xff0c;编程语言&#xff1a;C 目录 134.加油站 135. 分发糖果 860.柠檬水找零 406.根据身高重建队列 134.加油站 文档讲解&#xff1a;代码随想录加油站 视频讲解&#xff1a;手撕加油站…