C++复习 -- 继承

ops/2024/9/20 4:03:11/ 标签: c++, 开发语言, 继承, 虚函数, 权限

继承基本概念

继承是面向对象编程(OOP)中的一个核心概念,特别是在C++中。它允许一个类(称为派生类或子类)继承另一个类(称为基类或父类)的属性和方法

继承的主要目的是实现代码重用,以及建立一种类型之间的层次关系。


特点


1. 代码重用:子类继承了父类的属性和方法,减少了代码的重复编写。
2. 扩展性:子类可以扩展父类的功能,添加新的属性和方法,或者重写(覆盖)现有的方法。
3. 多态性:通过继承虚函数,C++支持多态,允许在运行时决定调用哪个函数。基本用法


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


=========================================
C语音实现继承  --  在子类结构体里面声明父类 --> 不太好用 --> 结构体的组合 - 并不能实现完美的继承:

// 继承没有指定 权限 就是私有继承(default)

实例


=======================================


case1: 基本使用 

#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;
}


======================================


case2:分文件实现继承

animal.h

#ifndef ANIMAL_H
#define ANIMAL_H#include <string>
#include<iostream>
using namespace  std;class Animal
{
public:string  name;int age;Animal();void makeSound();void eatFood();
};#endif // ANIMAL_H


-------------------------------------------


animal.cpp

#include "animal.h"Animal::Animal()
{}void Animal::makeSound()
{cout<<"动物叫"<<endl;
}void Animal::eatFood()
{cout<<"动物进食"<<endl;
}


======================

cat.h

#ifndef CAT_H
#define CAT_H
#include "animal.h"class cat : public Animal
{
public:void eatFish();cat();
};#endif // CAT_H


cat.cpp

#include "cat.h"void cat::eatFish()
{cout<<"猫吃鱼"<<endl;
}cat::cat()
{}


lion.h

#ifndef LION_H
#define LION_H
#include "animal.h"class lion : public Animal
{
public:int sleepingTime;void hunt();lion();
};#endif // LION_H


lion.cpp

#include "lion.h"void lion::hunt()
{cout<<"狮子打猎"<<endl;
}lion::lion()
{}


main.cpp

#include <iostream>
#include "animal.h"
#include "lion.h"
#include "cat.h"using namespace std;int main()
{Animal a;a.makeSound();lion l;l.hunt();cat c;c.eatFish();return 0;
}

==========================


权限继承的影响:

权限

case: 配合权限图观看:

#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 stateOfTop){
//    this->contry = contry;
//    this->price = price;
//    this->stateOfTop = 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;
}

注意


// 基类默认构造的时候子类可以自己实现构造函数
   但是基类写了构造函数,子类就必须继承他的构造函数扩写

不然报错如下:
main.cpp:24:5: error: constructor for 'Roadster' must explicitly initialize the base class 'Vehicle' which does not have a default constructor
main.cpp:5:7: note: 'Vehicle' declared here

============================


虚函数:


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


virtual 关键字


1. 使用场景:在基类中声明虚函数
2. 目的:允许派生类重写该函数,实现多态。
3. 行为:当通过基类的指针或引用调用一个虚函数时,调用的是对象实际类型的函数版本。
4. 示例:

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

override 关键字


1. 使用场景:在派生类中重写虚函数
2. 目的:明确指示函数意图重写基类的虚函数
3. 行为:确保派生类的函数确实重写了基类中的一个虚函数。如果没有匹配的虚函数,编译器会报
错。
4. 示例:


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


注意点


只在派生类中使用 override: override 应仅用于派生类中重写基类的虚函数


虚析构函数:如果类中有虚函数,通常应该将析构函数也声明为虚的。
默认情况下,成员函数不是虚的:在C++中,成员函数默认不是虚函数。只有显式地使用 virtual
关键字才会成为虚函数


继承中的虚函数:一旦在基类中声明为虚函数,该函数在所有派生类中自动成为虚函数,无论是否
使用 virtual 关键字。
正确使用 virtual 和 override 关键字有助于清晰地表达程序员的意图,并利用编译器检查来避免常
见的错误,如签名不匹配导致的非预期的函数重写。

case:

