当前位置: 首页 > news >正文

C++ Primer 自定义数据结构

欢迎阅读我的 【C++Primer】专栏

专栏简介:本专栏主要面向C++初学者,解释C++的一些基本概念和基础语言特性,涉及C++标准库的用法,面向对象特性,泛型特性高级用法。通过使用标准库中定义的抽象设施,使你更加适应高级程序设计技术。希望对读者有帮助!

在这里插入图片描述
在这里插入图片描述

目录

  • 自定义数据结构
    • 定义Sales_data类型
    • 类数据成员
    • 使用Sales_data类
    • 添加两个Sales_data对象
    • Sales_data对象读入数据
    • 编写自己的头文件
    • 预处理器概述

自定义数据结构

从最基本的层面理解,数据结构是把一组相关的数据元素组织起来然后使用它们的策略和方法。举一个例子,我们的Sales_item类把书本的TSBN编号、售出量及销售收入等数据组织在了一起,并且提供诸如isbn函数、>>、<<、+、+=等运算在内的一系列操作,Sales_item类就是一个数据结构。

C++语言允许用户以类的形式自定义数据类型,而库类型string、istream、ostream等也都是以类的形式定义的,就像Sales_item类型一样。C++语言对类的支持甚多,事实上本书的第III部分和第IV部分都将大篇幅地介绍与类有关的知识。尽管Sales_item类非常简单,但是要想给出它的完整定义可在第14章介绍自定义运算符之后。

定义Sales_data类型

尽管我们还写不出完整的Sales_item类,但是可以尝试着把那些数据元素组织到一起形成一个简单点儿的类。初步的想法是用户能直接访问其中的数据元素,也能实现一些基本的操作。

既然我们筹划的这个数据结构不带有任何运算功能,不妨把它命名为Sales_data以示与Sales_item的区别。Sales_data初步定义如下:

struct Sales_data{std::strtng bookNo;unsigned units_sold = 0;double revenue = 0.0;
}

我们的类以关键字struct开始,紧跟着类名和类体(其中类体部分可以为空)。类体由花括号包围形成了一个新的作用域。类内部定义的名字必须唯一,但是可以与类外部定义的名字重复。类体右侧的表示结束的花括号后必须写一个分号,这是因为类体后面可以紧跟变量名以示对该类型对象的定义,所以分号必不可少:

struct Sales_data{/*…*/}accum,trans,*salesptr;
//与上一条语句等价,但可能更好一些
struct Sales_data{}
Sales_data acoum , trans , *salesptr;

分号表示声明符的结束。一般来说,最好不要把对象的定义和类的定义放在一起。这么做无异于把两种不同实体的定义混在了一条语句里,一会儿定义类,一会儿又定义变量,显然这是一种不被建议的行为。

WARNING: 很多新手程序员经常忘了在类定义的最后加上分号。

类数据成员

类体定义类的成员,我们的类只有数据成员(data member)。类的数据成员定义了类的对象的具体内容,每个对象有自己的一价数据成员拷贝。修改一个对象的数据成员,不会影响其他Sales_data的对象。

定义数据成员的方法和定义普通变量一样:首先说明一个基本类型,随后紧跟一个或多个声明符。我们的类有3个数据成员:一个名为 bookNo 的 string 成员、一个名为 units_sold 的unsigned 成员和一个名为 revenue 的 double 成员。又个Sales_data的对象都将包括这3个数据成员。

C++11新标准规定,可以为数据成员提供一个类内初始值(in-class initializer)。创建对象时,类内初始值将用于初始化数据成员。没有初始值的成员将被默认初始化。因此当定义Sales_data的对象时,units_sold和revenue都将初始化为0,bookNo将初始化为空字符串。

对类内初始值的限制与之前介绍的类似:或者放在花括号里,或者放在等号右边,记住不能使用圆括号。

使用Sales_data类

