C++学习笔记----8、掌握类与对象(四)---- 不同类型的数据成员(1)

news2024/10/5 8:35:09

        c++对于数据成员给了你许多选项。除了在类中声明简单的数据成员,可以生成静态数据成员供所有类的对象共享,const成员,引用成员,reference-to-const成员,等等。本节我们解释一下这些不同类型的数据成员的细节。

1、静态数据成员

        有时候给类的第一个对象变量的拷贝会过度猎杀或者不管用。数据成员可能特定于类,但让每个对象有一个拷贝是不合适的。例如,你可能想给每个spreadsheet一个单独的数字标识符。就需要一个从0开始的计数器,每个对象可以包含它的ID。这个spreadsheet计数器确实属于Spreadsheet类,但是让每个Spreadsheet对象都有一个拷贝是没有什么道理的,因为不管怎么样你都要让所有的计数器同步。c++提供了一个解决方案,使用静态数据成员。静态数据成员是一个与类而不是对象相关联的数据成员。可以认为静态数据成员是类的全局变量。下面是Spreadsheet类的定义,包含了新的静态计数数据成员:

export class Spreadsheet
{
    // Omitted for brevity

private:
    static std::size_t ms_counter;
};

        在类定义中除了列出静态类成员之外,还需要在源文件中为它们分配空间,通常会把类成员函数的定义放到源文件中。可以同时初始化它们,但是要记住与正常的变量与数据成员不同,它们缺省是被初始化为0的。静态指针会被初始化为nullptr。下面是分配空间并且将其初始化为0的ms_counter的代码:

size_t Spreadsheet::ms_counter;

        静态数据成员缺省初始化为0,但是如果你想,也可以显式地像下面这样对其进行初始化:

size_t Spreadsheet::ms_counter { 0 };

        该代码出现在任何函数或者成员函数体之外。差不多像是声明一个全局变量,除了Spreadsheet::范围解释符指出它是Spreadsheet类的一部分。

        与正常的数据成员一样,访问控制指示符也应用于静态数据成员。可以将ms_counter数据成员弄成public的,但是,你早已知晓,是不推荐拥有public数据成员的(我们后面要讨论的const static数据成员是个例外)。应该通过public的getter与setter来获得对数据成员的访问。如果想要给静态数据成员赋予访问的权限,可以提供public的静态get/set成员函数。

1.1、内联变量

        可以将静态数据成员声明为inline。这样做的好处是不需要在源文件中为其分配空间。下面是例子:

export class Spreadsheet
{
    // Omitted for brevity

private:
    static inline std::size_t ms_counter { 0 };
};

        注意inline关键字,有了这样的类定义,下面这行代码就可以从源文件中移除了:

size_t Spreadsheet::ms_counter;

1.2、在类成员函数内访问静态数据成员

        可以使用静态数据成员就像它们是类成员函数中的通常的数据成员一样。例如,你可能会想生成一个Spreadsheet类的m_id的数据成员并在Spreadsheet构造函数中从ms_counter进行初始化。下面是带有m_id成员的Spreadsheet类定义:

export class Spreadsheet
{
public:
	// Omitted for brevity
	std::size_t getId() const;
private:
	// Omitted for brevity
    static inline std::size_t ms_counter{ 0 }; 
    std::size_t m_id { 0 };
};

        下面是对赋值给初始ID的Spreadsheet构造函数的实现:

Spreadsheet::Spreadsheet(size_t width, size_t height)
: m_id { ms_counter++ }, m_width { width }, m_height { height }
{
    // Omitted for brevity
}

        你可以看到,构造函数可以访问ms_counter就像它是一个正常的成员。拷贝构造函数也赋值一个新的ID。这会自动处理,因为Spreadsheet拷贝构造函数代理到non-copy构造函数,它生成了新的ID。

        对于这个例子,假定一旦ID赋值给一个对象,它就不再改变。所以,不应该在拷贝赋值操作符中拷贝ID。这样的话,推荐使m_id成为一个const数据成员:

export class Spreadsheet
{
private:
    // Omitted for brevity
    const std::size_t m_id { 0 };
};

        既然数据成员一旦生成就不再改变,就不可能在构造函数体内初始化。这样的数据成员必须要么直接在类定义或者在构造函数初始化器中初始化。这也就意味着不能在赋值操作符中给这样的数据成员赋新值。对于m_id来说这不是总是,因为一旦Spreadsheet拥有了一个ID,它就不会再改变。然而,要依实际情况而定,如果这就使你的类无法赋值,赋值操作符就要被明正典刑--显式删除了。

2、constexpr静态数据成员

        类中的数据成员可以被声明为const或者constexpr,意思是它们在生成与初始化后不能被改变。应该使用static constexpr(或者constexpr static)数据成员在全局常量的位置上,当常量只应用于类时,也叫做类常量。整型的和枚举型的static constexpr数据成员可以被定义并且初始化在类定义内,即使没有将它们定义成内联变量。例如,你可能想要给spreadsheet指定一个最大的高度与宽度。如果用户想要构建一个比最大值更大的高度与宽度的spreadsheet,就会使用最大值。可以将Spreadsheet类的最大值高度与宽度弄成static constexpr成员。

