【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

前端新手必学:5分钟搞懂import.meta.glob

快速体验 1. 打开 InsCode(快马)平台 https://www.inscode.net 2. 点击'项目生成'按钮,等待项目生成完整后预览效果 输入框内输入如下内容: 创建一个面向新手的import.meta.glob教学示例,要求:1. 使用最简单的项目结构 2. 分步骤解释功能原理 3. 提供可一键运行的代码 4. 包含常见问题解答 5. 使用比喻和图示辅助理解。生成Markdown格式的教学文档和配套示例代码。 最近在学习Vite时发现一个超级实用的功能——import.meta.glob,它能让模块导入变得像查电话簿一样简单。作为刚入坑的前端小白,我把摸索过程整理成这份指南,用最直白的方式帮你快速上手。 1. 什么是import.meta.glob? 想象你有个装满照片的文件夹,传统方式需要手动记录每张照片路径才能查看。而import.meta.glob就像给文件夹装了扫描仪,

By Ne0inhk

深入理解 Web Worker

深入理解 Web Worker:开启多线程编程的新时代 前言 在现代 Web 应用中,随着功能的日益复杂,JavaScript 单线程的特性逐渐成为性能瓶颈。当需要执行大量计算、处理复杂任务或进行密集型操作时,主线程可能会被阻塞,导致页面卡顿甚至无响应。Web Worker 的出现为这一问题提供了完美的解决方案。 什么是 Web Worker? Web Worker 是 HTML5 提供的一种在后台线程中运行 JavaScript 的技术。它允许开发者将耗时的任务从主线程分离出来,在独立的线程中执行,从而避免阻塞用户界面。 Web Worker 的核心特性 1. 并行执行:Worker 在独立的线程中运行,不会阻塞主线程 2. 消息传递:通过 postMessage 和 onmessage 进行线程间通信 3. 同源限制:Worker 只能加载同源的脚本

By Ne0inhk

零基础手把手教程:用gpt-oss-20b-WEBUI快速搭建本地AI对话系统

零基础手把手教程:用gpt-oss-20b-WEBUI快速搭建本地AI对话系统 1. 为什么选这个镜像?小白也能跑起来的“真开源”体验 你可能已经看到过不少“本地大模型”教程,但真正能让你在普通电脑上点开浏览器就聊天、不用折腾CUDA版本、不报错、不卡死的方案,其实不多。gpt-oss-20b-WEBUI这个镜像,就是为“不想装环境、只想用模型”的人准备的。 它不是包装精美的黑盒应用,也不是需要你手动编译vLLM的硬核项目——它是OpenAI官方开源权重(gpt-oss)+ vLLM高速推理引擎 + 预置WebUI的完整组合包,所有依赖都已打包好,部署完就能直接打开网页对话。 重点来了: * 不用装Python、不用配CUDA、不用改配置文件; * 不依赖Ollama、不依赖Docker Desktop(Windows用户尤其友好); * 双卡RTX 4090D可跑20B模型,单卡3090/4080也能稳推,甚至A10G云显卡实测可用; * 界面就是ChatGPT风格,输入即响应,支持多轮对话、历史保存、导出记录。 如果你试过其他方案却卡在“pip install

By Ne0inhk

Clawdbot整合Qwen3-32B保姆级教程:Web网关18789端口调试全记录

Clawdbot整合Qwen3-32B保姆级教程:Web网关18789端口调试全记录 1. 为什么需要这个整合方案 你是不是也遇到过这样的问题:想用本地部署的大模型做聊天机器人,但发现直接调用Ollama的API在Web前端里跨域报错?或者Clawdbot配置完后一直连不上模型,控制台疯狂刷404?又或者好不容易跑起来了,发个消息却卡在“正在思考”半天没反应? 这正是我们搭建这套环境时踩过的坑。Clawdbot本身不直接对接Ollama,它需要一个中间层来处理协议转换、请求转发和端口映射。而18789这个端口,就是整个链路里最关键的“通关密码”——它不是随便选的,而是Clawdbot默认监听的Web网关入口。 整套方案的核心逻辑其实很朴素: * 你在浏览器里访问 http://localhost:18789,看到的是Clawdbot的聊天界面 * Clawdbot收到你的消息后,不自己去算答案,而是把请求转给内部代理 * 代理再把请求发到 http://localhost:8080(Ollama API地址) * Ollama调用本地的Qwen3-32B模型生成回复

By Ne0inhk