和Sales_item类不同的是,我们自定义的Sales_data类没有提供任何操作,Sales_data类的使用者如果想执行什么操作就必须自己动手实现。。程序的输入是下面这两条交易记录:

0-201-78345-X320.00
0-201-78345-X225.00

每笔交易记录着图书的ISBN编号、售出数量和售出单价。

添加两个Sales_data对象

因为sales_data类没有提供任何操作,所以我们必须自己编码实现输入、输出和相加的功能。假设已知Sales_data类定义于sales_data.h文件内,将详细介绍定义头文件的方法。

因为程序比较长,所以接下来分成儿部分介绍。总的来说,程序的结构如下:

#nclude<iostreami>
#include<string>
#include“Sales_data.h“
ntmain()
{Sales_data data1,data2;//读入data1 和 data2的代码//datal和data2的ISBN是否相同的代码//如果相同,求data1和data2的总和
}

和原来的程序一样,先把所需的头文件包含进来并且定义变量用于接受输入。和Sales_item类不同的是,新程序还包含了string头文件,因为我们的代码中将用到string类型的成员变量bookkNo。

Sales_data对象读入数据

第3章和第10章将详细介绍string类型的细节,在此之前,我们先了解一点儿关于string的知识以便定义和使用我们的ISBN成员string类型其实就是字符的序列,它的操作有>>、<<和==等,功能分别是读入字符串、写出字符串和比较字符串。这样我们就能书写代码读入第一笔交易了:

    double price=0;//书的单价,用于计算销售收入//读入第1笔交易:ISBN、销售数量、单价std::cin >> data1.bookNo >> datal.units_sold >> price;//计算销售收入datal.revenue = datal.units_sold * price;

交易信息记录的是书售出的单价,而数据结构存储的是一次交易的销售收入,因此需要将单价读入到double变量price,然后再计算销售收入revenue。输入语句

std::cin >> data1.bookNo >> data1.units_sold >> price;

使用点操作符读入对象 data1 的bookNo成员和unitssold成员。最后一条语句把datal.units_sold和price的乘积赋值给data1的revenue成员。接下来程序重复上述过程读入对象data2的数据:

    //读入第2笔交易std::cin>>data2.bookNo>>data2.units_sold>>price;data2.revenue=data2.units_sold * price;

输出两个Sales_data对象的和

剩下的工作就是检查两笔交易涉及的ISBN编号是否相同了.如果相同输出它们的和,否则输出一条报错信息:

if(datal.bookNo == _data2.bookNo) {unsigned totalCnt =datal.units_sold+data2.units_sold;double totalRevenue=datalrevenue+data2.revenue;//输出:ISBN、总销售量、总销售额、平均价格std::cout<<datal.bookNo<<““<<totalCnt  <<““<<totalRevenue<<““if(totalCnt!=0) {std::cout<<totalRevenue/totalCnt<<std::endl;}elsestd::cout<<(nosales)<<std::endl;return 0;//标示成功
} else {//两笔交易的ISBN不一样  std::cerr<<“Data must refer to the same ISBN“ << std::endl;return -1;//标示失败
}

在第一个if语句中比较了daata1和data2的bookNo成员是否相同。如果相同则执行第一个if语句花括号内的操作,首先计算units_sold的和并赋给变量totalCnt,然后计算revenue的和并赋给变量totalRevenue,输出这些值。接下来检查是否确实售出了书籍,如果是,计算并输出每本书的平均价格;如果售量为零,输出一条相应的信息。

眼下先把Sales_data类的定义和 main 函数放在同一个文件里。

编写自己的头文件

类一般都不定义在函数体内。当在函数体外部定义类时,在各个指定的源文件中可能只有一处该类的定义。而且,如果要在不同文件中使用同一个类,类的定义就必须保持一致。

为了确保各个文件中类的定义一致,类通常被定义在头文件中,而且类所在头文件的名字应与类的名字一样。例如,库类型string在名为string的头文件中定义。又如,我们应该把Sales_data类定义在名为sales_data.h的头文件中。