export class Spreadsheet
{
public:
    // Omitted for brevity
    static constexpr std::size_t MaxHeight { 100 };
    static constexpr std::size_t MaxWidth { 100 };
};

        可以如下面这样在构造函数中使用新的常量:

Spreadsheet::Spreadsheet(size_t width, size_t height)
: m_id { ms_counter++ }
, m_width { std::min(width, MaxWidth) } // std::min() defined in <algorithm>
, m_height { std::min(height, MaxHeight) }
{
    // Omitted for brevity
}

        注意:不自动用最大值替换超过的宽度与高度,也可以决定在宽度与高度超过最大值时抛出例外。然而,在构造函数中抛出例外是不会调用析构函数的。所以要认真对待这一点。这个我们会在以后讨论错误处理时再详细讨论。

        这样的常量也可以用于参数的缺省值。记住只能对于从最右边开始的连续的参数给出缺省值。下面是例子:

export class Spreadsheet
{
public:
    explicit Spreadsheet(
    std::size_t width = MaxWidth, std::size_t height = MaxHeight);
    // Omitted for brevity
};

2.1、从类成员函数外部访问静态数据成员

如前所述,访问控制标识符应用于静态数据成员:MaxWidth与MaxHeight为public,所以它们可以从类成员函数外部访问,通过指定变量为Spreadsheet类的一部分,使用::范围解析操作符。例如:

println("Maximum height is: {}", Spreadsheet::MaxHeight);

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

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

相关文章

渗透测试入门学习——使用python脚本自动跟踪csrf_token实现对网站登录界面的暴力破解

目录 写在前面 使用方法 相关代码 写在前面 最近在学习使用Burp Suite时发现其intruder模块无法实现多种模式的混合使用&#xff0c;就如想要暴力破解账号和口令两个区域并同时跟踪网页的csrf_token时BP似乎不能很方便的实现这一功能&#xff0c;于是自己在练习时就想到了用…

【DataLoom】智能问数 - 自然语言与数据库交互

探索DataLoom的智能问数功能&#xff1a;简化数据库查询 在数据驱动的决策制定中&#xff0c;数据库查询是获取洞察的关键步骤。但是&#xff0c;传统的数据库查询方法往往复杂且技术性强&#xff0c;这限制了非技术用户的使用。DataLoom的智能问数功能正是为了解决这一问题而…

【WebGis开发 - Cesium】如何确保Cesium场景加载完毕

目录 引言一、监听场景加载进度1. 基础代码2. 加工代码 二、进一步封装代码1. 已知存在的弊端2. 封装hooks函数 三、使用hooks方法1. 先看下效果2. 如何使用该hooks方法 三、总结 引言 本篇为Cesium开发的一些小技巧。 判断Cesium场景是否加载完毕这件事是非常有意义的。 加载…

Spring Boot中线程池使用

说明&#xff1a;在一些场景&#xff0c;如导入数据&#xff0c;批量插入数据库&#xff0c;使用常规方法&#xff0c;需要等待较长时间&#xff0c;而使用线程池可以提高效率。本文介绍如何在Spring Boot中使用线程池来批量插入数据。 搭建环境 首先&#xff0c;创建一个Spr…

自动驾驶系列—颠覆未来驾驶:深入解析自动驾驶线控转向系统技术

&#x1f31f;&#x1f31f; 欢迎来到我的技术小筑&#xff0c;一个专为技术探索者打造的交流空间。在这里&#xff0c;我们不仅分享代码的智慧&#xff0c;还探讨技术的深度与广度。无论您是资深开发者还是技术新手&#xff0c;这里都有一片属于您的天空。让我们在知识的海洋中…

【树莓派系列】交叉编译工具、交叉编译链的安装使用

交叉编译工具、交叉编译链的安装使用 文章目录 交叉编译工具、交叉编译链的安装使用一、交叉编译1.1什么是交叉编译1.2为什么要交叉编译1.3宿主机和目标机 二、搭建交叉编译工作环境2.1安装工具链2.2配置环境变量● 配置临时环境变量● 配置永久环境变量 三、交叉编译宿主机和目…

NASA:Seasat-A 散射计(SASS)得出的风速和风向矢量数据集

目录 简介 摘要 代码 引用 网址推荐 0代码在线构建地图应用 机器学习 SEASAT SCATTEROMETER DEALIASED OCEAN WIND VECTORS (Atlas) 简介 SEASAT散射计反回波强度&#xff08;scattering&#xff09;提供了对海面风速和风向的估计。SEASAT散射计被用来获取海面风场的信…

LabVIEW提高开发效率技巧----调度器设计模式

