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

C++共享数据的保护

虽然数据隐藏保护了数据的安全性,但各种形式的数据共享却又不同程度地破坏了数据的安全。因此,对于既需要共享有需要防止改变的数据应该声明为常量。因为常量在程序运行期间不可改变,所以可以有效保护数据。

1.常对象

常对象:它的数据成员值在对象的整个生存期内不能被改变。也就是说,常对象必须进行初始化,而且不能被更新。

声明常对象的语法形式:

const 类型说明符 对象名;

例如:

class A
{
public:A(int i,int j):x(i),y(j){}
private:int x, y;
};
const A a(3, 4);//a是常对象,不能被更新

与基本数据类型的常量相似,常对象的值不能被改变。在C++语法中,对基本数据类型的常量提供了可靠的保护。如果程序中出现了类似下面这样的语句,编译时是会出错的。也就是说,语法检查时确保了常量不能被赋值。

const int n=10;//正确,用10对常量n进行初始化
n=20;//错误,不能对常量赋值

【注意】在定义一个变量或者常量时为它指定初值叫做初始化,而在定义一个变量或常量以后使用赋值运算符修改它的值叫做赋值。

语法保障类类型的常对象的值不被改变:
改变对象的数据成员值有两个途径,一是通过对象名访问其成员对象,由于常对象的数据成员都被视为常量,这时语法限制不能赋值。二是在类的成员函数中改变数据成员的值,然而几乎无法预料和统计哪些成员函数会改变数据成员的值,对此语法只好规定不能通过常对象调用普通的成员函数。因此,为常对象定义了常成员函数。

【注意】基本数据类型的常量也可以看作一种特殊的常对象。

2.常成员函数

使用关键字const修饰的函数称为常成员函数,常成员函数的声明格式如下:

类型说明符 函数名(参数表)const;

【注意】
(1)const是函数类型的一个组成部分,因此在函数的定义部分也要带const关键字。
(2)如果将一个对象说明为常对象,则通过该常对象只能调用它的常成员函数,而不能调用其他成员函数(这就是C++从语法机制上对常对象的保护,也是常对象唯一的对外接口方式)。
(3)无论是否通过常对象调用常成员函数,在常成员函数调用期间,目的对象都被视为常对象,因此常成员函数不能更新目的对象的数据成员,也不能针对目的对象调用该类中没有用const修饰的成员函数(这就保证了在常成员函数中不会更改目的对象的数据成员值)。
(4)const关键字可以用于对重载函数的区分。例如,如果在类中这样声明:

void print();
void print() const;

这是对print函数的有效重载。
【注意】如果仅以const关键字区分对成员函数的重载,那么通过非const的对象调用该函数,两个重载函数都可以与之匹配,这是编译器将选择最近的函数重载——不带const关键字的函数。

【例】在R类中声明了一个常成员函数。

class R
{
public:R(int r1, int r2) :r1(r1), r2(r2) {}void print();void print()const;
private:int r1, r2;
};
void R::print()
{cout << r1 << ":" << r2 << endl;
}
void R::print()const
{cout << r1 << ";" << r2 << endl;
}
int main()
{R a(5, 4);a.print();//调用void print()const R b(20, 32);//调用void print()constb.print();return 0;
}

运行结果及分析:
在这里插入图片描述
在R类中声明了两个同名函数print,其中一个是常成员函数。在主函数中定义了两个对象a和b,其中a是普通的R类类型的对象,b是R类类型的常对象。通过对象a调用的是没有const修饰的print函数,而通过对象b调用的是用const修饰的print常成员函数。

(1)如果将程序做以下修改:

class R
{
public:R(int r1, int r2) :r1(r1), r2(r2) {}void print();//void print()const;
private:int r1, r2;
};
void R::print()
{cout << r1 << ":" << r2 << endl;
}
//void R::print()const
//{
//	cout << r1 << ";" << r2 << endl;
//}
int main()
{R a(5, 4);a.print();//调用void print()const R b(20, 32);//调用void print()constb.print();//错误return 0;
}

这样会导致编译不通过,因为b在主函数中被定义为常对象,常对象不可以调用普通的成员函数。
(2)如果将程序做以下修改:

