【C++】类和对象(四)
前言:在类和对象中,我们走过了十分漫长的道路,今天我们将进一步学习类和对象,类和对象这块荆棘地很长,各位一起加油呀。
💖 博主CSDN主页:卫卫卫的个人主页 💞
👉 专栏分类:高质量C++学习 👈
💯代码仓库:卫卫周大胖的学习日记💫
💪关注博主和博主一起学习!一起努力!
目录标题
- 类和对象
- const修饰成员函数
- 再谈构造函数之函数体赋值
- explict关键字
- static成员
类和对象
const修饰成员函数
在C++中,可以使用const关键字来修饰成员函数。const修饰符可以被应用于类的成员函数,这表示该函数不会修改任何类的成员变量。
当一个成员函数被const修饰时,它被称为常量成员函数。常量成员函数承诺不会修改任何成员变量。常量成员函数的定义和声明都必须包含const关键字。
语法格式:
返回类型 类名::函数名()const
{//函数体......
}
下面是一个示例:
class MyClass
{
public:void nonConstFunction(int year,int month ,int day); // 非常量成员函数 void nonConstFunction() const; // 常量成员函数
private:int _day;int _month;int _year;
};void MyClass::nonConstFunction(int year = 1,int month = 1 ,int day =1)
{// 对成员变量进行修改_year = year;_month = month;_day = day;
}void MyClass::nonConstFunction() const
{// 不对成员变量进行修改cout << "year: " << _year << " month: " << _month << " day: " << _day << endl;
}
在上面的示例中,nonConstFunction是一个非常量成员函数,可以修改成员变量。而nonConstFunction的const版本是一个常量成员函数,不会修改成员变量。
那我们思考一下为什么在上面这个示例中,const修饰了以后就无法对里面的成员变量进行修改了?请看下图:

在上图中我们可以知道,编译器会对this指针加上const进行修饰,让外部变量无法对其修改
如果在上面式子中我们对const修饰的成员函数中的成员变量进行修改,就会出现如下情况,如下所示:

使用const修饰常量成员函数的好处是可以在常量对象上调用该函数,而不会导致编译错误。这样可以提高代码的可读性和安全性。
注意事项:
C++中const成员函数有以下限制:
-
const成员函数不能修改类的非静态数据成员。这是因为const成员函数保证不会修改对象的状态,所以不能修改任何非静态数据成员。
-
const成员函数只能调用其他const成员函数。这是因为const成员函数保证不会修改对象的状态,所以只能调用其他也不会修改对象状态的const成员函数。
-
const成员函数不能通过指针或引用返回非const指针或引用。这是因为const成员函数要保证不会修改对象的状态,所以不能返回非const指针或引用,否则调用者就可以通过这个指针或引用修改对象的状态。
-
const成员函数可以被非const对象和const对象调用。非const对象调用const成员函数时会被自动转换为const对象。
-
const成员函数不能被声明为虚函数。虚函数是根据对象的动态类型来调用的,而const成员函数是根据对象的静态类型来调用的,所以不能将const成员函数声明为虚函数。
再谈构造函数之函数体赋值
在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。
class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。
- . 初始化列表:构造函数可以通过初始化列表来初始化成员变量。在构造函数的参数列表后面使用冒号(:)来定义初始化列表,然后通过成员变量名称和初始值来初始化成员变量(当然这个括号里面也可以写一个有返回值的表达式)。例如:


注意:
- 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)
- 类中包含以下成员,必须放在初始化列表位置进行初始化:
引用成员变量,const成员变量,自定义类型成员(该类没有默认构造函数)
实例演示:
class A
{
public:A(int a):_a(a){cout <<"_a: " << _a << endl;}
private:int _a;
};class d
{
public:d(int a, int b, int c):_aa(a),_b(b),_c(c){cout << "_b: " << _b << endl;cout << "_c: " << _c << endl;}private:A _aa;//自定义变量int& _b;//引用const int _c;//const
};int main()
{d d1(10, 20, 30);return 0;
}

