C++的面向对象学习(7):面向对象编程的三大特性之:继承

文章目录

  • 前言
  • 一、继承:继承的类除了拥有上一级类的共性,也拥有自己的特性。
  • 二、继承方式:公有继承(public inheritance)、私有继承(private inheritance)和保护继承(protected inheritance)
    • 1.公共继承
    • 2.保护继承
    • 3.私有继承
  • 三、子类实例化对象后,父类继承的成员哪些属于子类对象?
  • 四、子类继承了父类后,子类的构造与析构函数怎么被继承使用呢?
    • 1.继承的构造函数与析构函数执行顺序?
    • 2.父类如果写了构造函数,子类怎么写构造函数呢?
  • 五、父类子类出现同名成员变量处理方式
  • 六、多继承:一个类继承多个类
    • 1.语法:class 子类 : 继承方式 父类1, 继承方式 父类2
    • 2.缺点:如果不同父类存在变量或者函数重名的情况,子类就必须用作用域::来指定。可能会引起命名冲突和二义性问题。
  • 七、菱形继承方式
  • 总结:继承的重要性


前言

前面几节学的基本是两块内容:第一块是C++的一些特性,比如重载、引用、函数参数值传递与地址传递。第二块是面向对象编程的三大特性的其一:封装。封装中涉及了格式、成员变量和成员函数、访问权限、实例化对象、构造函数与析构函数、成员变量与成员函数的存储位置、this指针、友元声明、operator声明的运算符重载等知识。

现在就要接触到面向对象编程的三大特性的其二:继承。

一、继承:继承的类除了拥有上一级类的共性,也拥有自己的特性。

继承的主要优势在于代码的重用性和扩展性。通过继承,子类可以直接使用父类的属性和方法,无需重新编写相同的代码。这样可以减少代码的冗余,并提高代码的可维护性。同时,子类还可以在继承的基础上添加自己的特性,以满足特定的需求

在继承关系中,父类通常是一个更通用、抽象的类,而子类则是在父类基础上进行特化和扩展的类。子类可以通过继承获得父类的属性和方法,并且可以添加新的属性和方法,或者重写父类的方法以实现自己的逻辑。

继承还可以形成类的层次结构,使得代码的组织更加清晰和易于理解。通过继承,可以将类按照其关系进行分类和组织,形成一个类的层次结构,从而更好地组织和管理代码。
举个例子:

#include <iostream>
using namespace std;class Animal {
protected:string name;public:Animal(string name) {this->name = name;}void speak() {cout << "动物发出声音" << endl;}
};class Dog : public Animal {
private:string breed;public:Dog(string name, string breed) : Animal(name) {this->breed = breed;}void speak() {cout << "汪汪汪!" << endl;}void fetch() {cout << "狗狗正在追逐球" << endl;}
};int main() {Animal animal("动物");animal.speak();  // 输出:动物发出声音Dog dog("旺财", "哈士奇");dog.speak();  // 输出:汪汪汪!dog.fetch();  // 输出:狗狗正在追逐球return 0;
}

Animal类是父类,它有一个name属性和一个speak方法。Dog类是子类,它继承了Animal类,并且添加了一个新的属性breed(品种)和一个新的方法fetch(追逐)。

继承的语法:
class 子类: 继承方式 父类

子类也叫派生类,父类也叫基类。

二、继承方式:公有继承(public inheritance)、私有继承(private inheritance)和保护继承(protected inheritance)

在这里插入图片描述

1.公共继承

使用关键字public来指定继承方式。
子类继承了父类的公开成员和保护成员,但不继承父类的私有成员(即不能访问)。
父类的公开接口成员函数既可以让外部调用,也可以让子类调用。

2.保护继承

使用关键字protected来指定继承方式。
子类继承父类的公开成员和保护成员,且在子类中都变为保护成员,父类的私有成员仍然不能访问
父类的接口函数限制在子类和子类的派生类中,外部无法直接访问父类的成员

3.私有继承

使用关键字private来指定继承方式。
子类继承父类的公开成员和保护成员,且在子类中都变为私有成员,父类的私有成员仍然不能访问
私有继承将父类的接口隐藏起来,子类不能直接访问父类的成员函数,只能通过子类自己的公有成员或者友元函数来间接访问。

在这里插入图片描述
子类中无法访问父类私有的权限,但是可以访问公开和受保护的权限。
有几个注意的地方:
①保护权限的成员,只能在子类内部访问,而不能在外部的主函数里访问。
子类继承父类的protected变量,不能在主函数里用对象调用吗?
保护成员可以在子类内部和子类对象中访问,但不能在类外部直接访问。

