【C++入门】类的继承

文章目录

  • 前言
    • 继承是什么?
      • 为什么需要继承?
    • 在 C++ 中如何继承另一个类?
      • 访问修饰符
    • 类的多继承
      • 菱形继承
    • 继承中的构造函数和析构函数
      • 无参数的构造函数
      • 有参数的构造函数
        • 代码解释
        • 输出结果
    • 继承的好处与问题
      • 继承的好处
      • 继承的潜在问题
      • 示例代码
  • 总结


前言

C++ 是一种功能强大的编程语言,以其面向对象编程(OOP)特性而闻名。类的继承是 C++ 面向对象编程中的一个核心概念,它允许开发人员创建新的类,这些类可以继承现有类的属性和方法。通过继承,代码可以得到复用,结构更加清晰,从而提升软件开发的效率和可维护性。本篇文章将介绍 C++ 中类的继承,包括其定义、使用方法、修饰符及多继承的概念。


继承是什么?

继承是一种面向对象编程的机制,它允许一个类(子类或派生类)继承另一个类(基类或父类)的属性和方法。通过继承,子类可以复用基类的代码,同时还可以添加新的属性和方法,或者重写基类的方法以实现多态。

为什么需要继承?

  1. 代码重用:继承允许子类复用基类的代码,减少重复代码,提高开发效率。
  2. 提高可维护性:通过继承,可以更好地组织代码结构,使其更具层次性和可读性。
  3. 多态性:继承是实现多态的基础,多态允许一个接口多个实现,提高代码的灵活性和可扩展性。

在 C++ 中如何继承另一个类?

在 C++ 中,使用 : 符号来表示类的继承。语法如下:

class 基类 {// 基类的属性和方法
};class 子类 : 访问修饰符 基类 {// 子类的属性和方法
};

访问修饰符

访问修饰符用于控制基类成员在子类中的可访问性。在继承时,C++ 提供了三种访问修饰符:publicprotectedprivate

  1. public 继承:基类的 publicprotected 成员在子类中保持其访问级别不变。
  2. protected 继承:基类的 publicprotected 成员在子类中都变为 protected
  3. private 继承:基类的 publicprotected 成员在子类中都变为 private
class Base {
public:int publicVar;
protected:int protectedVar;
private:int privateVar;
};class PublicDerived : public Base {// publicVar 是 public// protectedVar 是 protected// privateVar 不可访问
};class ProtectedDerived : protected Base {// publicVar 是 protected// protectedVar 是 protected// privateVar 不可访问
};class PrivateDerived : private Base {// publicVar 是 private// protectedVar 是 private// privateVar 不可访问
};

类的多继承

C++ 允许一个类从多个基类继承,即多继承。多继承可以让子类继承多个基类的属性和方法,但也可能带来复杂性,如命名冲突和菱形继承问题。

class Base1 {
public:void show() {std::cout << "Base1 show" << std::endl;}
};class Base2 {
public:void show() {std::cout << "Base2 show" << std::endl;}
};class Derived : public Base1, public Base2 {
public:void show() {Base1::show(); // 显式调用 Base1 的 show 方法Base2::show(); // 显式调用 Base2 的 show 方法}
};

菱形继承

菱形继承是多继承的一种特殊情况,即多个派生类继承同一个基类,并且又有一个类同时继承这些派生类。这种情况可能导致基类的成员在派生类中存在多个拷贝。为了解决这个问题,可以使用虚继承。

class Base {
public:void show() {std::cout << "Base show" << std::endl;}
};class Derived1 : virtual public Base {};
class Derived2 : virtual public Base {};class Final : public Derived1, public Derived2 {// Base 的成员在 Final 中只有一份拷贝
};

继承中的构造函数和析构函数

在继承关系中,构造函数和析构函数的调用顺序如下:

构造函数:先调用基类的构造函数,再调用子类的构造函数。
析构函数:先调用子类的析构函数,再调用基类的析构函数。

无参数的构造函数

#include <iostream>class Base {
public:Base() {std::cout << "Base constructor" << std::endl;}~Base() {std::cout << "Base destructor" << std::endl;}
};class Derived : public Base {
public:Derived() {std::cout << "Derived constructor" << std::endl;}~Derived() {std::cout << "Derived destructor" << std::endl;}
};int main() {Derived obj;return 0;
}

有参数的构造函数

在 C++ 中,当一个子类继承自一个带有参数的构造函数的父类(基类)时,子类必须在其构造函数的初始化列表中显式调用基类的构造函数,并传递适当的参数。这是因为基类的构造函数不会自动被调用,必须通过子类的构造函数显式指定。