头文件通常包含那些只能被定义一次的实体,如类、const和constexpr变量等。头文件也经常用到其他头文件的功能.例如,我们的Sales_data类包含有一个string成员,所以Sales_data.h必须包含string.h头文件。同时,使用Sales_data类的程序为了能操作bookkNo成员需要再一次包含string.h头文件。

这样,事实上使用Sales_data类的程序就先后两次包含了string.h头文件:一次是直接包含的,另有一次是随着包含Sales_data.h被隐式地包含进来的。有必要在书写头文件时做适当处理,使其遇到多次包含的情况也能安全和正常地工作。

头文件一旦改变,相关的源文件必须重新编译以获取更新过的声明。

预处理器概述

确保头文件多次包含仍能安全工作的常用技术是预处理器(preprocessor),它由C++语言从C语言继承而来。预处理器是在编译之前执行的一段程序,可以部分地改变我们所写的程序。之前已经用到了一项预处理功能include,当预处理器看到#include标记时就会用指定的头文件的内容代替#include。

C++程序还会用到的一项预处理功能是头文件保护符(header guard),头文件保护符依赖于预处理变量。预处理变量有两种状态:已定义和未定义。#define 指令把一个名字设定为预处理变量,另外两个指令则分别检查某个指定的预处理变量是否已经定义: #ifdef 当且仅当变量已定义时为真,#ifndef当且仅当变量未定义时为真。一旦检查结果为真,则执行后续操作直至遇到#endif指令为止。

使用这些功能就能有效地防止重复包含的发生:

#ifndef SRLES_DATA_H
#define SRLES_DATA_H
#include<string>
struct Sales_data{std::string bookNo;unsigned units_sold=0;double revenue=0.0;
}

第一次包含Sales_data.h 时,#ifndef的检查结果为真,预处理器将顺序执行后面的操作直至遇到#endif为止。此时,预处理变量SALES_DATA_H的值将变为已定义,而且sales_data.h也会被拷贝到我们的程序中来.后面如果再一次包含sales_data.h,则 #ifndef的检查结果将为假,编译器将忽略#ifndef到#endif之间的部分。

WARNING: 预处理变量无视C++语言中关于作用域的规则。

整个程序中的预处理变量包括头文件保护符必须唯一,通常的做法是基于头文件中类的名字来构建保护符的名字,以确保其唯一性。为了避免与程序中的其他实体发生名字冲突,一般把预处理变量的名字全部大写。

相关文章:

C++ Primer 自定义数据结构

欢迎阅读我的 【CPrimer】专栏 专栏简介&#xff1a;本专栏主要面向C初学者&#xff0c;解释C的一些基本概念和基础语言特性&#xff0c;涉及C标准库的用法&#xff0c;面向对象特性&#xff0c;泛型特性高级用法。通过使用标准库中定义的抽象设施&#xff0c;使你更加适应高级…...

35.Word:公积金管理中心文员小谢【37】

目录 Word1.docx ​ Word2.docx Word2.docx ​ 注意本套题还是与上一套存在不同之处 Word1.docx 布局样式的应用设计页眉页脚位置在水平/垂直方向上均相对于外边距居中排列&#xff1a;格式→大小对话框→位置→水平/垂直 按下表所列要求将原文中的手动纯文本编号分别替换…...

北京钟鼓楼:立春“鞭春牛”,钟鼓迎春来

仁风导和气,勾芒御昊春。“钟鼓迎春”立春鞭春牛民俗体验活动于立春当日在北京钟鼓楼隆重举办。此次活动由北京市钟鼓楼文物保管所主办,京睿文(北京)文化科技有限公司承办,通过礼官报春、击鼓鸣钟、春娃喊春、中国时间文化角色巡游、鞭春牛等一系列精彩的活动环节,为观众呈现了…...

股票入门知识

