【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

解锁DeepSeek潜能:Docker+Ollama打造本地大模型部署新范式

解锁DeepSeek潜能:Docker+Ollama打造本地大模型部署新范式

🐇明明跟你说过:个人主页 🏅个人专栏:《深度探秘:AI界的007》 🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、什么是Docker 2、什么是Ollama 二、准备工作 1、操作系统 2、镜像准备 三、安装 1、安装Docker 2、启动Ollama 3、拉取Deepseek大模型 4、启动Deepseek  一、引言 1、什么是Docker Docker:就像一个“打包好的App” 想象一下,你写了一个很棒的程序,在自己的电脑上运行得很好。但当你把它发给别人,可能会遇到各种问题: * “这个软件需要 Python 3.8,但我只有 Python 3.6!

By Ne0inhk
深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本

深挖 DeepSeek 隐藏玩法·智能炼金术2.0版本

前引:屏幕前的你还在AI智能搜索框这样搜索吗?“这道题怎么写”“苹果为什么红”“怎么不被发现翘课” ,。看到此篇文章的小伙伴们!请准备好你的思维魔杖,开启【霍格沃茨模式】,看我如何更新秘密的【知识炼金术】,我们一起来解锁更加刺激的剧情!友情提醒:《《《前方高能》》》 目录 在哪使用DeepSeek 如何对提需求  隐藏玩法总结 几个高阶提示词 职场打工人 自媒体创作 电商实战 程序员开挂 非适用场地 “服务器繁忙”如何解决 (1)硅基流动平台 (2)Chatbox + API集成方案 (3)各大云平台 搭建个人知识库 前置准备 下载安装AnythingLLM 选择DeepSeek作为AI提供商 创作工作区 导入文档 编辑  编辑 小编寄语 ——————————————————————————————————————————— 在哪使用DeepSeek 我们解锁剧情前,肯定要知道在哪用DeepSeek!咯,为了照顾一些萌新朋友,它的下载方式我放在下面了,拿走不谢!  (1)

By Ne0inhk
【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

【AI大模型】DeepSeek + 通义万相高效制作AI视频实战详解

目录 一、前言 二、AI视频概述 2.1 什么是AI视频 2.2 AI视频核心特点 2.3 AI视频应用场景 三、通义万相介绍 3.1 通义万相概述 3.1.1 什么是通义万相 3.2 通义万相核心特点 3.3 通义万相技术特点 3.4 通义万相应用场景 四、DeepSeek + 通义万相制作AI视频流程 4.1 DeepSeek + 通义万相制作视频优势 4.1.1 DeepSeek 优势 4.1.2 通义万相视频生成优势 4.2

By Ne0inhk
【DeepSeek微调实践】DeepSeek-R1大模型基于MS-Swift框架部署/推理/微调实践大全

【DeepSeek微调实践】DeepSeek-R1大模型基于MS-Swift框架部署/推理/微调实践大全

系列篇章💥 No.文章01【DeepSeek应用实践】DeepSeek接入Word、WPS方法详解:无需代码,轻松实现智能办公助手功能02【DeepSeek应用实践】通义灵码 + DeepSeek:AI 编程助手的实战指南03【DeepSeek应用实践】Cline集成DeepSeek:开源AI编程助手,终端与Web开发的超强助力04【DeepSeek开发入门】DeepSeek API 开发初体验05【DeepSeek开发入门】DeepSeek API高级开发指南(推理与多轮对话机器人实践)06【DeepSeek开发入门】Function Calling 函数功能应用实战指南07【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:本地部署与API服务快速上手08【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:Web聊天机器人部署指南09【DeepSeek部署实战】DeepSeek-R1-Distill-Qwen-7B:基于vLLM 搭建高性能推理服务器10【DeepSeek部署实战】基于Ollama快速部署Dee

By Ne0inhk