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

九、重学C++—类和函数

上一章节:

八、重学C++—动态多态(运行期)-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/147004745?spm=1001.2014.3001.5502

本章节代码:

cpp/cppClassAndFunc.cpp · CuiQingCheng/cppstudy - 码云 - 开源中国https://gitee.com/cuiqingcheng/cppstudy/blob/master/cpp/cppClassAndFunc.cpp

一、引言

        学到这里,会深深被C++的灵活多变所折服,学习C++的过程仿佛遨游在瑰丽多彩的海底世界。类与函数便是其中极为精妙的招式。今天,就让我们一起重新踏上探索 C++ 类与函数的奇妙之旅,揭开它们神秘的面纱。就像古人云:“温故而知新,可以为师矣。” 重学 C++ 的类与函数,也能让我们对编程有全新的感悟。

二、重新认识类:类中成员和特殊类

1、内联函数:代码中的“瞬移大师“

        内联函数,可以是类中的,也可以是普通函数。在常见的函数调用中,程序需要跳转去执行函数代码,执行完再跳转回来,这中间会消耗一些时间和资源。而内联函数呢,编译器会直接将函数代码嵌入到调用它的地方,因此这里常与宏函数对比

例如:

/***  1、内联函数*/
#include <iostream>// 宏函数
# define ADD(a,b)  (a+b)// 内联函数
inline int add(int& a, int &b)
{return a+b;
}class optData{
public:// 类中内联函数inline int add(int& a, int &b){return a+b;}
};int main()
{int n = 5;int m = 13;std::cout << "sum1: " << add(n,m) << std::endl;std::cout << "sum2: " << ADD(n,m) << std::endl;optData opt;std::cout << "sum3: " << opt.add(n,m) << std::endl;return 0;
}

宏函数不推荐使用,宏函数在设计初,就存在以下缺点,(1)、类型不安全,无法进行类型检测(2)、无法调试(3)、无法进行递归调用(4)、可读性差。

使用场景:

(1)、短小且频繁调用的函数:当函数体代码量很少(通常不超过 3 - 5 行 ),且在程序中会被频繁调用时,适合定义为内联函数。

(2)、 模板函数:简短的模板函数在编译时会生成具体的函数实例,更容易被内联化。内联后的模板函数能提供更好的性能

#include <iostream>// 模板内联函数,返回两个数中较大的值
template <typename T>
inline T max(T a, T b) {return a > b? a : b;
}int main()
{int n = 5;int m = 13;int iMax = max(n, m);std::cout << "iMax: " << iMax << std::endl;return 0;
}

优点:

        减少函数调用开销;提高程序执行效率;增强代码可读性;类型安全检查;相比于宏函数方便可调式

2、静态成员:不依赖对象存在,是类中的”常驻大使“

        静态成员变量是类的所有对象共享的一个变量,它就像班级里的公共财产,不管哪个同学都可以使用它

例如:

/***  1、静态成员*/#include <iostream>class Student {
public:Student(std::string name) :m_name(name){++m_totalStudents;}~Student() {--m_totalStudents;}// 静态成员函数static int getTotalStudents() {// ++m_totalStudents; 错误静态成员函数中不能出现普通成员变量,这里仅能操作静态成员变量;return m_totalStudents;}static std::string getSchoolName(){return m_schoolName;}// 普通成员函数int getStudentsCount(){return getTotalStudents();}
private:std::string m_name;// 静态成员变量static std::string m_schoolName;static int m_totalStudents;
};std::string Student::m_schoolName = "上海中学";
int Student::m_totalStudents = 0;int main()
{// 静态成员Student stu1("小明");Student stu2("小红");std::cout << "学生总数:" << Student::getTotalStudents() << " 学校名:"<< Student::getSchoolName()<<std::endl;std::cout << "小明知道的学生总数:" << stu1.getStudentsCount() << std::endl;return 0;
}

注意:

(1)静态成员函数只能操作静态成员变量;

(2)静态成员属于整个类共有的,不依赖于类所创建的对象;

(3)普通成员函数可以修改静态成员变量,因为要注意线程安全;

3、const常量

3.1 、成员变量是常量

一经初始化便不能修改;

3.2、成员函数形参为常量

传入形参在代码段内不能修改;

3.3、成员函数返回值为常量

3.4、成员函数,后接const修饰

不能修改成员变量值;

例如:

#include <iostream>
class Student {
public:Student(std::string name) :m_name(name){++m_totalStudents;}Student(std::string name, std::string strlocal) : m_name(name),m_strLocal(strlocal){++m_totalStudents;}~Student() {--m_totalStudents;}// 静态成员函数static int getTotalStudents() {// ++m_totalStudents; 错误静态成员函数中不能出现普通成员变量,这里仅能操作静态成员变量;return m_totalStudents;}static std::string getSchoolName(){return m_schoolName;}// 普通成员函数int getStudentsCount(){return getTotalStudents();}std::string getSchoolLocation(){return m_strLocal;}void setSex(const std::string strSex){// 传入的形参不能修改;m_strSex = strSex;}const std::string getSex(){return m_strSex;}// 不能修改所有成员变量void getStudetCount(int &count) const{count = m_totalStudents;}private:const std::string m_strLocal{"上海"};std::string m_name;std::string m_strSex;// 静态成员变量static std::string m_schoolName;static int m_totalStudents;
};std::string Student::m_schoolName = "上海中学";
int Student::m_totalStudents = 0;
int main()
{//constStudent stu1("小王");stu1.setSex("男");Student stu2("小丽");stu2.setSex("女");Student stu3("小张", "北京");stu3.setSex("男");int stuCount = 0;stu2.getStudetCount(stuCount);std::cout << "小王学校在哪儿:" << stu1.getSchoolLocation() << " 小王性别:" << stu1.getSex() << std::endl;std::cout << "小丽学校在哪儿:" << stu2.getSchoolLocation() << " 小丽学校学生数量:" << stuCount <<std::endl;std::cout << "小张学校在哪儿:" << stu3.getSchoolLocation() << std::endl;return 0;
}

4、无法实例化对象的类

4.1、抽象类无法实例化对象(略)

4.2、构造函数为私有的

// 构造函数私有
class baseClass {
private:baseClass(){std::cout << "构造函数" <<std::endl;}private:int m_num;
};

5、无法被继承的类final

class NonInheritable2 final {
public:void print() {std::cout << "This is a final class." << std::endl;}
};

6、delete特殊用法(修饰构造函数)

在 C++ 里,在构造函数后面使用 = delete 是 C++11 引入的特性,其作用是显式地删除该构造函数。删除构造函数后,就无法再使用该构造函数来创建类的对象,这在一些场景下很有用,下面详细介绍:

6.1、禁止默认构造函数

当你不希望类拥有默认构造函数(即无参数的构造函数)时,可使用 = delete 将其删除。

#include <iostream>class MyClass {
public:MyClass(int value) : data(value) {}// 删除默认构造函数MyClass() = delete; 
private:int data;
};int main() {// MyClass obj; // 错误,默认构造函数已被删除MyClass obj(42); // 正确,使用带参数的构造函数return 0;
}

在上述代码中,MyClass的默认构造函数被删除,所以不能通过无参数方式构造对象;

6.2、禁止拷贝构造函数和拷贝赋值运算符

若你不希望类的对象被复制,可使用 = delete 删除拷贝构造函数和拷贝赋值运算符。

#include <iostream>class NonCopyable {
public:NonCopyable() = default;// 删除拷贝构造函数NonCopyable(const NonCopyable&) = delete; // 删除拷贝赋值运算符NonCopyable& operator=(const NonCopyable&) = delete; 
};int main() {NonCopyable obj1;// NonCopyable obj2 = obj1; // 错误,拷贝构造函数已被删除// NonCopyable obj3;// obj3 = obj1; // 错误,拷贝赋值运算符已被删除return 0;
}

此代码中,NonCopyable 类的拷贝构造函数和拷贝赋值运算符都被删除,这就阻止了对象的复制操作。

三、友元

友元就像是类的 “好朋友”,虽然不在类的内部,但却能访问类的私有成员。它打破了类的封装性,但有时候为了提高代码的灵活性和效率,这种 “破格” 也是必要的

比如:

#include <iostream>class A {
public:A(int data) : m_privateData(data) {}protected:double m_protectedData{3.88};private:friend void friendFunction(A& a); // 友元函数friend class ClassB; // 友元类private:int m_privateData;
};void friendFunction(A& a) {std::cout << "访问到私有数据:" << a.m_privateData << std::endl;
}class ClassB {
public:void accessClassAData(A& obj) {// 友元类可以访问 ClassA 的私有和受保护成员std::cout << "Accessing private data of Class A: " << obj.m_privateData << std::endl;std::cout << "Accessing protected data of Class A: " << obj.m_protectedData << std::endl;}
};int main()
{// 友元A a(10);friendFunction(a);ClassB b;b.accessClassAData(a);
}

在上述代码中,ClassB 被声明为 A 的友元类,所以 ClassB 的成员函数 accessClassAData 能够访问 A 的私有成员 privateData 和受保护成员 protectedData。

使用场景

(1)、数据共享:当两个类之间存在紧密的关联,需要共享数据时,可以使用友元类。

注意事项

(1)、打破封装性:友元类破坏了类的封装性,因为它允许外部类访问本类的私有和受保护成员。过度使用友元类会导致代码的安全性和可维护性降低,所以应该谨慎使用。

(2)、单向性:友元关系是单向的。

(3)、不具有传递性。

四、名字空间

名字空间就像是编程世界里的 “房间分隔器”。当我们的项目越来越大,代码中的名字(变量名、函数名、类名等)可能会产生冲突,这时候名字空间就能把不同功能的代码隔离开来。

namespace Math {int add(int a, int b) {return a + b;}
}namespace Utility {int add(int a, int b) {return a * b;}
}int main() {std::cout << "Math 名字空间的加法:" << Math::add(3, 5) << std::endl;std::cout << "Utility 名字空间的加法:" << Utility::add(3, 5) << std::endl;return 0;
}

这里定义了 Math 和 Utility 两个名字空间,它们都有 add 函数,但功能不同,通过名字空间的限定,我们可以准确调用到想要的函数。

五、总结

        C++ 的类与函数蕴含着无尽的奥秘,从内联函数的高效执行,到静态成员的独特共享机制,再到各种特殊类和关键字的巧妙运用,以及友元和名字空间的神奇功能,每一处都值得我们细细品味。

相关文章:

九、重学C++—类和函数

上一章节&#xff1a; 八、重学C—动态多态&#xff08;运行期&#xff09;-CSDN博客https://blog.csdn.net/weixin_36323170/article/details/147004745?spm1001.2014.3001.5502 本章节代码&#xff1a; cpp/cppClassAndFunc.cpp CuiQingCheng/cppstudy - 码云 - 开源中国…...

使用MCP服务器实现AI任务完成通知:让Cursor更智能

0. 简介 在使用AI工具进行长时间任务时&#xff0c;常常需要等待结果。MCP&#xff08;Model Context Protocol&#xff09;服务器"mcp_server_notify"提供了一个优雅的解决方案&#xff0c;让AI在完成任务后通过系统通知提醒你。本文将介绍如何在Cursor中配置和使用…...

解决 Hugging Face SentenceTransformer 下载失败的完整指南:ProxyError、SSLError与手动下载方案

问题背景 在使用 Hugging Face 的 SentenceTransformer 加载预训练模型 all-MiniLM-L6-v2 时&#xff0c;遇到了以下错误&#xff1a; 代理连接失败&#xff08;ProxyError / SSLError: KRB5_S_TKT_NYV&#xff09;大文件下载中断&#xff08;unexpected EOF while reading&a…...

Linux | I.MX6ULL开发板固件烧录所需文件详述(9)

01 搞清楚手里的开发板是 EMMC 还是 NAND FLASH 。默认我的商业级是EMMC ,开关:10011010 终结者i.MX6ULL 开卡板分为工业级和商业级两种不同的开发板。 商业级的核心板,它的存储是 EMMC 的,EMMC 的存储是类似于正方形的芯片,旁边是 NAND FLASH的一个封装,因为我们这里…...

论文阅读笔记:Denoising Diffusion Implicit Models (5)

0、快速访问 论文阅读笔记&#xff1a;Denoising Diffusion Implicit Models &#xff08;1&#xff09; 论文阅读笔记&#xff1a;Denoising Diffusion Implicit Models &#xff08;2&#xff09; 论文阅读笔记&#xff1a;Denoising Diffusion Implicit Models &#xff08…...

【AI论文】GPT-ImgEval:一个用于诊断GPT4o在图像生成方面的综合基准

摘要&#xff1a;OpenAI的GPT4o模型最近的突破在图像生成和编辑方面展现了令人惊讶的良好能力&#xff0c;引起了社区的极大兴奋。 本技术报告介绍了第一眼评估基准&#xff08;名为GPT-ImgEval&#xff09;&#xff0c;定量和定性诊断GPT-4o在三个关键维度的性能&#xff1a;&…...

CSS3学习教程,从入门到精通, 学院网站完整项目 - HTML5 + CSS3 实现(25)

学院网站完整项目 - HTML5 CSS3 实现 下面是一个完整的学院网站项目&#xff0c;包含主页、新闻列表页、新闻详情页和视频宣传页的实现。我将按照您的要求提供详细的代码和注释。 项目结构 college-website/ ├── index.html # 主页 ├── news-list.html …...

Java虚拟机面试题:内存管理(中)

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家&#xff0c;历代文学网&#xff08;PC端可以访问&#xff1a;https://literature.sinhy.com/#/?__c1000&#xff0c;移动端可微信小程序搜索“历代文学”&#xff09;总架构师&#xff0c;15年工作经验&#xff0c;精通Java编…...

如何绕过myabtis-plus的逻辑删除条件

目标 mp中所有方法都会带上逻辑删除,如果启用了逻辑删除,有时候我们需要忽略逻辑删除.改如何实现 解决方法 自定义DeleteReal 方法 import com.baomidou.mybatisplus.core.enums.SqlMethod; import com.baomidou.mybatisplus.core.injector.AbstractMethod; import com.ba…...

王者荣耀的游戏匹配机制

王者荣耀的匹配机制主要基于ELO评分系统&#xff08;隐藏分机制&#xff09;和段位匹配&#xff0c;旨在平衡对局双方实力&#xff0c;同时通过多种策略控制玩家胜率趋近50%。 一、匹配机制核心 1. ELO评分&#xff08;隐藏分&#xff09; - 系统根据玩家的胜负、KDA、伤害量、…...

游戏无法启动?XINPUT1_3.dll 丢失的终极解决方案

当你兴奋地启动一款新游戏时&#xff0c;突然弹出一个错误提示——‘程序无法启动&#xff0c;因为计算机中丢失 XINPUT1_3.dll’。这种问题在 PC 玩家中非常常见&#xff0c;尤其是运行一些较老的游戏时。XINPUT1_3.dll 是 DirectX 运行库的关键组件&#xff0c;缺失会导致游戏…...

macOS下SourceInsight的替代品

macOS 推荐的几款开源、轻量级、且功能类似于 SourceInsight 的源码阅读工具&#xff08;排除 VS Code&#xff09;&#xff1a; 1. Zeal&#xff08;离线文档 简单代码导航&#xff09; 官网/GitHub: https://zealdocs.org/特点&#xff1a; 轻量级离线文档浏览器&#xff0…...

嵌入式硬件如何在PADS中将原理图转换为PCB详解

本文旨在讲述如何在PADS中将原理图转换为PCB。 本文以C51原理图作为例子。 1.首先在桌面上打开PADS Logic 2.找到菜单栏的文件选项,然后点击新建。 点击新建之后出现如下界面。...

FreeRTOS 软件定时器工作原理及应用

FreeRTOS 软件定时器工作原理及应用 FreeRTOS 的 软件定时器(Software Timer) 是一种基于系统节拍(Tick)的计时机制,允许开发者创建周期性或单次触发的定时任务,而无需依赖硬件定时器。软件定时器由 定时器服务任务(Timer Service Task) 管理,适用于需要时间控制但无…...

软件工程-UML

例图&#xff0c;类图&#xff0c;状态图&#xff0c;顺序图&#xff0c;活动图 目录 例图 类图 状态图 顺序图 活动图 例图 例图由四个元素组成&#xff0c;参与者、用例、系统边界、参与者和用例之间的关系 参与者用一个小人表示&#xff0c;用例用椭圆表示&#xff…...

力扣经典算法篇-9-跳跃游戏(贪心算法,反向递推)

题干&#xff1a; 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 …...

【Linux学习笔记】初识进程概念和进程PCB

【Linux学习笔记】初识冯诺依曼体系和进程PCB &#x1f525;个人主页&#xff1a;大白的编程日记 &#x1f525;专栏&#xff1a;Linux学习笔记 文章目录 【Linux学习笔记】初识冯诺依曼体系和进程PCB前言一. 冯诺依曼体系结构1.1 关于冯诺依曼体系的要点&#xff1a; 二. 操…...

深入探索 Linux Top 命令:15 个实用示例

在 Linux 系统管理中&#xff0c;top 命令是系统性能监控不可或缺的工具。它能够实时显示系统的 CPU、内存、进程等资源的使用情况&#xff0c;帮助您快速识别性能瓶颈和异常进程。本文将详细介绍 15 个实用的 top 命令使用示例&#xff0c;旨在帮助您更高效地进行系统管理与优…...

Linux命令-cut

cut 命令是一个非常实用的工具&#xff0c;用于从文本中提取特定部分。 参数 功能 -b 按字节提取内容 -c 按字符提取内容 -f 按字段提取内容&#xff0c;需配合 -d 指定分隔符 -d 指定字段分隔符&#xff08;默认是 \t&#xff09; -s 只处理包含分隔符的行 –complement 提取除…...

风电行业预测性维护解决方案:AIoT驱动下的风机健康管理革命

在风电行业向平价化与智慧化转型的关键阶段&#xff0c;如何通过预测性维护技术将风机可用率提升至99%以上&#xff1f;本文基于中讯烛龙系统的实战经验&#xff0c;解析如何构建基于LSTM、数字孪生与边缘计算的智能运维体系&#xff0c;实现从“故障维修”到“健康预判”的技术…...

通过Postman和OAuth 2.0连接Dynamics 365 Online的详细步骤

&#x1f31f; 引言 在企业应用开发中&#xff0c;Dynamics 365 Online作为微软的核心CRM平台&#xff0c;提供了强大的Web API接口。本文将教你如何通过Postman和OAuth 2.0认证实现与Dynamics 365的安全连接&#xff0c;轻松调用数据接口。 &#x1f4dd; 准备工作 工具安装…...

Ubuntu-安装redis

apt list | grep redis apt 类似于应用商店的感觉 ‘|’的作用是作为管道&#xff0c;把前者到的数据列表再通过grep筛选出包含redis字眼的一行数据 需要联网 apt install redis -y 修改配置文件 vi /etc/redis/redis.conf redis是客户端服务器程序 需要先把服务器给后台启…...

Mac 上使用 mysql -u root -p 命令,出现“zsh: command not found: mysql“?

一、确定 MySQL 安装路径&#xff1a; 如果你是使用 Homebrew 安装的 MySQL&#xff0c;通常安装路径是 /usr/local/mysql/bin 。 如果你是通过官方 DMG 安装包安装的 MySQL&#xff0c;默认安装路径可能是 /usr/local/mysql/bin 。你可以在终端中使用以下命令来查找 MySQL 的…...

P1883 【模板】三分 | 函数

题目描述 给定 n 个二次函数 f1​(x),f2​(x),…,fn​(x)&#xff08;均形如 ax2bxc&#xff09;&#xff0c;设 F(x)max{f1​(x),f2​(x),...,fn​(x)}&#xff0c;求 F(x) 在区间 [0,1000] 上的最小值。 输入格式 输入第一行为正整数 T&#xff0c;表示有 T 组数据。 每组…...

制造装备物联及生产管理ERP系统设计与实现(代码+数据库+LW)

摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装制造装备物联及生产管理ERP系统软件来发挥其高效地信息处理…...

[ctfshow web入门] web4

前置知识 robots.txt是机器人协议&#xff0c;在使用爬虫爬取网站内容时应该遵循的协议。协议并不能阻止爬虫爬取&#xff0c;更像是一种道德规范。 假设robots.txt中写道 Disallow: /admind.php&#xff0c;那我就暴露了自己的后台&#xff0c;这属于信息泄漏&#xff0c;攻击…...

Java的Selenium的特殊元素操作与定位之iframe切换

iframe切换 四种切换方式: driver.switchTo().frame(index);driver.switchTo().frame(id);driver.switchTo().frame(name);driver.switchTo().frame(WebElement); 切换之后&#xff0c;回到默认内容页面(否则会找不到元素 driver.switchTo().defaultContent(); //iframe处…...

【JavaWeb-Spring boot】学习笔记

目录 <<回到导览Spring boot1. http协议1.1.请求协议1.2.响应协议 2.Tomcat2.1.请求2.1.1.apifox2.1.2.简单参数2.1.3.实体参数2.1.4.数组集合参数2.1.5.日期参数2.1.6.(重点)JSON参数2.1.7.路径参数 2.2.响应2.3.综合练习 3.三层架构3.1.三层拆分3.2.分层解耦3.3.补充 &…...

SQLmap工具使用

1. sqlmap介绍 sqlmap是一款自动化的SQL注入工具&#xff0c;用于检测和利用web应用程序中的SQL注入漏洞。不需要我们进行手注&#xff0c;当我们输入url地址后&#xff0c;会自动进行注入指令并将payload返回显示。 在kali中自带。在本机中需要下载&#xff0c;在相应的路径…...

OpenCV 实现对形似宝马标的黄黑四象限标定位

文章目录 功能背景代码效果 功能 实现对形似宝马标的黄黑四象限光学识别标定位 背景 大学同学遇到了这个场景&#xff0c;琢磨了下&#xff0c;以备不时之需。 代码 所用opencv版本&#xff1a;4.12 numpy2.2.4 scikit_learn1.6.1import time import cv2 import numpy as…...