class R
{
public:R (int r1,int r2):r1(r1),r2(r2){}//void print();void print()const;
private:int r1, r2;
};
//void R::print()
//{
//	cout << r1 << ":" << r2 << endl;
//}
void R::print()const
{cout << r1 << ";" << r2 << endl;
}
int main()
{R a(5, 4);a.print();const R b(20, 32);b.print();return 0;
}

运行结果及分析:
在这里插入图片描述
如果R类中没有普通成员函数print,只有const修饰的常成员函数void print()const;,那么在主函数中,普通的R类类型的对象a和常对象b都会调用常成员函数,所以普通对象和常对象都可以调用常成员函数。

3.常数据成员

就像一般数据一样,类的数据成员也可以是常量,使用const说明的数据成员为常数据成员。如果在一个类中说明了常数据成员,那么任何函数中都不能对该成员赋值。构造函数对常数据成员进行初始化,就只能通过初始化列表。

【例】在类A中声明了一个常数据成员。

class A
{
public:A(int i);void print();
private:const int a;static const int b;//静态常数据成员
};const int A::b = 10;//静态常数据成员在类外声明和初始化。//常数据成员只能通过初始化列表来获得初值
A::A(int i) :a(i){}void A::print()
{cout << a << ":" << b << endl;
}
int main()
{/*建立对象a和b,并以100和1作为初值,分别调用构造函数,通过构造函数的初始化列表给对象的常数据成员赋值*/A m(100);A n(1);m.print();n.print();return 0;
}

运行结果:
在这里插入图片描述
分析:

类数据成员中的静态变量和常量都应当在类定义之外加以定义,但C++标准规定了一个例外:类的静态常量如果具有整型或枚举类型,那么可以直接在类中定义为它指定常量值,例如上面代码可以改写为如下所示,在类中定义时直接给b指定常量值10:

class A
{
public:A(int i);void print();
private:const int a;static const int b=10;//静态常数据成员
};//const int A::b = 10;//静态常数据成员在类外声明和初始化。//常数据成员只能通过初始化列表来获得初值
A::A(int i) :a(i){}void A::print()
{cout << a << ":" << b << endl;
}
int main()
{/*建立对象a和b,并以100和1作为初值,分别调用构造函数,通过构造函数的初始化列表给对象的常数据成员赋值*/A m(100);A n(1);m.print();n.print();return 0;
}

这时不必在类外定义A::b,因为编译器会将程序中对A::b的所有引用都替换成数值10,一般无须再为A::b分配空间。但也有例外,例如如果程序中出现了对b取地址的情况,则必须通过专门的定义为A::b分配空间。由于已经在类中为它指定了初值,就不能再在类定义之外为它指定初值,即使两处给的值一样也不行。

但是对于类数据成员中的常量,必须在构造函数的初始化列表对其进行赋初值,即初始化。

4.常引用

如果在声明引用时用const修饰,被声明的引用就是常引用常引用所引用的对象不能被更新。如果常引用作为形参,便不会意外地发生对实参的更改。常引用的声明形式如下:

const 类型说明符 &引用名;

非const的引用只能绑定到普通的对象,而不能绑定到常对象,但常引用可以绑定到常对象。一个常引用,无论绑定到一个普通对象,还是一个常对象,通过该引用访问该对象时,都只能把该对象当作常对象。这意味着,对于基本数据类型的引用,则不能为数据赋值,对于类类型的引用,则不能修改它的数据成员,也不能调用它的非const成员函数。

【例】常引用做形参

class Point//Point类的定义
{
public://外部接口Point(int x = 0, int y = 0) :x(x), y(y) {}int getX() { return x; }int getY() { return y; }friend float dist(const Point& p1, const Point& p2);//友元函数声明
private://私有数据成员int x, y;
};float dist(const Point& p1, const Point& p2)//常引用作为形参
{double  x = p1.x - p2.x;//通过对象访问Point类的私有数据成员double  y = p1.y - p2.y;return static_cast<float>(sqrt(x * x + y * y));
}int main()//主函数
{const Point myp1(1, 1), myp2(4, 5);//定义Point类的对象cout << "两点之间的距离为:";cout << dist(myp1, myp2) << endl;//计算两点之间的距离return 0;
}