②子类继承父类后,孙子类应该继承子类的哪些成员呢?
答:当子类继承父类后,孙子类会继承子类的所有成员,包括公有成员、保护成员和私有成员。孙子类可以直接访问子类的公有成员和保护成员,但无法直接访问子类的私有成员。继承的层次可以一直延续下去,每个子类都可以成为下一个子类的父类。

三、子类实例化对象后,父类继承的成员哪些属于子类对象?

在这里插入图片描述
儿子类继承了父类的三个不同权限的成员变量,自己有一个独特的成员变量,那sizeof(son)的结果到底是多少呢?
答案是子类的对象拥有了这四个变量的空间,即使父类有一个私有变量,子类只是不能访问,但实例化对象时也开辟了它的空间。

四、子类继承了父类后,子类的构造与析构函数怎么被继承使用呢?

1.继承的构造函数与析构函数执行顺序?

构造函数的继承:子类会继承父类的构造函数。当创建子类对象时,会先调用父类的构造函数,然后再调用子类自身的构造函数。这样可以确保父类的成员被正确初始化。

析构函数的继承:子类会继承父类的析构函数。当子类对象被销毁时,会先调用子类自身的析构函数,然后再调用父类的析构函数。这样可以确保父类的资源被正确释放。

2.父类如果写了构造函数,子类怎么写构造函数呢?

class father {
private:string name;int age;
protected:int money;
public:father() {name = "xiaogang";age = 38;money = 6000;address = "nanjing";}string address;
};

子类:

class son :public father {
public:son() {money = 5000;address = "beijing";height = 150;}int height;
};

也就是说,父类的构造函数在父类写好后,子类继承时就不能用默认构造函数去实例化对象了,而是要重新写一个含参的构造函数。

一定要注意一点:
子类的对象和父类的对象是完全不同的两个对象,他们各自的成员变量的地址是不同的。构造函数里面的赋值,也只是给自己的对象的成员变量赋值而已

int main() {father f;son son1;cout << son1.address << endl;//儿子是北京cout << f.address << endl;//父亲是南京return 0;
}

五、父类子类出现同名成员变量处理方式

举个例子,父类有个成员变量叫friends,子类也有一个成员变量叫friends。任何通过子类的对象去访问父类的同名成员变量呢?
使用作用域声明:

son1.father::friends
class father {
private:string name;int age;
protected:int money;
public:father() {name = "xiaogang";age = 38;money = 6000;address = "nanjing";friends = "limiing";}string address;string friends;
};class son :public father {
public:son() {money = 5000;address = "beijing";height = 150;friends = "xiaohong";}int height;string friends;
};int main() {father f;son son1;cout << son1.father::friends << endl;return 0;
}

对象son1调用了父亲作用域下的成员变量。

六、多继承:一个类继承多个类

1.语法:class 子类 : 继承方式 父类1, 继承方式 父类2

比如:class C : public A, public B

#include <iostream>
using namespace std;// 基类A
class A {
public:void displayA() {cout << "This is class A" << endl;}
};// 基类B
class B {
public:void displayB() {cout << "This is class B" << endl;}
};// 派生类C,继承自类A和类B
class C : public A, public B {
public:void displayC() {cout << "This is class C" << endl;}
};int main() {C c;c.displayA();  // 调用继承自类A的成员函数c.displayB();  // 调用继承自类B的成员函数c.displayC();  // 调用派生类C自己的成员函数return 0;
}

2.缺点:如果不同父类存在变量或者函数重名的情况,子类就必须用作用域::来指定。可能会引起命名冲突和二义性问题。

七、菱形继承方式

在这里插入图片描述

总结:继承的重要性

继承是C++中的一个重要特性,被广泛应用于面向对象编程中。在实际开发中,继承被广泛用于代码复用和扩展性设计。

下面是一些继承的常见应用场景:

实现类的层次结构:通过继承,可以将类组织成层次结构,从而更好地组织和管理代码。

代码复用:通过继承,可以将一个类的成员函数和成员变量复用到另一个类中,从而减少代码量,提高代码的可维护性和可重用性。

多态性:通过继承和虚函数,可以实现多态性,即同一个函数在不同的派生类中具有不同的实现。

接口设计:通过继承和抽象类,可以定义接口,从而实现代码的松耦合和可扩展性。

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

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

相关文章

代码回滚(git reset)后push失败的解决方法

问题描述 代码本地回滚之后&#xff08;即 git reset 到之前的某个历史节点&#xff09;&#xff0c;push上去失败&#xff0c;并报出以下错误信息 ! [rejected] master -> master (non-fast-forward) error: failed to push some refs to gitgithub.com:PisecesPeng/useg…