#include <iostream>
using namespace std;
//基类,父类
class Vehicle{ //交通工具,车,抽象的概念
public:string contry;double price;Vehicle (){};Vehicle(string contry, double price){cout << "基类的构造函数被调用" << endl;this->contry = contry;this->price = price;};
//虚函数virtual  void run(){cout << "车跑起来了" << endl;}void stop();
};
class Bike : public Vehicle{
public:void run() override{// 虚函数重写cout<<"脚踩自行车"<<endl;}};int main()
{Bike b;b.run();return 0;
}


=============================================


多重继承:

概念

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


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

case

#include <iostream>
using namespace std;
class ClassA {
public:
void displayA() {
std::cout << "Displaying ClassA" << std::endl;
}
void test(){
cout<<"A"<<endl;
}};
class ClassB {
public:
void displayB() {
std::cout << "Displaying ClassB" << std::endl;
}
void test(){
cout<<"A"<<endl;
}
};
class Derived : public ClassA, public ClassB {
public:
void display() {
displayA(); // 调用 ClassA 的 displayA
displayB(); // 调用 ClassB 的 displayB
ClassA::test();
}
};
int main() {
Derived obj;
obj.displayA(); // 调用 ClassA 的 displayA
obj.displayB(); // 调用 ClassB 的 displayB
obj.display(); // 调用 Derived 的 display
return 0;
}

-------------------------------------------------
//重名:需要指明要调用哪个类的:

注意事项


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


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


设计考虑:虽然多重继承提供了很大的灵活性,但过度使用可能导致代码难以理解和维护。在一些
情况下,使用组合或接口(纯虚类)可能是更好的设计选择。
多重继承是C++的一个强大特性,但应谨慎使用。合理地应用多重继承可以使代码更加灵活和强大,但不当的使用可能导致设计上的问题和维护困难。

继承


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

case- 虚继承解决菱形继承

#include <iostream>
using namespace std;class Base {
public:
int data;
Base(int data){this->data = data;
}
void printInfo(){cout<<data<<endl;
}};
class Derived1 : virtual public Base { //虚继承
// 继承自 Base
public:Derived1(int data):Base(data){}};
class Derived2 : virtual public Base {
// 继承自 Base
public:Derived2(int data):Base(data){}};
class FinalDerived : public Derived1, public Derived2 {
// 继承自 Derived1 和 Derived2
public:FinalDerived(int data):Base(data),Derived2(data),Derived1(data){}};int main()
{FinalDerived final(10);//final.data = 10; //菱形继承不允许,需要加入虚继承解决final.printInfo();return 0;
}


http://www.ppmy.cn/ops/41554.html

相关文章

thinkphp8扩展think-swoole4.0-事件监听代码

首先服务端配置监听 swoole.php <?phpreturn [http > [enable > true,host > 0.0.0.0,port > 8000,worker_num > swoole_cpu_num(),options > [],],websocket > [enable > true,handler > \think\swo…

Mac电脑安装打开APP显示问题已损坏 问题解决

当MAC电脑安装完软件打开时&#xff0c;显示文件已损坏&#xff0c;无法打开。搜了很多教程终于找到解决方案&#xff0c;记录下方便以后再用。 我的mac电脑是intel芯片的&#xff0c;如果你遇到这个问题&#xff0c;可以参考我的这个方案。 1.首先当打开软件后出现 “xx软件已…

AIGC、LLM 加持下的地图特征笔记内容生产系统架构设计

文章目录 背景构建自动化内容生产平台系统架构设计架构详细设计流程介绍笔记来源笔记抓取干预 笔记 AIGC 赋能笔记 Rule 改写笔记特征库构建 附录Bash Cron 定时任务Golang 与 Pyhon AIGC 实践 小结 背景 在大模型的浪潮下&#xff0c;ChatGPT、Sora、Gemini、文言一心 等新技…

使用poi生成word文件时,zip相关的报错

apache poi-检测到Zip Bomb解决方案_zip bomb detected! the file would exceed the max. -CSDN博客

CentOS Linux 7 一键安装和卸载docker docker-compose

install_docker.sh #!/bin/bash # 安装 Dockerecho "下载关于Docker的依赖环境" echo "安装yum-utils包" sudo yum -y install yum-utils device-mapper-persistent-data lvm2 echo "设置存储库" sudo yum-config-manager --add-repo http://mi…

测试docker GPU性能损失

NVIDIA 3090 利用HSOpticalFlow代码测试docker GPU性能损失 docker介绍图如下&#xff1a; 形象生动展示了他们之间的关系 今天要测试docker容器运行HSOpticalFlow算法的性能损失&#xff0c;包括CPU和GPU 上一篇博客 http://t.csdnimg.cn/YW5kE 我已经介绍了使用docker和nvid…

暗黑4可以搬砖吗?暗黑4怎么搬砖 搬砖攻略

暗黑4可以搬砖吗&#xff1f;暗黑4怎么搬砖 搬砖攻略 暗黑破坏神4属于是暴雪旗下一款经典游戏IP&#xff0c;在全世界有着广泛的玩家群体&#xff0c;更是在今年暴雪国服宣布回归之后&#xff0c;吸引了一大批新玩家加入。今天小编就为大家带来暗黑4的详细搬砖教程。 现在我们…

matlab人脸识别

在MATLAB中实现人脸识别通常涉及到图像处理、特征提取和分类器的使用。下面是一个简化的MATLAB人脸识别代码的概述&#xff0c;使用了PCA&#xff08;主成分分析&#xff09;作为特征提取方法&#xff0c;以及简单的分类器&#xff08;如最近邻分类器&#xff09;进行分类。请注…

Ubuntu 22.04 下 Pycharm 卸载

由于调试原因&#xff0c;Ubuntu22 下重装Pycharm 1.卸载 PyCharm 删除以下几个目录&#xff1a; 1) 程序文件目录 所有的相关文件都保存在解压缩的目录中&#xff0c; /opt/pycharm-community/ $ sudo rm -r /opt/pycharm-community/ 2) 配置文件目录 启动 PyCharm 后&…

ES 数据写入方式:直连 VS Flink 集成系统

ES 作为一个分布式搜索引擎&#xff0c;从扩展能力和搜索特性上而言无出其右&#xff0c;然而它有自身的弱势存在&#xff0c;其作为近实时存储系统&#xff0c;由于其分片和复制的设计原理&#xff0c;也使其在数据延迟和一致性方面都是无法和 OLTP&#xff08;Online Transac…

安全风险 - 如何解决 setAccessible(true) 带来的安全风险?

可能每款成熟的金融app上架前都会经过层层安全检测才能执行上架&#xff0c;所以我隔三差五就能看到安全检测报告中提到的问题&#xff0c;根据问题的不同级别&#xff0c;处理的优先级也有所不同&#xff0c;此次讲的主要是一个 “轻度问题” &#xff0c;个人认为属于那种可改…

基于springboot的新闻推荐系统源码数据库

基于springboot的新闻推荐系统源码数据库 随着信息互联网购物的飞速发展&#xff0c;国内放开了自媒体的政策&#xff0c;一般企业都开始开发属于自己内容分发平台的网站。本文介绍了新闻推荐系统的开发全过程。通过分析企业对于新闻推荐系统的需求&#xff0c;创建了一个计算…

物联网到底物联了个啥?——青创智通

工业物联网解决方案-工业IOT-青创智通 物联网&#xff0c;这个听起来似乎颇具科技感和未来感的词汇&#xff0c;其实早已悄然渗透到我们生活的方方面面。从智能家居到智慧城市&#xff0c;从工业自动化到医疗健康&#xff0c;物联网技术正在以其独特的魅力改变着我们的生活方式…

查找总价格为目标值的两个商品(双指针)

算法原理&#xff1a; 其实我们首先想到的方法肯定是暴力&#xff0c;两个for循环嵌套就能找到&#xff0c;但肯定会超时。 其实啊一切算法的总结都是在暴力的基础上进行的&#xff0c;算法其实就是对暴力进一步的优化。 定义两个指针&#xff0c;分别指向两端&#xff0c;然后…

输电线路的覆冰

给出一些输电线路的覆冰类型 输电线路的覆冰类型可以根据其形成机理、条件及性质进行不同的分类。以下是一些主要的覆冰类型&#xff1a; 凝华覆冰&#xff1a;这种覆冰是近地表面空气中的水分因气温过低而直接凝结在输电线路表面的一种霜&#xff0c;也被称为晶状雾凇。云中…

软考-下午题-试题一

1、概念 2、答题技巧和规范 问题1、2&#xff1a;直接看 格式&#xff1a; 问题3&#xff1a; 格式&#xff1a; 3、例题 eg2&#xff1a;可以以后写完问题4之后&#xff0c;把问题3补充完整 问题4&#xff1a; 问题4 官方解释&#xff1a; 问题4&#xff08;3‘&#xff09; 2…

百面算法工程师 | YOLOv6面试考点原理全解析

本文给大家带来的百面算法工程师是深度学习目标检测YOLOv6面试总结&#xff0c;文章内总结了常见的提问问题&#xff0c;旨在为广大学子模拟出更贴合实际的面试问答场景。在这篇文章中&#xff0c;我们还将介绍一些常见的深度学习目标检测面试问题&#xff0c;并提供参考的回答…

算法详解——回溯法

一、回溯法概述——问题背景 回溯法是一种解决约束满足问题的方法&#xff0c;特别适用于解决组合问题、搜索优化问题等。它通过逐步构建候选解决方案并且在这个解决方案不再可能满足约束或条件时进行剪枝和回溯。具体来说&#xff0c;回溯法可以应用于以下类型的问题&#xff…

OpenMesh 最长边细分算法

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 这是一个很简单的算法,其特点在于使用“最长边”(LongestEdge)的某个阈值(T)作为细分的标准,并且这个细分是均匀进行的,即尽量保持各个部分的密度或复杂度相近。 具体的算法描述: 输入:一个初始的图形或网…

AI智能对话绘画二合一系统源码 在线生成绘画 带完整的源代码包以及搭建教程

系统概述 AI智能对话绘画二合一系统源码是一款集成了自然语言处理、深度学习、计算机视觉等多种技术的智能系统。该系统通过强大的自然语言处理能力&#xff0c;能够与用户进行流畅的AI对话&#xff0c;无论是创作构思、风格选择还是技巧咨询&#xff0c;系统都能给出精准的建…