运行结果及分析:

在这里插入图片描述
由于dist函数中,无须修改两个传入对象的值,因此将传参方式改为传递常引用更合适,这样,调用dist函数时,就可以用常对象作为参数。

【注意】对于在函数中无须改变其值的参数,不宜使用普通引方式传递,因为那会使得对象无法被传入,采用传值方式或传递常引用方式可避免这一问题。对于大对象来说,传值耗时较多,因此传递常引用为宜。拷贝构造函数的参数一般也宜采用常引用传递。
例如将上述代码改写为:

class Point//Point类的定义
{
public://外部接口Point(int x = 0, int y = 0) :x(x), y(y) {}int getX() { return x; }int getY() { return y; }friend float dist(Point& p1, Point& p2);//友元函数声明
private://私有数据成员int x, y;
};float dist(Point& p1, Point& p2)//常引用作为形参
{double  x = p1.x - p2.x;//通过对象访问Point类的私有数据成员double  y = p1.y - p2.y;return static_cast<float>(sqrt(x * x + y * y));
}int main()//主函数
{const Point myp1(1, 1), myp2(4, 5);//定义Point类的对象cout << "两点之间的距离为:";cout << dist(myp1, myp2) << endl;//errorreturn 0;
}

此时,dist函数并不是以常引用的方式进行传参,但是,因为主函数中定义的对象为常对象,不可以采用普通的引用进行传参,所以编译不会通过。

相关文章:

C++共享数据的保护

虽然数据隐藏保护了数据的安全性&#xff0c;但各种形式的数据共享却又不同程度地破坏了数据的安全。因此&#xff0c;对于既需要共享有需要防止改变的数据应该声明为常量。因为常量在程序运行期间不可改变&#xff0c;所以可以有效保护数据。 1.常对象 常对象&#xff1a;它…...

MyBatisPlus学习记录