在LabVIEW开发中&#xff0c;针对多任务并行的需求&#xff0c;使用调度器设计模式&#xff08;Scheduler Pattern&#xff09;可以有效地管理多个任务&#xff0c;确保它们根据优先级或时间间隔合理执行。这种模式在需要多任务并发执行时特别有用&#xff0c;尤其是在实时系统…

【算法】---归并排序(递归非递归实现)

参考 左程云算法 算法导论 前言 本篇介绍 归并排序分治法 前置知识 了解递归&#xff0c; 了解数组。 引入 归并排序 归并排序最早是由公认的现代计算机之父John von Neumann发明的&#xff0c; 这是一种典型的分治思想应用。 我们先介绍分治思想 分治思想 分治思想的…

java:pdfbox 3.0 去除扫描版PDF中文本水印

官网下载 https://pdfbox.apache.org/download.html下载 pdfbox-app-3.0.3.jar cd D:\pdfbox 运行 java -jar pdfbox-app-3.0.3.jar java -jar pdfbox-app-3.0.3.jar Usage: pdfbox [COMMAND] [OPTIONS] Commands:debug Analyzes and inspects the internal structu…

(C语言贪吃蛇)7.显示贪吃蛇完整身体改进

前言 上节显示了贪吃蛇身子的三个节点&#xff0c;但是吃了食物后蛇身变长应该如何操作&#xff0c;本节给出答案。 一、贪吃蛇身体是什么&#xff1f; 使用链表这个数据结构来动态的显示贪吃蛇的身体。 二、对贪吃蛇身体进行改进 1.贪吃蛇身子显示 代码如下&#xff1a; …

信息学奥赛使用的编程IDE:Dev-C++ 安装指南

信息学奥赛&#xff08;NOI&#xff09;作为全国性的编程竞赛&#xff0c;要求参赛学生具备扎实的编程能力&#xff0c;而熟练使用适合的编程工具则是学习与竞赛的基础。在众多编程环境中&#xff0c;Dev-C IDE 因其简洁、轻量、支持C编程等特点&#xff0c;成为许多参赛者的常…

最新版的dubbo服务调用(用nacos做注册中心用)

一、介绍 1.1、什么是 nacos Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称&#xff0c;一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 Nacos 致力于帮助您发现、配置和管理微服务。Nacos 提供了一组简单易用的特性集&a…

Java 每日一刊(第21期):反射机制

文章目录 前言动态插件系统面临的问题如何在运行时动态加载和调用类与方法设计模式的尝试引入反射 Java 反射的核心概念Class 类Constructor 类Method 类Field 类 Java 反射的应用场景框架开发插件系统序列化与反序列化动态代理测试工具 反射的优缺点反射实战动态加载类并调用方…

【hot100-java】【将有序数组转换为二叉搜索树】

二叉树篇 BST树 递归直接实现。 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNo…

【C++差分数组】2381. 字母移位 II|1793

本文涉及知识点 C差分数组 LeetCode2381. 字母移位 II 给你一个小写英文字母组成的字符串 s 和一个二维整数数组 shifts &#xff0c;其中 shifts[i] [starti, endi, directioni] 。对于每个 i &#xff0c;将 s 中从下标 starti 到下标 endi &#xff08;两者都包含&#…

STM32的串行外设接口SPI

一、SPI简介 1.SPI总线特点 &#xff08;1&#xff09;四条通信线 SPI需要SCK、MISO、MOSI、NSS四条通信线来完成数据传输 &#xff0c;每增加一个从机&#xff0c;多一条NSS通信线。 &#xff08;2&#xff09;多主多从 SPI总线允许有多个主机和多个从机。 &#xff08;3&…

再见 ESNI,你好 ECH!—— ECH的前世今生

译者注&#xff1a;2024 年 9 月 25 日&#xff0c;Cloudflare 宣布再次推出 ECH 功能。借此契机&#xff0c;本人翻译了 Cloudflare 介绍 ECH 的博文 Good-bye ESNI, hello ECH! &#xff0c;以便科普ECH的发展历程。 现代互联网上的大多数通信都经过加密&#xff0c;以确保其…

Flink源码剖析

写在前面 最近一段时间都没有更新博客了&#xff0c;原因有点离谱&#xff0c;在实现flink的两阶段提交的时候&#xff0c;每次执行自定义的notifyCheckpointComplete时候&#xff0c;好像就会停止消费数据&#xff0c;完成notifyComplete后再消费数据&#xff1b;基于上述原因…

在Stable Diffusion WebUI中安装SadTalker插件时几种错误提示的处理方法

SD中的插件一般安装比较简单&#xff0c;但也有一些插件安装会比较难。比如我在安装SadTalker时&#xff0c;就遇到很多问题&#xff0c;一度放弃了&#xff0c;后来查了一些网上攻略&#xff0c;自己也反复查看日志&#xff0c;终于解决&#xff0c;不吐不快。 一、在Stable …