以下是一个示例,展示了如何在子类的构造函数中调用带有参数的基类构造函数。

#include <iostream>// 基类
class Base {
public:// 带有参数的基类构造函数Base(int x, int y) : a(x), b(y) {std::cout << "Base constructor called with a = " << a << " and b = " << b << std::endl;}private:int a, b;
};// 派生类
class Derived : public Base {
public:// 派生类构造函数,初始化列表中调用基类构造函数Derived(int x, int y, int z) : Base(x, y), c(z) {std::cout << "Derived constructor called with c = " << c << std::endl;}private:int c;
};int main() {// 创建派生类对象Derived obj(1, 2, 3);return 0;
}
代码解释
  1. 基类 Base

    • Base(int x, int y) : a(x), b(y) 是基类的构造函数,它接受两个整数参数 xy,并使用初始化列表将它们分别赋值给成员变量 ab
    • 在构造函数中打印出 ab 的值。
  2. 派生类 Derived

    • Derived(int x, int y, int z) : Base(x, y), c(z) 是派生类的构造函数,它接受三个整数参数 xyz
    • 在派生类构造函数的初始化列表中,调用基类构造函数 Base(x, y),并将 xy 传递给它。
    • 同时在初始化列表中,将参数 z 赋值给派生类的成员变量 c
    • 在构造函数中打印出 c 的值。
  3. main 函数

    • 创建 Derived 类的对象 obj,并传递参数 123。这将调用派生类的构造函数,并依次调用基类的构造函数。
输出结果
Base constructor called with a = 1 and b = 2
Derived constructor called with c = 3

继承的好处与问题

继承的好处

  1. 代码重用

    • 减少重复代码:继承允许子类复用基类的属性和方法,从而减少重复代码,提高开发效率。
    • 易于维护:当需要修改通用行为时,只需在基类中进行修改,所有继承该基类的子类都会自动继承这些更改,减少了维护成本。
  2. 提高可读性和组织性

    • 结构化代码:通过继承,可以将通用功能提取到基类中,使代码更具层次性和组织性,提高代码的可读性。
    • 逻辑清晰:继承关系可以清晰地表达类之间的关系和层次结构,使代码逻辑更加清晰。
  3. 实现多态性

    • 动态绑定:继承和虚函数结合使用,可以实现多态性,即在运行时根据对象的实际类型调用相应的方法,增强了程序的灵活性和可扩展性。
    • 统一接口:通过继承,可以为不同的子类提供统一的接口,调用者无需关心对象的具体类型,只需调用统一的接口方法即可。

继承的潜在问题

  1. 过度继承

    • 复杂性增加:过度使用继承可能会导致复杂的继承层次结构,增加代码的复杂性和理解难度。
    • 维护困难:复杂的继承关系会使代码的维护变得困难,尤其是在修改基类时,可能会影响到多个子类的行为。
  2. 紧耦合

    • 耦合度高:继承使子类和基类之间的耦合度增加,子类依赖于基类的实现,难以独立修改和扩展。
    • 修改风险:基类的修改可能会对所有子类产生影响,增加了修改代码的风险。
  3. 命名冲突

    • 方法重名:在多继承情况下,不同基类中可能存在同名的方法,导致命名冲突,增加了解决冲突的复杂性。
    • 数据成员冲突:如果基类中有同名的数据成员,也可能导致冲突,需特别小心处理。
  4. 菱形继承问题

    • 多重继承:多重继承时,若多个基类继承自同一个基类,可能会导致菱形继承问题,即子类中存在多个基类实例。
    • 数据冗余:菱形继承可能导致数据冗余和多义性问题,需使用虚继承来解决。

示例代码

以下示例展示了继承的好处和潜在问题。