- 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
- 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关
在C++中,构造函数体赋值的注意事项如下:
-
初始化列表的优先级高于构造函数体内的赋值:如果同时在初始化列表和构造函数体内对成员变量进行赋值,初始化列表中的赋值操作会先于构造函数体内的赋值操作执行。
-
成员变量的声明顺序决定了初始化的顺序:成员变量在类中的声明顺序决定了它们初始化的顺序。在构造函数体内的赋值操作也会按照成员变量的声明顺序进行。
-
成员变量的初始化顺序与初始化列表中的顺序一致:在初始化列表中的顺序决定了成员变量初始化的顺序。如果在初始化列表中没有给出某个成员变量的初始值,该成员变量会按照默认构造函数进行初始化。
-
常量成员变量必须在初始化列表中进行初始化:对于类中的常量成员变量(const类型),它们必须在初始化列表中进行初始化,而不能在构造函数体内进行赋值操作。
-
使用成员初始化列表可以提高效率:使用成员初始化列表可以在对象构造时直接进行赋值操作,避免了先构造默认对象再赋值的额外开销,因此可以提高效率。
总体而言,通过初始化列表进行成员变量的赋值是更好的选择,除非有特殊需要,如需要在构造函数体内做其他逻辑处理,才使用构造函数体内的赋值语句。
explict关键字
在C++中,explicit也是一个关键字,但其使用情况与C#中的略有不同。
在C++中,explicit关键字可以用于单参数构造函数(或转换函数),以防止编译器进行隐式类型转换。默认情况下,单参数构造函数可以用于隐式类型转换。但是,当我们使用explicit关键字来修饰该构造函数时,它将变为只能进行显式类型转换的构造函数,禁止隐式转换。
下面是一个使用explicit关键字的示例:
class Number {
private:int value;
public:explicit Number(int value) : value(value) {}int getValue() const {return value;}
};void printNumber(const Number& number) {std::cout << number.getValue() << std::endl;
}int main() {int intValue = 10;// 隐式类型转换不被允许// Number number = intValue;// 显式类型转换Number number = Number(intValue);printNumber(number);return 0;
}

在上面的示例中,Number类定义了一个带有单参数的构造函数,并使用explicit关键字进行修饰。在main函数中,我们首先声明一个int类型的变量intValue,并将其赋值为10。然后,我们尝试使用隐式类型转换将intValue转换为Number类型,但由于Number类的构造函数使用了explicit关键字,这会导致编译错误。接着,我们使用显式类型转换将intValue转换为Number类型,并将结果赋值给number变量。最后,我们通过调用printNumber函数,将number对象传递给它并输出结果。可以看到,通过使用explicit关键字,我们可以明确指定我们希望进行显式类型转换,从而避免了隐式类型转换可能带来的意外行为。
static成员
在C++中,static关键字可以应用于类的成员,用于指示该成员是静态的。静态成员与类的实例无关,它们属于整个类而不是类的实例。以下是一些关于C++中静态成员的信息:
- 静态数据成员:静态数据成员与类的所有实例共享,它们只有一个副本。可以在类的内部声明并在类的外部初始化。静态数据成员必须在类的定义之外进行初始化,并且必须在类的外部定义。并且静态成员变量是在初始化时分配内存的,程序结束时释放内存。
class MyClass
{
public:static int staticData; // 声明静态数据成员int unstaticData = 10; //声明并初始化非静态成员
};int MyClass::staticData = 0; // 初始化静态数据成员int main()
{MyClass obj1;MyClass obj2;obj1.staticData = 5;cout <<"非静态成员: " << obj1.unstaticData << endl; //输出非静态成员cout <<"静态成员: " << obj2.staticData << endl; // 输出静态成员: 5return 0;
}

- 静态成员函数:静态成员函数没有访问类的任何实例成员的权限,它们只能访问静态成员。静态成员函数可以通过类名或对象名来引用,非静态成员函数只能通过对象名引用。
class MyClass
{
public:static void StaticFunction()//静态成员函数 {cout << "Static Function" << endl;}void UnstaticFunction()//非静态成员函数{cout << "UnStatic Function" << endl;}
};int main() {MyClass d1;MyClass::StaticFunction(); // 输出: Static Functiond1.UnstaticFunction(); //输出: UnStatic Functionreturn 0;
}