MyBatisPlus(简称MP&#xff09;是基于MyBatis框架基础上开发的增强型工具&#xff0c;旨在简化开发、提高效率 MyBatisPlus简介 入门案例 创建新模块&#xff0c;选择Spring初始化&#xff0c;并配置模块相关基础信息选择当前模块需要使用的技术集&#xff08;仅选择MySQL …...

如何开启一个java微服务工程

安装idea IDEA常用配置和插件&#xff08;包括导入导出&#xff09; https://blog.csdn.net/qq_38586496/article/details/109382560安装配置maven 导入source创建项目 修改项目编码utf-8 File->Settings->Editor->File Encodings 修改项目的jdk maven import引入…...

libhv之hio_t分析

上一篇文章解析了fd是怎么与io模型关联。其中最主要的角色扮演者&#xff1a;hio_t 1. hio_t与hloop的关系 fd的值即hio_t所在loop ios变量中所在的index值。 hio_t ios[fd] struct hloop_s { ...// ios: with fd as array.index//io_array保存了和hloop关联的所有hio_t&…...

C语言的转义字符

转义字符也叫转移序列&#xff0c;包含如下&#xff1a; 转移序列 \0oo 和 \xhh 是 ASCII 码的特殊表示。 八进制数示例&#xff1a; 代码&#xff1a; #include<stdio.h> int main(void) {char beep\007;printf("%c\n",beep);return 0; }结果&#xff1a; …...

【腾讯云 Cloud Studio 实战训练营】CloudStudio体验真正的现代化开发方式,双手插兜不知道什么叫对手!

CloudStudio体验真正的现代化开发方式&#xff0c;双手插兜不知道什么叫对手&#xff01; 文章目录 CloudStudio体验真正的现代化开发方式&#xff0c;双手插兜不知道什么叫对手&#xff01;前言出现的背景一、CloudStudio 是什么&#xff1f;二、CloudStudio 的特点三、CloudS…...

Pandas时序数据分析实践—时序数据集

1. 跑步运动为例&#xff0c;对运动进行时序分析 时序数据是指时间序列数据&#xff0c;是按照时间顺序排列的数据集合&#xff0c;每个数据点都与一个特定的时间戳相关联。在跑步活动中&#xff0c;我们可以将每次跑步的数据记录作为一个时序数据样本&#xff0c;每个样本都包…...

use strict 是什么意思?使用它区别是什么?

use strict 是什么意思&#xff1f;使用它区别是什么&#xff1f; use strict 代表开启严格模式&#xff0c;这种模式下使得 JavaScript 在更严格的条件下运行&#xff0c;实行更严格解析和错误处理。 开启“严格模式”的优点&#xff1a; 消除 JavaScript 语法的一些不合理…...

常见OOM异常分析排查

常见OOM异常分析排查 Java内存溢出Java堆溢出原因解决思路总结 Java内存溢出 java堆用于存储对象实例,如果不断地创建对象,并且保证GC Root到对象之间有可达路径,垃圾回收机制就不会清理这些对象,对象数量达到最大堆的容量限制后就会产生内存溢出异常. Java堆溢出原因 无法在…...

kubernetes网络之网络策略-Network Policies

Kubernetes 中&#xff0c;Network Policy&#xff08;网络策略&#xff09;定义了一组 Pod 是否允许相互通信&#xff0c;或者与网络中的其他端点 endpoint 通信。 NetworkPolicy 对象使用标签选择Pod&#xff0c;并定义规则指定选中的Pod可以执行什么样的网络通信&#xff0…...

交换机VLAN技术和实验(eNSP)

目录 一&#xff0c;交换机的演变 1.1&#xff0c;最小网络单元 1.2&#xff0c;中继器&#xff08;物理层&#xff09; 1.3&#xff0c;集线器&#xff08;物理层&#xff09; 1.4&#xff0c;网桥&#xff08;数据链路层&#xff09; 二&#xff0c;交换机的工作行为 2.…...

8.Winform界面打包成DLL提供给其他的项目使用

背景 希望集成一个Winform的框架&#xff0c;提供权限菜单&#xff0c;根据权限出现各个Winform子系统的菜单界面。不希望把所有的界面都放放在同一个解决方案下面。用各个子系统建立不同的解决方案&#xff0c;建立代码仓库&#xff0c;进行管理。 实现方式 将Winform的UI界…...

海量数据存储组件Hbase

hdfs hbase NoSQL数据库 支持海量数据的增删改查 基于Rowkey查询效率特别高 kudu 介于hdfs和hbase之间 hbase依赖hadoopzookeeper&#xff0c;同时整合框架phoenix(擅长读写),hive&#xff08;分析数据&#xff09; k&#xff0c;v 储存结构 稀疏的&#xff08;为空的不存…...

(一)基于Spring Reactor框架响应式异步编程|道法术器

在执行程序时: 通常为了提供性能,处理器和编译器常常会对指令进行重排序。 从排序分为编译器重排序和处理器重排序两种 * (1)编译器重排序: 编译器保证不改变单线程执行结构的前提下,可以调整多线程语句执行顺序&#xff1b; * (2)处理器重排序&#xff1a; 如果不存在数据依赖…...

Vue3 让localstorage变响应式

Hook使用方式&#xff1a; import {useLocalStore} from "../js/hooks"const aauseLocalStore("aa",1) 需求一&#xff1a; 通过window.localStorage.setItem可以更改本地存储是&#xff0c;还可以更新aa的值 window.localStorage.setItem("aa&quo…...

【深度学习】InST,Inversion-Based Style Transfer with Diffusion Models,论文,风格迁移,实战

代码&#xff1a;https://github.com/zyxElsa/InST 论文&#xff1a;https://arxiv.org/abs/2211.13203 文章目录 AbstractIntroductionRelated WorkImage style transferText-to-image synthesisInversion of diffusion models MethodOverview ExperimentsComparison with Sty…...

【CSS】3D卡片效果

效果 index.html <!DOCTYPE html> <html><head><title> Document </title><link type"text/css" rel"styleSheet" href"index.css" /></head><body><div class"card"><img…...

OrderApplication

目录 1 OrderApplication 2 /// 查询订单 2.1.1 //补充商品单位 2.1.2 //补充门店名称 2.1.3 //补充门店名称 2.1.4 //订单售后 2.1.5 //订单项售后 OrderApplication...

如何在保健品行业运用IPD?

保健品是指能调节机体功能&#xff0c;不以治疗为目的&#xff0c;并且对人体不产生任何急性、亚急性或者慢性危害的产品。保健品是食品的一个种类&#xff0c;具有一般食品的共性&#xff0c;其含有一定量的功效成分&#xff0c;能调节人体的机能&#xff0c;具有特定的功效&a…...

Flink系列之:动态发现新增分区

Flink系列之&#xff1a;动态发现新增分区 一、动态发现新增分区二、Flink SQL动态发现新增分区三、Flink API动态发现新增分区 为了在不重新启动 Flink 作业的情况下处理主题扩展或主题创建等场景&#xff0c;可以将 Kafka 源配置为在提供的主题分区订阅模式下定期发现新分区。…...

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周&#xff0c;有很多同学在写期末Java web作业时&#xff0c;运行tomcat出现乱码问题&#xff0c;经过多次解决与研究&#xff0c;我做了如下整理&#xff1a; 原因&#xff1a; IDEA本身编码与tomcat的编码与Windows编码不同导致&#xff0c;Windows 系统控制台…...

云原生核心技术 (7/12): K8s 核心概念白话解读(上):Pod 和 Deployment 究竟是什么?

大家好&#xff0c;欢迎来到《云原生核心技术》系列的第七篇&#xff01; 在上一篇&#xff0c;我们成功地使用 Minikube 或 kind 在自己的电脑上搭建起了一个迷你但功能完备的 Kubernetes 集群。现在&#xff0c;我们就像一个拥有了一块崭新数字土地的农场主&#xff0c;是时…...

【服务器压力测试】本地PC电脑作为服务器运行时出现卡顿和资源紧张(Windows/Linux)

要让本地PC电脑作为服务器运行时出现卡顿和资源紧张的情况&#xff0c;可以通过以下几种方式模拟或触发&#xff1a; 1. 增加CPU负载 运行大量计算密集型任务&#xff0c;例如&#xff1a; 使用多线程循环执行复杂计算&#xff08;如数学运算、加密解密等&#xff09;。运行图…...

GC1808高性能24位立体声音频ADC芯片解析

1. 芯片概述 GC1808是一款24位立体声音频模数转换器&#xff08;ADC&#xff09;&#xff0c;支持8kHz~96kHz采样率&#xff0c;集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器&#xff0c;适用于高保真音频采集场景。 2. 核心特性 高精度&#xff1a;24位分辨率&#xff0c…...

算法笔记2

1.字符串拼接最好用StringBuilder&#xff0c;不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

Web后端基础(基础知识)

BS架构&#xff1a;Browser/Server&#xff0c;浏览器/服务器架构模式。客户端只需要浏览器&#xff0c;应用程序的逻辑和数据都存储在服务端。 优点&#xff1a;维护方便缺点&#xff1a;体验一般 CS架构&#xff1a;Client/Server&#xff0c;客户端/服务器架构模式。需要单独…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)

前言&#xff1a; 双亲委派机制对于面试这块来说非常重要&#xff0c;在实际开发中也是经常遇见需要打破双亲委派的需求&#xff0c;今天我们一起来探索一下什么是双亲委派机制&#xff0c;在此之前我们先介绍一下类的加载器。 目录 ​编辑 前言&#xff1a; 类加载器 1. …...

【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验

Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...

高防服务器价格高原因分析

高防服务器的价格较高&#xff0c;主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因&#xff1a; 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器&#xff0c;因此…...

uni-app学习笔记三十五--扩展组件的安装和使用

由于内置组件不能满足日常开发需要&#xff0c;uniapp官方也提供了众多的扩展组件供我们使用。由于不是内置组件&#xff0c;需要安装才能使用。 一、安装扩展插件 安装方法&#xff1a; 1.访问uniapp官方文档组件部分&#xff1a;组件使用的入门教程 | uni-app官网 点击左侧…...