继承是面向对象编程的三大特性之一,也是C中实现代码复用和多态的重要机制。本文将带你深入理解C继承的核心概念与应用。

一、继承的基本概念

1.1 什么是继承?

继承允许我们基于已有的类创建新类,新类(派生类)可以继承已有类(基类)的属性和方法,并添加自己的特性。

继承的优势:

  • 代码复用:避免重复编写相同代码

  • 扩展性:在现有类基础上添加新功能

  • 层次结构:建立类之间的层次关系

1.2 继承语法

class BaseClass {// 基类成员
};class DerivedClass : access-specifier BaseClass {// 派生类成员
};

访问说明符:

  • public:基类的公有成员在派生类中保持公有

  • protected:基类的公有成员在派生类中变为保护

  • private:基类的公有和保护成员在派生类中变为私有(默认)

二、继承类型详解

2.1 公有继承(public)

最常用的继承方式,遵循"is-a"关系

class Animal {
public:void eat() { cout << "Eating..." << endl; }
protected:int age;
};class Dog : public Animal {
public:void bark() { eat();      // 可访问基类public方法age = 2;    // 可访问基类protected成员cout << "Woof!" << endl; }
};int main() {Dog myDog;myDog.eat();    // 输出: Eating...myDog.bark();   // 输出: Woof!
}

2.2 保护继承(protected)

基类的公有和保护成员在派生类中都变为保护

class Vehicle {
public:void start() { cout << "Starting..." << endl; }
};class Car : protected Vehicle {
public:void drive() { start();  // 在派生类中可以访问}
};int main() {Car myCar;// myCar.start(); // 错误! 在类外不可访问myCar.drive();    // 正确
}

2.3 私有继承(private)

基类的所有成员在派生类中都变为私有(默认继承方式)

class Engine {
public:void ignite() { cout << "Igniting..." << endl; }
};class Car : private Engine { // private可省略
public:void start() { ignite();  // 在派生类中可以访问}
};int main() {Car myCar;// myCar.ignite(); // 错误! 在类外不可访问myCar.start();     // 正确
}

三、派生类的构造与析构

3.1 构造顺序

  1. 基类构造函数

  2. 派生类的成员对象构造函数

  3. 派生类自身构造函数

3.2 析构顺序

与构造顺序相反:

  1. 派生类自身析构函数

  2. 派生类的成员对象析构函数

  3. 基类析构函数

class Base {
public:Base() { cout << "Base constructor" << endl; }~Base() { cout << "Base destructor" << endl; }
};class Derived : public Base {
public:Derived() : Base() { cout << "Derived constructor" << endl; }~Derived() { cout << "Derived destructor" << endl; }
};int main() {Derived d;/* 输出:Base constructorDerived constructorDerived destructorBase destructor*/
}

四、函数重写与多态性

4.1 虚函数(virtual)

使用virtual关键字声明可在派生类中重写的函数

class Shape {
public:virtual void draw() {cout << "Drawing a shape" << endl;}
};class Circle : public Shape {
public:void draw() override { // C++11引入override关键字cout << "Drawing a circle" << endl;}
};int main() {Shape* shape = new Circle();shape->draw(); // 输出: Drawing a circledelete shape;
}

4.2 纯虚函数与抽象类

包含纯虚函数的类称为抽象类,不能实例化

class Shape {
public:virtual void draw() = 0; // 纯虚函数
};class Rectangle : public Shape {
public:void draw() override {cout << "Drawing a rectangle" << endl;}
};int main() {// Shape s; // 错误! 抽象类不能实例化Shape* shape = new Rectangle();shape->draw(); // 输出: Drawing a rectangledelete shape;
}

五、多重继承与虚继承

5.1 多重继承

一个类可以继承多个基类

class Printer {
public:void print() { cout << "Printing..." << endl; }
};class Scanner {
public:void scan() { cout << "Scanning..." << endl; }
};class Copier : public Printer, public Scanner {
public:void copy() {print();scan();cout << "Copying completed!" << endl;}
};

5.2 菱形继承问题

菱形继承结构:

    Animal/   \/     \
Mammal   WingedAnimal\     /\   /Bat

问题描述:

当 Bat 类同时继承 Mammal 和 WingedAnimal 时,如果它们都继承自 Animal,会导致 Bat 对象中包含两份 Animal 成员

class Animal {
public:int age;
};class Mammal : public Animal {};
class WingedAnimal : public Animal {};class Bat : public Mammal, public WingedAnimal {};int main() {Bat bat;// bat.age = 2; // 错误! 二义性访问bat.Mammal::age = 2;     // 通过Mammal路径访问bat.WingedAnimal::age = 3; // 通过WingedAnimal路径访问cout << bat.Mammal::age << endl;     // 输出: 2cout << bat.WingedAnimal::age << endl; // 输出: 3
}

5.3 虚继承解决方案

使用virtual关键字解决菱形继承的二义性问题

class Animal {
public:int age;
};class Mammal : virtual public Animal {};
class WingedAnimal : virtual public Animal {};class Bat : public Mammal, public WingedAnimal {};int main() {Bat bat;bat.age = 2; // 没有二义性// 未使用虚继承时: bat.Mammal::age 和 bat.WingedAnimal::age
}

六、继承中的访问控制总结

基类成员访问权限

继承类型

在派生类中的访问权限

public

public

public

protected

public

protected

private

public

不可访问

public

protected

protected

protected

protected

protected

private

protected

不可访问

public

private

private

protected

private

private

private

private

不可访问

七、继承的最佳实践

  1. 遵循LSP原则:派生类应该能够完全替代基类

  2. 优先使用组合:除非是"is-a"关系,否则优先使用组合而非继承

  3. 避免深层次继承:继承层次不宜过深(通常不超过3层)

  4. 使用override关键字:明确表示重写基类虚函数

  5. 基类析构函数声明为虚函数:确保正确调用派生类析构函数

class Base {
public:virtual ~Base() {} // 虚析构函数
};

八、总结

C++继承机制提供了强大的代码复用和多态支持:

  • 三种继承方式:public、protected、private

  • 虚函数实现运行时多态

  • 虚继承解决菱形继承问题

  • 抽象类定义接口规范

正确使用继承可以使代码更加灵活、可扩展,但需注意避免过度使用继承带来的设计问题。

掌握继承机制是成为C++高级开发者的必经之路。希望本文能帮助你建立清晰的继承概念体系,在实际开发中灵活运用这些知识!

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

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

相关文章

Jenkins安装与配置全攻略:从入门到高级功能实战

在DevOps实践中,Jenkins作为最流行的持续集成工具之一,扮演着至关重要的角色。本文将全面介绍Jenkins的安装、配置及高级功能使用,帮助开发、运维和测试团队快速搭建高效的CI/CD流水线。 一、Jenkins安装 1.1 环境准备 Jenkins官网:https://jenkins.io 注意:Jenkins 2…

[OS_26] 计算机系统安全 | CIA原则 | 侧信道攻击

系统调用是唯一访问操作系统对象的途径 拒绝越权访问 →→ Confidentiality拒绝越权修改 →→ Integrity(再加上公平资源调度 →→ Availability) 在操作系统 API 上&#xff0c;我们可以构建命令行工具、编译器、数据库、浏览器等丰富的应用。 当越来越多用户开始共享计算机、…

Chromium 136 编译指南 macOS篇:编译优化技巧(六)

1. 引言 在现代软件开发的高效化进程中&#xff0c;编译优化已经从简单的性能调优发展为一门综合性的工程科学。对于Chromium 136这样一个包含超过2500万行代码的超大规模项目而言&#xff0c;编译时间往往成为制约开发效率的关键瓶颈。在典型的开发场景中&#xff0c;一次完整…

Spark教程6:Spark 底层执行原理详解

文章目录 一、整体架构概述二、核心组件详解1. SparkContext2. DAG Scheduler3. Task Scheduler4. Executor 三、作业执行流程1. DAG 生成与 Stage 划分2. Task 调度与执行3. 内存管理 四、Shuffle 机制详解1. Shuffle 过程2. Shuffle 优化 五、内存管理机制1. 统一内存管理&am…

xlsx-style 插件批量导出多个sheet表格excel中遇到的问题及解决

Vue2中 前端界面导出表格&#xff0c;使用XLSXS插件版本(^0.8.13)导出表格存在表格背景颜色无法正常展示&#xff0c;百分比数据没有正常展示 【有条件的尽量先升级高版本插件&#xff0c;此插件版本对样式支持度不够】 优先考虑插件版本升级 同样的使用方法在vue3中没有出现错…

Java后端与Vue前端项目部署全流程:从环境配置到Nginx反向代理

文章目录 1. 准备项目所需的环境2. 后端项目打包步骤 1&#xff1a;使用 Maven 打包步骤 2&#xff1a;定位生成的 JAR 包步骤 3&#xff1a;上传 JAR 包到 Linux 系统步骤 4&#xff1a;验证 Java 环境步骤 5&#xff1a;启动 JAR 包 3. 前端项目打包步骤 1&#xff1a;执行 B…

Mybatis踩坑之一天

background: 对接AML系统&#xff0c;日间实时需要送交易对手要素过去&#xff08;目前主要是交易对手全名&#xff09;&#xff0c;夜间需要将历史交易送AML进行回溯&#xff0c;交互方式是文件。文件要素为日期、对手类型、对手名、交易流水之类。 设置对送AML的文件设计表…

【PyTorch】分布式训练报错记录-ERROR:torch.distributed.elastic.multiprocessing.api:failed (exitcode: 1)

最近&#xff0c;我在服务器上起基于PyTorch分布式框架的预训练实验&#xff0c;起初实验都在顺利进行&#xff0c;但是当我们把模型的深度与宽度调大之后&#xff0c;模型在训练几代之后便会出现如下的报错&#xff1a; WARNING:torch.distributed.elastic.multiprocessing.a…

有哪些词编码模型

有哪些词编码模型 词编码模型:是将自然语言符号映射为稠密的高维向量,使语义相近的词汇在向量空间中位置接近。 不过,也有部分模型会考虑字母或字符信息,如基于字节对编码(BPE)的模型会将单词拆分成子词,这里的子词可能是字母组合。 词编码模型的原理主要是通过机器学…

Mono 功能介绍与使用示例

Mono 功能介绍与使用示例 一、核心概念与特性 Mono 是 Spring Reactor 框架中的核心组件&#xff0c;属于响应式编程&#xff08;Reactive Programming&#xff09;模型&#xff0c;专注于处理包含 0 或 1 个元素 的异步序列[1][2][5]。其核心特点包括&#xff1a; 异步非阻…

5060Ti双显卡+LLaMA-factory大模型微调环境搭建

查看环境确定安装版本安装CUDA12.8安装Anaconda安装Visual Studio C桌面开发环境&#xff08;编译llama.cpp需要&#xff09;安装cmake(编译llama.cpp需要)安装llama.cpp(用于量化)安装huggingface-cli安装llama-factory安装PyTorch2.7.0安装bitsandbytes安装flash-attention加…

Lnmp和XunRuiCMS一键部署(Rocky linux)

先上传XunRuiCMS-Study.zip包到当前目录&#xff0c;可以去官网下载 #!/bin/bash # function: install nginx mysql php on Rocky Linux 9.5 with fixed PHP-FPM configip$(hostname -I | awk {print $1}) yhxunrui passwordxunrui123# 检查是否为root用户 if [ "$USER&qu…

高精度OFDR设备在CPO交换机中的应用

光电共封装&#xff08;CPO&#xff09;交换机的特点 核心需求&#xff1a;CPO将光模块与交换芯片集成封装&#xff0c;缩短电互连距离&#xff0c;降低功耗和延迟&#xff0c;但需解决以下挑战&#xff1a; 1.光器件微型化&#xff1a;硅光芯片、光纤阵列等需高精度制造。 …

Vulkan 通过 CMake 集成 Dear ImGUI

一、 目录与文件部署 从官网获取 IMGUI 代码库&#xff0c;在项目 extern 目录下新建 imgui 目录&#xff0c;将相关文件复制进去&#xff0c;构建出如下目录结构&#xff1a; . ├── build ├── extern │ ├── glfw │ ├── glm │ └── imgui │ ├…

Linux设备框架:kset与kobject基本介绍

系列文章目录 Linux设备框架&#xff1a;kset与kobject基本介绍 [link] Linux设备框架&#xff1a;kset与kobject源码分析 [link] kset与kobject基本介绍 一、前言二、kobject、kset和设备的关系2.1 kset 结构体2.2 kobject 结构体 三、总结 一、前言 Linux 设备模型如同一座拥…

【AI论文】扩展大型语言模型(LLM)智能体在测试时的计算量

摘要&#xff1a;扩展测试时的计算量在提升大型语言模型&#xff08;LLMs&#xff09;的推理能力方面已展现出显著成效。在本研究中&#xff0c;我们首次系统地探索了将测试时扩展方法应用于语言智能体&#xff0c;并研究了该方法在多大程度上能提高其有效性。具体而言&#xf…

LeapMotion-PhysicalHandsManager 类详解

PhysicalHandsManager 类详解 这个类是 Ultraleap 物理手交互系统的核心管理器,负责处理手部物理交互的不同模式。下面我将详细解析这个类的结构和功能: 类概述 PhysicalHandsManager 继承自 LeapProvider,是物理手交互系统的中央控制器: public class PhysicalHandsMa…

vue-22(理解组合式 API:setup、ref、reactive)

Vue.js 中的组合式 API 代表了我们构建和组织组件方式的重大转变。它为传统的选项式 API 提供了一种更灵活、更强大的替代方案&#xff0c;尤其适用于复杂的应用程序。本章将深入探讨组合式 API 的核心概念&#xff1a;setup函数、ref和reactive&#xff0c;为你构建更可维护、…

【Golang玩转MCP】-实现一个加减乘除MCP服务

文章目录 概要1 首先创建一个MCP服务器2 添加MCP工具如何测试我们的MCP服务功能是否正常呢小结 概要 今天我们使用golang简单实现一个加减乘除MCP服务 1 首先创建一个MCP服务器 s : server.NewMCPServer("Hello World Server","1.0.0",server.WithToolCa…

计算机网络期末 网络基础概述

目录 网络的定义历史发展(了解) 网络的分类&#xff0c;功能和应用(熟悉) 网络的组成与结构(理解) 网络的 OSI 七层参考模型(熟悉) 网络的 TCP/IP 四次模型(理解) 网络有关性能指标(掌握) 网络的定义历史发展(了解) 计算机网络是什么 四个阶段 总结 网络 互连网 因特网的…