C++复习 -- 继承

news2024/11/16 3:25:20

继承基本概念

继承是面向对象编程(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.coloradmin.cn/o/1677476.html

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

相关文章

[启明智显技术分享] 在ESP32环境搭建过程中,如果在VS Code中遇到乱码问题应该怎么解决

前言&#xff1a; 【启明智显】专注于HMI&#xff08;人机交互&#xff09;及AIoT&#xff08;人工智能物联网&#xff09;产品和解决方案的提供商&#xff0c;我们深知彩屏显示方案在现代物联网应用中的重要性。为此&#xff0c;我们一直致力于为客户提供彩屏显示方案相关的技…

Gitlab、Redis、Nacos、Apache Shiro、Gitlab、weblogic相关漏洞

文章目录 一、Gitlab远程代码执行&#xff08;CVE-2021-22205&#xff09;二、Redis主从复制远程命令执行三、Nacos认证绕过漏洞&#xff08;CVE-2021-29441&#xff09;四、Apache Shiro认证绕过漏洞&#xff08;CVE-2020-1957&#xff09;五、Gitlab任意文件读取漏洞&#xf…

(done) NLP+HMM 协作,还有维特比算法

参考视频&#xff1a;https://www.bilibili.com/video/BV1aP4y147gA/?p2&spm_id_frompageDriver&vd_source7a1a0bc74158c6993c7355c5490fc600 &#xff08;这实际上是 “序列标注任务”&#xff09; HMM 的训练和预测如下图 训练过程&#xff1a;我们首先先给出一个语…

【leetcode面试经典150题】-27. 移除元素

88.合并两个有序数组 1 题目介绍1 个人解题思路1.1 解题代码1.2 思路解析 2、分析官方题解2.1 单侧双指针2.2 双侧双指针 1 题目介绍 给你一个数组 nums 和一个值 val&#xff0c;你需要 原地 移除所有数值等于 val 的元素&#xff0c;并返回移除后数组的新长度。 不要使用额外…

【Segment Anything Model】十四:原始SAM模型如何传入多框

之前第二三篇有更新过单点&#xff0c;多点&#xff0c;单框。本篇加上多框输入。 先确定一下目录 新建test_boxes.py文件&#xff0c;复制以下代码 import sys import torch import numpy as np from datetime import datetime import matplotlib.pyplot as plt from Net.se…

mysql 行转列 case when 和 聚合函数实现

一、原始数据## 二、行转列 第一步 SELECTCASE WHEN SUBSTRING( aaa.cost_code, 1, 3 ) 100 THEN aaa.budget_cost_budget ELSE 0 END b1,CASE WHEN SUBSTRING( aaa.cost_code, 1, 3 ) 300 THEN aaa.budget_cost_budget ELSE 0 END b2,CASE WHEN SUBSTRING( aaa.cost_cod…

JeeSite Vue3:前端开发页面如何动态设置菜单展示模式?

推荐阅读&#xff1a; JeeSite Vue3&#xff1a;前端开发的未来之路(更新版) 随着技术的飞速发展&#xff0c;前端开发技术日新月异。在这个背景下&#xff0c;JeeSite Vue3 作为一个基于 Vue3、Vite、Ant-Design-Vue、TypeScript 和 Vue Vben Admin 的前端框架&#xff0c;引…

掌握未来的数字设计:深入浅出FPGA学习笔记,从新手到专家的全面指南!

在数字电路设计领域&#xff0c;现场可编程门阵列&#xff08;Field-Programmable Gate Array, FPGA&#xff09;是一种非常灵活且功能强大的技术。它允许设计师通过编程来自定义硬件逻辑&#xff0c;以适应不同的应用需求。本文将全面详细地介绍FPGA的学习笔记&#xff0c;包括…

CKA-Ubuntu18.04安装Kubernetes集群

文档整理参考:虫之教育唐老师 文章目录 K8S是什么修改静态ip环境准备修改更新源安装Docker安装K8S-master1.安装kubeadm, kubelet, kubectl2.初始化3.创建kubeadm-config.yaml4.查看是否安装成功运行集群环境报错排查问题安装网络安装K8S-node1,2步参考master3.查看是否安装成…

Java线程生命周期:Java线程生命周期全景解读

1. 线程生命周期概述&#xff1a;不仅仅是状态转换 在多线程编程中&#xff0c;理解线程的生命周期对于编写有效、高效的代码至关重要。线程生命周期通常描述了线程从创建到死亡的一系列状态变化过程&#xff0c;但其实不仅仅局限于这些状态的简单转换。线程生命周期的理解应该…

PHP黑魔法之strcmp与is_numeric绕过

1、strcmp绕过 PHP手册: int strcmp ( string $str1 , string $str2 )Return ValuesReturns < 0 if str1 is less than str2; > 0 if str1 is greater than str2, and 0 if they are equal 当输入的两个值为不是字符串时就会产生不预期的返回值 strcmp()在比较字符串和…

PyQt5编写的一个简易图像处理软件

文章目录 1. 简介2. 准备工作3. 主界面设计4. 功能构建5. 总结 1. 简介 通过编写简易图像处理软件&#xff0c;你可以学习如何使用 PyQt5 构建用户界面&#xff0c;以及如何与用户交互。同时&#xff0c;你还可以学习图像处理技术&#xff0c;如图像读取、傅里叶变换、滤波、增…

三、安装node_exporter

目录 一、简介 二、下载安装 一、简介 Exporter是Prometheus的指标数据收集组件。它负责从目标Jobs收集数据&#xff0c;并把收集到的数据转换为Prometheus支持的时序数据格式。 和传统的指标数据收集组件不同的是&#xff0c;他只负责收集&#xff0c;并不向Server端发送数据…

百度文心一言 java 支持流式输出,Springboot+ sse的demo

参考&#xff1a;GitHub - mmciel/wenxin-api-java: 百度文心一言Java库&#xff0c;支持问答和对话&#xff0c;支持流式输出和同步输出。提供SpringBoot调用样例。提供拓展能力。 1、依赖 <dependency> <groupId>com.baidu.aip</groupId> <artifactId…

Vue3使用datav3报错的三个问题解决

我这里写的是按需引入 报错问题Cannot find module dataview/datav-vue3 修改datav源码中的package.json文件 修改为 "module": "./es/index.mjs", 然就就会遇见新的报错问题 报错问题TypeError: Cannot read properties of null (reading $el) 然后修改…

Day 46 139.单词拆分

单词拆分 给定一个非空字符串 s 和一个包含非空单词的列表 wordDict&#xff0c;判定 s 是否可以被空格拆分为一个或多个在字典中出现的单词。 说明&#xff1a; 拆分时可以重复使用字典中的单词。 你可以假设字典中没有重复的单词。 示例 1&#xff1a; 输入: s “leet…

智能监控与安全管理:安全帽检测算法的实践与应用

在工地、煤矿等高危工作环境中&#xff0c;安全帽的佩戴至关重要。安全帽能够有效防止因坠落物体或碰撞等引起的头部伤害&#xff0c;从而保护工作人员的生命安全。然而&#xff0c;传统的检查人员佩戴安全帽的方式主要依赖于现场监督和巡查&#xff0c;这种方法不仅耗费大量人…

PDF编辑阅读器PDF Expert for Mac v3.10.1中文激活版

PDF Expert for Mac是一款易于使用的 PDF 编辑器和注释器&#xff0c;专为 Mac 设备设计。它允许用户轻松查看、编辑、签名、注释和共享 PDF。该软件使用户能够向他们的 PDF 添加文本、图像、链接和形状&#xff0c;突出显示和标记文本&#xff0c;填写表格以及签署数字文档。它…

更高、更快、更强,受管文件传输应该注意的三个要素

受管文件在很多公司内部都存在这个分类&#xff0c;受管文件不是特定的某一文件&#xff0c;而是指的是在一个组织或企业内&#xff0c;被正式管理和控制的文件。这些文件通常包含重要的信息&#xff0c;如技术规格、标准操作程序&#xff08;SOPs&#xff09;、质量手册、设计…