【C++深学日志】C++“类”的完全指南--从基础到实践(一)

【C++深学日志】C++“类”的完全指南--从基础到实践(一)
假想一下,你是一个顶级汽车设计师,你的任务不是亲自拧紧每一个螺丝,而是要设计出一幅“汽车蓝图”,你在图纸上设计了一辆汽车所需的一切:车轮、车灯、V8发动机、方向盘等,你手上这份设计好的蓝图就相当于我们今天要讲的C++中的“类”,它规定了汽车的属性(例如:离合器)和方法(功能:换挡),它本身并不是一辆真正的汽车,只是你的一份设计规划,后续你交付给工厂,工厂按照你的设计蓝图,生产出了一辆汽车,这就是实例化,后续工厂有根据你的蓝图设计了一条流水线,每一辆从流水线上生产下来的车辆,都是里这个蓝图(类)的一个对象,他们都有蓝图定义的属性和功能。在C++中类就充当着蓝图的作用,它定义了对象拥有哪些属性,那么就和我一起来揭开这份“蓝图”的面纱吧。

1.类

1.1.类的定义

类的基本思想是数据抽象封装,数据抽象是一种依赖于接口和实现的分离式编程技术,类的接口包括用户所能执行的操作,类的实现则是包括类的数据成员、负责接口实现的函数以及定义类所需的各种私有函数。封装实现了类的接口和实现的分离,封装后的类隐藏了他的视线细节,也就是说,用户只能使用指定的接口而无法访问实现部分。类想要实现数据抽象和封装,首先需要定义一个抽象数据类型,在抽象的数据类型中,由类的设计者负责考虑类的实现过程,使用该类型的程序员则只需要考虑类型做了什么,而无需了解类型的工作细节。

C++中通过关键字class来定义一个类,类的定义通常包括类名、访问限定符、成员变量和成员函数,类的定义格式如下:

class classname{ public: //公有成员变量,可以被直接访问 classname(); //类的构造函数后面会讲解 ~classname(); //类的析构函数 void test(); //成员函数 private: //私有成员变量,只能被类的成员函数和友元函数访问 int a; //私有成员变量 protect: //受保护的成员,可以被类的派生类所访问 int b; //受保护的成员变量 };

这里面有好多我们没有接触过的概念,放心先不急,一点一点来,都会讲到的。其中,class定义一个类,classname为定义的类名,{}所包含的为类的主体,特别注意:定义类结束时{}外面的分号不能像定义函数一样被省略。类主体中的内容被称为类成员,类中的变量被称为成员变量,类中的函数被称为成员函数。

成员函数的定义分为类内定义和类外定义,类内定义:在函数体内直接定义,一般地这一类函数会被编译器隐式地当作内联函数处理:

class classname { public: void setname(const std::string& Name) { name=Name; } private: std::string name; };

类外定义:在类内声明函数,然后再类外面使用作用域解析运算符::来定义函数体:

class classname { public: void setname(const std::string& Name); private: std:string name; }; void classname::setname(const std::string& Name) { name=Name; }

大家应该发现我在前两个类定义的例子中传入的形参和类内的成员变量相同,为了区分我将形参的首个字母大写处理了,这种方法其实不太好,我们在工作中难免会遇到这种情况,如果一时疏忽忘了区分大小写,这时候处理起来会非常麻烦,为了区分成员变量,我们一般习惯为成员变量加一个特殊标识,我用习惯了在成员变量前加"_",这样我们在区分时会非常方便,举个例子:

class Date { public: void Init(int year,int month,int day) { _year=year; _month=month; _day=day; } private: int _year; int _month; int _day; };

1.2访问限定符

C++中访问限定符是面向对象编程中实现封装的基石,访问限定符主要用于控制类成员的访问权限,访问限定符决定了类的成员(包括成员变量和成员函数)是否可以被类外的代码或其他类访问,C++提供了三种主要的访问限定符:public、private、protected。

1.2.1piblic访问限定符

public访问限定符表示类的成员可以被类外面的代码直接访问,换句话说,public成员对任何人都是可见的。通常用于类的接口,即那些希望被外部代码访问的成员函数和变量:

class MyClass { public: int publicVar; //公有成员变量 void publicFunction() //公有成员函数 { // 此处省略函数体 } }; int main() { MyClass obj; obj.publicVar = 10; // 可以直接访问 obj.publicFunction(); // 可以直接调用 return 0; } 

1.2.2private访问限定符

private访问限定符表示类的成员只能被类的成员函数和类的友元函数访问,不能被类外的代码直接访问。通常用于隐藏类的内部实现细节,确保类的封装,通常将成员设置成private,为了防止直接从类的外部直接修改类成员的值,从而提升代码的安全性和稳定性:

class Myclass { public: //用来展现类内的成员函数可以直接访问private的成员 void publicFunction(int a) { privateVal=a; } private: int privateVal;//private的成员 }; int main() { Myclass test; test.privateVal=10; test.publicFuntion(10); return 0; }

在这里我们可以看到报错反馈:不可访问。这就是private访问限定符将成员保护起来了,阻止外界直接对其值随意修改。那怎么证明类的成员函数可以直接访问private的成员呢?打个断点和监视窗口我们来看看private成员的值有没有发生改变被修改成10:

1.2.3protected访问限定符

protected访问限定符表示类的成员可以被类的成员函数、友元函数以及类的派生类访问,不能被类外的代码直接访问。大家是不是觉得protected访问限定符和刚刚的private访问限定符好像,只是多了一个可以被派生类所访问,其实他就是public和private的一种折中的结果,现在大家可以先把它的功能理解为和private一样,等到后面继承时会详细讲解他俩的区别,现在我就为大家简单的实现一下可以被派生类访问这一个例子:

class Myclass { protected: int val; }; class test:public Myclass { public: void Function(int a) { val=a; printf("val=%d",val); } }: int main() { test SL; SL.Function(10); return 0; }

这时候又该有小伙伴说了:这两次限定符都能被友元函数所访问你怎么没实现,因为后面会单独对它进行讲解,那时候会有很多例子让大家可以清楚的感知到这一特性。

1.3类域

在C++中,类域也被称为类作用域,指的是类成员(成员变量和成员函数)的作用范围和可见性,其和C语言中函数的作用域差不多。我们知道局部域和全局域是会影响生命周期的,因为它会影响对象是否存在不用的作用域内,局部的会存在函数的栈帧中,函数结束就销毁了,而静态、全局域则会存在静态区里,main函数创建之前就已经存在,当main函数结束时才会销毁。类作用域和命名空间都不影响生命周期,只会影响查找规则,同一个作用域内不能出现相同的变量名,不同的作用域是可以创建同名变量的。类的成员都是在类作用域内的,类外定义成员函数时必须使用作用域解析运算符(::)来指明类域:

class Date { public: void Init(int year, int month, int day); private: int _year; int _month; int _day; }; void Date::Init(int year, int month, int day) { _year = year; _month = month; _day = day; } int main() { Date time; time.Init(2025,9,21); return 0; }

在C++中静态成员变量必须在类外定义和初始化,这是由静态成员和新特性和C++编译链接模型共同决定的,这样主要是为了确保静态成员变量在程序的所有使用场合中只有一次定义,避免多重定义错误,并明确其独特的生命周期和存储位置。

class Myclass { public: static int val; }; int Myclass::val=10; 

生命和定义分离的核心原因:在类内使用static关键字对成员变量进行声明,仅仅像编译器说明这是一个该类的静态变量,并不会实际分配内存,定义的的作用是真正为变量分配空间,C++遵循“一次定义规则”(只能有一次定义,但可以有多次声明),为了确保整个程序中静态成员变量只有唯一的一次定义,这个定义必须放到类外(通常放到.cpp文件中),避免了多个源文件包含同一个头文件而出现的重复定义的错误:

静态成员变量不属于任何对象,它存放于静态区,其生命周期与程序同步,这种全局特性决定了它的初始化不能依赖于对象的创建,要在程序开始时完成初始化,在类外初始化正式为了满足他这一特性。

我的博客即将同步至腾讯云开发者社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=bgh7lptdufj

Read more

SkyWalking - .NET / C++ / Lua 探针现状与社区支持

SkyWalking - .NET / C++ / Lua 探针现状与社区支持

👋 大家好,欢迎来到我的技术博客! 📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。 🎯 本文将围绕SkyWalking这个话题展开,希望能为你带来一些启发或实用的参考。 🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获! 文章目录 * SkyWalking - .NET / C++ / Lua 探针现状与社区支持 🌐 * 一、SkyWalking 多语言探针架构概览 🧩 * 二、Java 探针:成熟稳定,功能最全 ☕️ * 示例:Spring Boot 应用接入 SkyWalking * Java 探针高级特性 * 三、.NET 探针现状:渐趋成熟,生产可用 🖥️ * 技术原理 * 使用方式 * 当前支持的功能 * 局限性 * 四、C++ 探针现状:SDK 形式,适合嵌入式场景 ⚙️ * cpp2sky SDK

By Ne0inhk
【一天一个计算机知识】—— 【 C/C++ 内存管理与分布】

【一天一个计算机知识】—— 【 C/C++ 内存管理与分布】

⚡ CYBER_PROFILE ⚡ /// SYSTEM READY /// [WARNING]: DETECTING HIGH ENERGY 🌊 🌉 🌊 心手合一 · 水到渠成 >>> ACCESS TERMINAL <<<[ 🦾 作者主页 ][ 🔥 C语言核心 ][ 💾 编程百度 ][ 📡 代码仓库 ] --------------------------------------- Running Process: 100% | Latency: 0ms 索引与导读 * 🚩一、C/C++ 内存分布 * 🚩二、C语言的动态内存管理 * 💪C动态内存管理的面试考点 * 1)realloc的工作机制 * 2)malloc/calloc/realloc的区别是什么? * 🚩三、C++ 动态内存管理 * 1)操作内置类型 * 1.1)单个变量的分配和释放

By Ne0inhk
【Linux/C++多进程篇(一) 】一个变两个?揭秘 C/C++ 程序中神奇的“分身术”

【Linux/C++多进程篇(一) 】一个变两个?揭秘 C/C++ 程序中神奇的“分身术”

⭐️在这个怀疑的年代,我们依然需要信仰。 个人主页:YYYing. ⭐️Linux/C++进阶系列专栏:【从零开始的linux/c++进阶编程】 ⭐️其他专栏:【linux基础】【数据结构与算法】【从零开始的计算机网络学习】 系列上期内容:【Linux/C++文件篇(一) 】标准I/O与文件I/O基础  系列下期内容:【Linux/C++多进程篇(二) 】万字解析linux系统编程之进程间通信 (IPC) 目录 前言:        多进程理论基础 一、为什么要引入多进程 二、多进程相关概念 三、进程的内存管理 四、进程与程序的区别 五、进程的种类 六、进程PID 七、特殊的进程 八、linux中有关进程的指令 九、进程状态的切换

By Ne0inhk

Java毕设选题推荐:基于SpringBoot的电脑笔记本维修工单进度管理系统的设计与实现【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍:✌️码农一枚 ,专注于大学生项目实战开发、讲解和毕业🚢文撰写修改等。全栈领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围::小程序、SpringBoot、SSM、JSP、Vue、PHP、Java、python、爬虫、数据可视化、大数据、物联网、机器学习等设计与开发。 主要内容:免费开题报告、任务书、全bao定制+中期检查PPT、代码编写、🚢文编写和辅导、🚢文降重、长期答辩答疑辅导、一对一专业代码讲解辅导答辩、模拟答辩演练、和理解代码逻辑思路。 特色服务内容:答辩必过班 (全程一对一技术交流,帮助大家顺利完成答辩,小白必选) 全网粉丝50W+,累计帮助2000+完成优秀毕设 🍅文末获取源码🍅 感兴趣的可以先收藏起来,还有大家在毕设选题,

By Ne0inhk