#include <iostream>// 基类
class Base {
public:Base(int x) : a(x) {std::cout << "Base constructor called with a = " << a << std::endl;}virtual void show() {std::cout << "Base show method" << std::endl;}
private:int a;
};// 子类1
class Derived1 : public Base {
public:Derived1(int x, int y) : Base(x), b(y) {std::cout << "Derived1 constructor called with b = " << b << std::endl;}void show() override {std::cout << "Derived1 show method" << std::endl;}
private:int b;
};// 子类2
class Derived2 : public Base {
public:Derived2(int x, int z) : Base(x), c(z) {std::cout << "Derived2 constructor called with c = " << c << std::endl;}void show() override {std::cout << "Derived2 show method" << std::endl;}
private:int c;
};// 子类多继承
class MultiDerived : public Derived1, public Derived2 {
public:MultiDerived(int x, int y, int z) : Derived1(x, y), Derived2(x, z) {std::cout << "MultiDerived constructor called" << std::endl;}void show() {Derived1::show(); // 调用 Derived1 的 show 方法Derived2::show(); // 调用 Derived2 的 show 方法}
};int main() {// 创建对象并调用方法Derived1 d1(1, 2);Derived2 d2(3, 4);MultiDerived md(5, 6, 7);d1.show();  // 调用 Derived1 的 show 方法d2.show();  // 调用 Derived2 的 show 方法md.show();  // 调用 MultiDerived 的 show 方法,分别调用 Derived1 和 Derived2 的 show 方法return 0;
}

总结

继承是 C++ 面向对象编程中的一个重要特性,通过继承,开发人员可以创建层次分明、结构清晰的代码,从而提高代码的复用性和可维护性。通过合理使用访问修饰符,可以控制基类成员在子类中的可访问性,多继承则提供了更大的灵活性,但也需要注意其复杂性。掌握继承及其相关概念,对于提高 C++ 编程水平和开发效率至关重要。

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

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

相关文章

UDP通信 单播,广播,组播

UDP通信实现 #include <sys/types.h> #include <sys/socket.h> ssize_t sendto(int sockfd, const void *buf, size_t len, int flags, const struct sockaddr *dest_addr, socklen_t addrlen); - 参数&#xff1a; struct sockaddr *src_addr, socklen_t *addrlen…

最长连号(不会dp解法)

这题咋dp啊 #include<bits/stdc.h> using namespace std; int main() {int a;cin>>a;vector<int>s(a,0);vector<int>dp(a);dp[0]1; // s.push_back(1);for(int i0;i<a;i){ // cout<<s[i];cin>>s[i];}for(int i1;i<a;i){if(s[i-1]1…

数据库期末复习

数据库期末复习 分析题 1 &#xff08;1&#xff09;使用数据库系统可以大大提高应用开发的效率&#xff0c;方便用户的使用减轻数据库系统管理人员维护的负担&#xff0c;请回答数据库系统有哪些部分组成&#xff1f;什么是数据库管理系统&#xff0c;其主要功能包括哪些方而&…

vue3项目报错集合

目录 一、does not provide an export named default 一、does not provide an export named default 报错截图&#xff1a; 原因&#xff1a; vite对commonjs兼容性太差&#xff0c;导致无法引入jsoneditor&#xff0c;可以使用originjs/vite-plugin-commonjs插件解决。&am…

ThinkPHP事件的使用

技术说明 1.ThinkPHP版本&#xff1a;支持6.0、8.0 2.使用场景&#xff1a;用户登陆后日志记录、通知消息发送等主流程、次流程分离等场景 3.说明&#xff1a;网上很多帖子说的不明不白的&#xff0c;建议大家自己手动尝试总结一下 4.事件手动绑定的时候&#xff0c;一定要…

Cocos Creator2D游戏开发(7)-飞机大战(5)-让子弹飞

飞机大战(5)-碰撞及积分 参考敌机的生成 子弹由飞机生成,放在player_node节点子弹重复使用,要使用预制体;子弹新增了动画 ①创建一个预制体 命名为playerBullet_prefab ② 双击预制体将bullet1图片拖入预制体 保存,关闭(场景编辑器里面的) ③ 发射子弹 player加入代码 prop…

【网络安全】破解邀请码实现未经授权的访问和账户接管

未经许可&#xff0c;不得转载。 文章目录 前言1、邀请用户2、低级账户访问3、提取用户 ID 和 OTP4、准备字典5、攻击6、账户接管 前言 ExampleSpark&#xff08;化名&#xff09;是一个专为团队管理和项目协作而设计的强大平台。它提供了用于管理用户、项目和权限的综合工具。…

【Python中OGR和GDAL有什么区别】

OGR和GDAL在地理信息系统&#xff08;GIS&#xff09;和遥感领域都扮演着重要角色&#xff0c;但它们在功能和处理的数据类型上有所不同。以下是OGR和GDAL的主要区别&#xff1a; 一、定义与功能 GDAL&#xff08;Geospatial Data Abstraction Library&#xff09; 定义&#…

docker部署本地词向量模型

开源项目&#xff1a;GitHub - huggingface/text-embeddings-inference: A blazing fast inference solution for text embeddings models 1. 下载词向量模型 参考我的另一篇博客&#xff1a;langchain 加载本地词向量模型 2. 部署词向量模型 就三行命令 model/data/BAAI/…

【华视电子CVR100A】 身份证读取与酒店收银系统源码整合:CyberWinApp-SAAS 本地化及未来之窗行业应用跨平台架构

一、酒店系统连接身份证阅读器好处 在开房界面&#xff0c;点击读取身份证&#xff0c;可以自动读取姓名&#xff0c;性别&#xff0c;地址&#xff0c;身份证号码 1. 提高办理入住效率 - 传统的手动输入身份证信息繁琐且容易出错&#xff0c;一键读取能够快速准确地获取客人身…

机器学习算法——常规算法,在同的业务场景也需要使用不同的算法(一)

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

苏州大学学报(哲学社会科学版)

《苏州大学学报&#xff08;哲学社会科学版&#xff09;》是苏州大学主办的综合性哲学社会科学类学术期刊&#xff0c;创刊于1906年&#xff0c;是我国高等学校第一本学报。逾百年以来&#xff0c;学报始终坚持正确舆论导向&#xff0c;追踪理论前沿&#xff0c;聚焦学术热点&a…

【C语言报错已解决】Format String Vulnerability

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言 在日常开发中&#xff0c;我们经常会遇到各种各样的bug&#xff0c;其中格式化字符串漏洞报错可能是最让人头疼的一种。这…

基于SpringBoot+Vue的地方美食分享网站(带1w+文档)

基于SpringBootVue的地方美食分享网站(带1w文档) 人类的进步带动信息化的发展&#xff0c;使人们生活节奏越来越快&#xff0c;所以人们越来越重视信息的时效性。以往的管理方式已经满足不了人们对获得信息的方式、方便快捷的需求。即地方美食分享网站慢慢的被人们关注。 项目简…

Redis集群启动步骤

前提&#xff1a;处理好配置文件。 一、通过配置文件启动三个Redis实例。 执行命令&#xff1a;redis-server /opt/redis/cluster/16381/16381.conf 二、因为 Redis 集群至少需要 3 个主节点。所以这三个都是主节点&#xff0c;暂不考虑从节点。 创建一个包含 3 个主节点的…

java RestClientBuilder es 集群 鉴权

在Java中使用RestClientBuilder连接到Elasticsearch集群并进行鉴权&#xff0c;可以通过设置HttpHosts、RequestConfig以及添加相应的Header来实现。 以下是一个示例代码&#xff1a; import org.apache.http.Header; import org.apache.http.HttpHost; import org.apache.htt…

全网最适合入门的面向对象编程教程:27 类和对象的Python实现-Python中异常层级与自定义异常类的实现

全网最适合入门的面向对象编程教程&#xff1a;27 类和对象的 Python 实现-Python 中异常层级与自定义异常类的实现 摘要&#xff1a; 本文主要介绍了在使用 Python 进行面向对象编程时&#xff0c;异常的层级和如何使用继承关系完成自定义自己项目中异常类&#xff0c;并以传…

麒麟v10安装mysql5.7(ARM架构)

下载路径&#xff1a;华为云镜像 麒麟v10是潮流时代的新时髦的linux操作系统&#xff0c;但随着ARM架构流行&#xff0c;出现了一些卡点&#xff0c;不以为然&#xff0c;没当回事的大吃一惊。经常卡住。例如: 在安装mysql5.7&#xff08;ARM架构&#xff09; 最简单&#xf…

刷题了:144.二叉树的前序遍历心|145.二叉树的后序遍历心|94.二叉树的中序遍历己

递归遍历 文章讲解:https://programmercarl.com/%E4%BA%8C%E5%8F%89%E6%A0%91%E7%9A%84%E9%80%92%E5%BD%92%E9%81%8D%E5%8E%86.html#%E6%80%9D%E8%B7%AF 视频讲解:https://www.bilibili.com/video/BV1Wh411S7xt/?spm_id_from333.788&vd_sourcee70917aa6392827d1ccc8d85e1…

【Websim.ai】一句话让AI帮你生成一个网页

【Websim.ai】一句话让AI帮你生成一个网页 网站链接 websim.ai 简介 websim.ai接入了Claude Sonnet 3.5&#xff0c;GPT-4o等常用的LLM&#xff0c;只需要在websim.ai的官网指令栏中编写相关指令&#xff0c;有点类似大模型的Prompt&#xff0c;指令的好坏决定了网页生成的…