静态成员提供了一种在类的所有实例之间共享和访问数据的方式。在某些情况下,静态成员函数可以用作工具函数或全局函数的替代品。然而,静态成员应谨慎使用,因为它们破坏了封装性和面向对象设计的一些原则。
好啦,今天的内容就到这里啦,下期内容预告类和对象(五)友元、内部类、匿名对象等,下期就会对类和对象进行最后的收尾了,各位加油呐!
结语:今天的内容就到这里吧,谢谢各位的观看,如果有讲的不好的地方也请各位多多指出,作者每一条评论都会读的,谢谢各位。
相关文章:
【C++】类和对象(四)
前言:在类和对象中,我们走过了十分漫长的道路,今天我们将进一步学习类和对象,类和对象这块荆棘地很长,各位一起加油呀。 💖 博主CSDN主页:卫卫卫的个人主页 💞 👉 专栏分类:高质量&a…...
XGB-5: DART Booster
XGBoost 主要结合了大量的回归树和一个小的学习率。在这种情况下,早期添加的树是重要的,而晚期添加的树是不重要的。 Vinayak 和 Gilad-Bachrach 提出了一种将深度神经网络社区的 dropout 技术应用于梯度提升树的新方法,并在某些情况下报告了…...
HiveSQL——不使用union all的情况下进行列转行
参考文章: HiveSql一天一个小技巧:如何不使用union all 进行列转行_不 union all-CSDN博客文章浏览阅读881次,点赞5次,收藏10次。本文给出一种不使用传统UNION ALL方法进行 行转列的方法,其中方法一采用了concat_wsposexplode()方…...
Python环境下基于指数退化模型和LSTM自编码器的轴承剩余寿命预测
滚动轴承是机械设备中关键的零部件之一,其可靠性直接影响了设备的性能,所以对滚动轴承的剩余使用寿命(RUL)进行预测是十分必要的。目前,如何准确地对滚动轴承剩余使用寿命进行预测,仍是一个具有挑战的课题。对滚动轴承剩余寿命评估…...
无人机竞赛视觉算法开发流程开源计划(询问大家意见)
本科中参加过一系列的无人机机器人竞赛,像电赛、工训赛、机器人大赛这些,有一些比较常用的方案打算开源一下。现在读研了,也算是对本科的一个总结,但是还是想看看大家意见,大家有什么需求可以在评论区说,我…...
DMA直接内存访问,STM32实现高速数据传输使用配置
1、DMA运用场景 随着智能化、信息化的不断推进,嵌入式设备的数据处理量也呈现指数级增加,因此对于巨大的数据量处理的情况时,必须采取其它的方式去替CPU减负,以保证嵌入式设备性能。例如SD卡存储器和音视频、网络高速通信等其它情…...
Web安全研究(六)
文章目录 HideNoSeek: Camouflaging(隐藏) Malicious JavaScript in Benign ASTs文章结构Introjs obfuscationmethodologyExample HideNoSeek: Camouflaging(隐藏) Malicious JavaScript in Benign ASTs CCS 2019 CISPA 恶意软件领域,基于学习的系统已经非常流行&am…...
python3 中try 异常调试 raise 异常抛出
一、什么是异常? 异常即是一个事件,该事件会在程序执行过程中发生,影响了程序的正常执行。 一般情况下,在Python无法正常处理程序时就会发生一个异常。 异常是Python对象,表示一个错误。 当Python脚本发生异常时我…...
Java中的序列化是什么?如何实现对象的序列化和反序列化?请解释Serializable接口的作用是什么?请解释transient关键字的作用是什么?为什么会使用它?
Java中的序列化是指将对象转换为字节序列的过程,以便可以在网络上传输或将其保存到持久存储介质中。反序列化则是将字节序列重新转换回对象的过程。Java提供了一种称为序列化(Serialization)的机制来实现对象的序列化和反序列化。 要实现对象…...
二维差分---三维差分算法笔记
文章目录 一.二维差分构造差分二维数组二维差分算法状态dp求b[i][j]数组的二维前缀和图解 二.三维前缀和与差分三维前缀和图解:三维差分核心公式图解:模板题 一.二维差分 给定一个原二维数组a[i][j],若要给a[i][j]中以(x1,y1)和(x2,y2)为对角线的子矩阵中每个数都加上一个常数…...
D. Divisible Pairs
思路:我们预处理出每个数分别摸上xy的值,用map存一下,然后遍历每个数,如果a b是x的倍数的话,那么他们模x的值相加为x,如果a - b是y的倍数的话,那么他们的模y的值相等。 代码: voi…...
【教程】Kotlin语言学习笔记(二)——数据类型(持续更新)
写在前面: 如果文章对你有帮助,记得点赞关注加收藏一波,利于以后需要的时候复习,多谢支持! 【Kotlin语言学习】系列文章 第一章 《认识Kotlin》 第二章 《数据类型》 文章目录 【Kotlin语言学习】系列文章一、基本数据…...
react 插槽
问题开发当中会经常出现组件十分相似的组件,只有一部分是不同的 解决: 父组件:在引用的时候 import { Component } from "react"; import Me from "../me";const name <div>名称</div> class Shoop extends Compone…...
Linux运用fork函数创建进程
fork函数: 函数原型: pid_t fork(void); 父进程调用fork函数创建一个子进程,子进程的用户区父进程的用户区完全一样,但是内核区不完全一样;如父进程的PID和子进程的PID不一样。 返回值: RETURN VALUEO…...
Pytest测试技巧之Fixture:模块化管理测试数据
在 Pytest 测试中,有效管理测试数据是提高测试质量和可维护性的关键。本文将深入探讨 Pytest 中的 Fixture,特别是如何利用 Fixture 实现测试数据的模块化管理,以提高测试用例的清晰度和可复用性。 什么是Fixture? 在 Pytest 中&a…...
设计模式-职责链模式Chain of Responsibility
职责链模式 一、原理和实现二、实现方式1) 使用链表实现2) 使用数组实现3) 扩展 作用:复用和扩展,在实际的项目开发中比较常用。在框架开发中,我们也可以利用它们来提供框架的扩展点,能够让框架的使用者在不修改框架源码的情况下&…...
书生浦语大模型实战营-课程作业(3)
下载sentence_transformer的代码运行情况。sentence_transformer用于embedding(转向量) 本地构建持久化向量数据库。就是把txt和md文件抽取出纯文本,分割成定长(500)后转换成向量,保存到本地,称…...
考研英语单词25
Day 25 bench n.长凳 elastic n.橡皮圈,松紧带 a.灵活的 “e-last 延伸出去” disaster n.灾难,灾祸【disastrous a.灾难性的,极坏的】 deadly a.致命的,极端的,势不两立的 hike n.徒步旅行&…...
计算机网络——08应用层原理
应用层原理 创建一个新的网络 编程 在不同的端系统上运行通过网络基础设施提供的服务,应用进程批次通信如Web Web服务器软件与浏览器软件通信 网络核心中没有应用层软件 网络核心没有应用层功能网络应用只能在端系统上存在 快速网络应用开发和部署 网络应用…...
面试计算机网络框架八股文十问十答第五期
面试计算机网络框架八股文十问十答第五期 作者:程序员小白条,个人博客 相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新! ⭐点赞⭐收藏⭐不迷路!⭐ 1)与缓存相关的HTTP请…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
React hook之useRef
React useRef 详解 useRef 是 React 提供的一个 Hook,用于在函数组件中创建可变的引用对象。它在 React 开发中有多种重要用途,下面我将全面详细地介绍它的特性和用法。 基本概念 1. 创建 ref const refContainer useRef(initialValue);initialValu…...
从WWDC看苹果产品发展的规律
WWDC 是苹果公司一年一度面向全球开发者的盛会,其主题演讲展现了苹果在产品设计、技术路线、用户体验和生态系统构建上的核心理念与演进脉络。我们借助 ChatGPT Deep Research 工具,对过去十年 WWDC 主题演讲内容进行了系统化分析,形成了这份…...
大型活动交通拥堵治理的视觉算法应用
大型活动下智慧交通的视觉分析应用 一、背景与挑战 大型活动(如演唱会、马拉松赛事、高考中考等)期间,城市交通面临瞬时人流车流激增、传统摄像头模糊、交通拥堵识别滞后等问题。以演唱会为例,暖城商圈曾因观众集中离场导致周边…...
为什么需要建设工程项目管理?工程项目管理有哪些亮点功能?
在建筑行业,项目管理的重要性不言而喻。随着工程规模的扩大、技术复杂度的提升,传统的管理模式已经难以满足现代工程的需求。过去,许多企业依赖手工记录、口头沟通和分散的信息管理,导致效率低下、成本失控、风险频发。例如&#…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
反射获取方法和属性
Java反射获取方法 在Java中,反射(Reflection)是一种强大的机制,允许程序在运行时访问和操作类的内部属性和方法。通过反射,可以动态地创建对象、调用方法、改变属性值,这在很多Java框架中如Spring和Hiberna…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...