股票入门&#xff08;更适合中国宝宝体制&#xff09; 股市基础知识 本文介绍了股票的基础知识&#xff0c;股票的分类&#xff0c;各板块发行上市条件&#xff0c;股票代码&#xff0c;交易时间&#xff0c;交易规则&#xff0c;炒股术语&#xff0c;影响股价的因素&#xf…...

Java自定义IO密集型和CPU密集型线程池

文章目录 前言线程池各类场景描述常见场景案例设计思路公共类自定义工厂类-MyThreadFactory自定义拒绝策略-RejectedExecutionHandlerFactory自定义阻塞队列-TaskQueue&#xff08;实现 核心线程->最大线程数->队列&#xff09; 场景1&#xff1a;CPU密集型场景思路&…...

Git的安装步骤详解(复杂的安装界面该如何勾选?)

目录 一、下载与安装 1.官网下载git 2、下载完成之后&#xff0c;双击下载好的exe文件进行安装 3、选择Git的安装路径 4、选择在安装 Git 时要包含的组件和功能 5、选择 Git 快捷方式在 Windows 开始菜单中的位置。 6、选择 Git 使用的默认编辑器 7、调整新仓库中初始分…...

文本预处理

一、文本的基本单位 1、Token 定义&#xff1a;文本的最小单位&#xff0c;例如单词、标点符号。 示例&#xff1a; 原句&#xff1a; "I love NLP." 分词结果&#xff1a; [I, love, NLP, .] 2、语法与语义 语法&#xff1a;词的结构和句子的组合规则。 语义&a…...

SQLAlchemy 2.0的简单使用教程

SQLAlchemy 2.0相比1.x进行了很大的更新&#xff0c;目前网上的教程不多&#xff0c;以下以链接mysql为例介绍一下基本的使用方法 环境及依赖 Python:3.8 mysql:8.3 Flask:3.0.3 SQLAlchemy:2.0.37 PyMySQL:1.1.1使用步骤 1、创建引擎&#xff0c;链接到mysql engine crea…...

基于RAG的知识库问答系统

基于RAG的知识库问答系统 结合语义检索与大语言模型技术&#xff0c;实现基于私有知识库的智能问答解决方案。采用两阶段处理架构&#xff0c;可快速定位相关文档并生成精准回答。 核心功能 知识向量化引擎 支持多语言文本嵌入&#xff08;all-MiniLM-L6-v2模型&#xff09;自…...

SQL/Panda映射关系

Pandas教程&#xff08;非常详细&#xff09;_pandas 教程-CSDN博客 SQL&#xff1a;使用SELECT col_1, col_2 FROM tab; Pandas&#xff1a;使用df[[col_1, col_2]]。 SQL&#xff1a;使用SELECT * FROM tab WHERE col_1 11 AND col_2 > 5; Pandas&#xff1a;使用df…...

自定义数据集 使用paddlepaddle框架实现逻辑回归

导入必要的库 import numpy as np import paddle import paddle.nn as nn 数据准备&#xff1a; seed1 paddle.seed(seed)# 1.散点输入 定义输入数据 data [[-0.5, 7.7], [1.8, 98.5], [0.9, 57.8], [0.4, 39.2], [-1.4, -15.7], [-1.4, -37.3], [-1.8, -49.1], [1.5, 75.6…...

Docker入门篇(Docker基础概念与Linux安装教程)

目录 一、什么是Docker、有什么作用 二、Docker与虚拟机(对比) 三、Docker基础概念 四、CentOS安装Docker 一、从零认识Docker、有什么作用 1.项目部署可能的问题&#xff1a; 大型项目组件较多&#xff0c;运行环境也较为复杂&#xff0c;部署时会碰到一些问题&#xff1…...

c/c++高级编程

1.避免变量冗余初始化 结构体初始化为0&#xff0c;等价于对该内存进行一次memset&#xff0c;对于较大的结构体或者热点函数&#xff0c;重复的赋值带来冗余的性能开销。现代编译器对此类冗余初始化代码具有一定的优化能力&#xff0c;因此&#xff0c;打开相关的编译选项的优…...