跨境电商迎来综合竞争力比拼时代 五大趋势解读跨境2024

过去几年&#xff0c;跨境电商成为外贸出口增长的一大亮点&#xff0c;随着年底国务院办公厅《关于加快内外贸一体化发展的若干措施》的发布&#xff0c;跨境电商在促进经济发展、助力内外贸一体化发展方面的价值更加凸显。 这是跨境电商变化最快的时代&#xff0c;也是跨境电…

Java核心知识点1-java和c++区别、隐式和显示类型转换

java和c区别 java通过虚拟机实现跨平台特性&#xff0c;但c依赖于特定的平台。java没有指针&#xff0c;它的引用可以理解为安全指针&#xff0c;而c和c一样具有指针。java支持自动垃圾回收&#xff0c;而c需要手动回收。java不支持多重继承&#xff0c;只能通过实现多个接口来…

音频播放软件Foobar2000 mac特点介绍

Foobar2000 mac是一款高度可定制的音频播放器&#xff0c;适用于Windows平台。它支持各种音频格式&#xff0c;包括MP3、FLAC、AAC、WMA等&#xff0c;同时也支持各种音频插件和效果器&#xff0c;可以提供更好的音质和用户体验。 Foobar2000 mac软件特点 1. 高度可定制&#…

探索效率与可扩展性:MinIO图片服 VS FastDFS图片服

目录 1、前言 2、背景知识 2.1 Minio图片服的概述 2.2 FastDFS图片服的概述 3、性能比较 3.1 存储性能比较 3.1.1 对比上传速度和下载速度 3.1.2 比较两者的读写性能 3.2 负载均衡性能比较 4、可扩展性比较 4.1 横向扩展性性能比较 4.2 纵向扩展性性能比较 5、结语…

大模型微调LoRA训练与原理

1.什么是LoRA&#xff1f; LoRA的全称是LOW-RANK-ADAPTATION。是一种实现迁移学习的技术手段。 2. 矩阵的秩&#xff1f; 秩是一个向量空间的基向量的个数。例如&#xff1a;二维平面坐标系存在两个基向量&#xff0c;平面上任意的一个向量都可以使用这两个基向量进行线性表示…

Vue模板编译

Vue模板编译 Vue生命周期中&#xff0c;在初始化阶段各项工作做完之后调用了vm.$mount方法&#xff0c;该方法的调用标志着初始化阶段的结束和进入下一个阶段&#xff0c;从官方文档给出的生命周期流程图中可以看到&#xff0c;下一个阶段就进入了模板编译阶段(created和befor…

Java集合/泛型篇----第一篇

系列文章目录 文章目录 系列文章目录前言一、ArrayList和linkedList的区别二、HashMap和HashTable的区别三、Collection包结构,与Collections的区别四、泛型常用特点前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站…

【网络安全 | XCTF】simple_transfer

考察kali基本工具的使用 方法一 打开文件如图&#xff1a; 存在较多协议&#xff0c;将协议分级&#xff1a; 可以看到DLEP协议占比最大&#xff1a; 将其作为过滤器应用&#xff1a; 搜索DLEP&#xff1a; 并没有有利信息&#xff0c;但观察到多数数据包损坏&#xff1a; 执行…

湘潭大学-2023年下学期-c语言-作业0x0a-综合1

A 求最小公倍数 #include<stdio.h>int gcd(int a,int b) {return b>0?gcd(b,a%b):a; }int main() {int a,b;while(~scanf("%d%d",&a,&b)){if(a0&&b0) break;printf("%d\n",a*b/gcd(a,b));}return 0; }记住最大公约数的函数&…

Java进阶(第八期): Java中递归的的使用和递归解决一些算法问题 Java中的异常机制、异常的处理逻辑 自定义异常

文章目录 一、递归1.1 递归的介绍1.2 递归的简单练习1.3 图解递归执行流程&#xff1a;1.4 使用递归完成悲波那契数列1.5 猴子吃桃子问题 二、异常三 、异常的处理逻辑3.1 try catch 捕获异常3.2 throws抛出异常 四、自定义异常 Java进阶&#xff08;第八期&#xff09; 一、递…

深入探索MySQL主从架构与读写分离:提升数据安全和性能的实战指南

一、实验目的与环境 实验目的&#xff1a; MySQL是互联网中广泛使用的开源数据库。在开发时&#xff0c;我们通常使用单机服务&#xff0c;但在生产环境中&#xff0c;由于数据量庞大和高安全性要求&#xff0c;单机MySQL无法满足这些需求。因此&#xff0c;生产环境中的MySQL需…