2024-我的学习成长之路

因为热爱&#xff0c;无畏山海...

vscode软件操作界面UI布局@各个功能区域划分及其名称称呼

文章目录 abstract检查用户界面的主要区域官方文档关于UI的介绍 abstract 检查 Visual Studio Code 用户界面 - Training | Microsoft Learn 本质上&#xff0c;Visual Studio Code 是一个代码编辑器&#xff0c;其用户界面和布局与许多其他代码编辑器相似。 界面左侧是用于访…...

xmind使用教程

xmind使用教程 前言xmind版本信息“xmind使用教程”的xmind思维导图 前言 首先xmind是什么&#xff1f;XMind 是一款思维导图和头脑风暴工具&#xff0c;用于帮助用户组织和可视化思维、创意和信息。它允许用户通过图形化的方式来创建、整理和分享思维导图&#xff0c;可以用于…...

Day33【AI思考】-分层递进式结构 对数学数系的 终极系统分类

文章目录 **分层递进式结构** 对数学数系的 **终极系统分类**总览**一、数系演化树&#xff08;纵向维度&#xff09;**数系扩展逻辑树**数系扩展逻辑** **二、代数结构对照表&#xff08;横向维度&#xff09;**数系扩展的数学意义 **三、几何对应图谱&#xff08;空间维度&am…...

k8s二进制集群之ETCD集群证书生成

安装cfssl工具配置CA证书请求文件创建CA证书创建CA证书策略配置etcd证书请求文件生成etcd证书 继续上一篇文章《负载均衡器高可用部署》下面介绍一下etcd证书生成配置。其中涉及到的ip地址和证书基本信息请替换成你自己的信息。 安装cfssl工具 下载cfssl安装包 https://github…...

MySQL5.5升级到MySQL5.7

【卸载原来的MySQL】 cmd打开命令提示符窗口&#xff08;管理员身份&#xff09;net stop mysql&#xff08;先停止MySQL服务&#xff09; 3.卸载 切换到原来5.5版本的bin目录&#xff0c;输入mysqld remove卸载服务 测试mysql -V查看Mysql版本还是5.5 查看了环境变量里的…...

Golang Gin系列-9:Gin 集成Swagger生成文档

文档一直是一项乏味的工作&#xff08;以我个人的拙见&#xff09;&#xff0c;但也是编码过程中最重要的任务之一。在本文中&#xff0c;我们将学习如何将Swagger规范与Gin框架集成。我们将实现JWT认证&#xff0c;请求体作为表单数据和JSON。这里唯一的先决条件是Gin服务器。…...

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站&#xff0c;会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后&#xff0c;网站没有变化的情况。 不熟悉siteground主机的新手&#xff0c;遇到这个问题&#xff0c;就很抓狂&#xff0c;明明是哪都没操作错误&#x…...

【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15

缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下&#xff1a; struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

Java多线程实现之Callable接口深度解析

Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...

Nuxt.js 中的路由配置详解

Nuxt.js 通过其内置的路由系统简化了应用的路由配置&#xff0c;使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

多种风格导航菜单 HTML 实现(附源码)

下面我将为您展示 6 种不同风格的导航菜单实现&#xff0c;每种都包含完整 HTML、CSS 和 JavaScript 代码。 1. 简约水平导航栏 <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport&qu…...

图表类系列各种样式PPT模版分享

图标图表系列PPT模版&#xff0c;柱状图PPT模版&#xff0c;线状图PPT模版&#xff0c;折线图PPT模版&#xff0c;饼状图PPT模版&#xff0c;雷达图PPT模版&#xff0c;树状图PPT模版 图表类系列各种样式PPT模版分享&#xff1a;图表系列PPT模板https://pan.quark.cn/s/20d40aa…...

Pinocchio 库详解及其在足式机器人上的应用

Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库&#xff0c;专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性&#xff0c;并提供了一个通用的框架&…...