【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

Python 入门:FastAPI + SQLite3 + Requests 基础教学

Python 入门:FastAPI + SQLite3 + Requests 基础教学

前言 本文从语法、库使用、数据库连接到接口开发、请求调用一步步讲解,适合新手学习与日后复习。全程使用 Python 内置库 + 轻量框架,无需复杂环境。 一、基础知识点说明 1.1 各组件作用 * - FastAPI:Python 高性能 Web 框架,用于快速编写 API 接口。 * - SQLite3:Python 内置轻量级数据库,无需安装、无需启动服务,直接以文件形式存储数据。 * - Requests:用于发送 HTTP 请求,测试或调用自己写的 API。 * - Uvicorn:ASGI 服务器,用于运行 FastAPI 项目。 1.2 环境安装 pip

By Ne0inhk
【实战干货】AI时代,个人开发者如何用 Python 实现“黄金”量化交易?

【实战干货】AI时代,个人开发者如何用 Python 实现“黄金”量化交易?

摘要:最近金价狂飙,身边不少朋友都在讨论买黄金。作为一名技术人,我们能不能不靠“直觉”和“跟风”,而是用代码和 AI 模型来帮我们辅助决策?本文将通俗易懂地介绍什么是量化交易,并手把手带你从零开始,用 Python 搭建一个简单的 AI 黄金价格预测模型。 一、 什么是量化交易? 说得高大上一点,量化交易(Quantitative Trading)是“利用数学模型和计算机算法进行投资决策”。 说人话就是: * 传统交易:看新闻、听消息、看K线图,觉得“要涨了”就买,觉得“要跌了”就卖。核心是人的主观判断(容易上头,容易被割)。 * 量化交易:把你的判断逻辑写成代码。比如,“当金价跌破 20 日均线,且 RSI 指标小于 30

By Ne0inhk
【Python】【数据分析】Python 数据分析与可视化:全面指南

【Python】【数据分析】Python 数据分析与可视化:全面指南

目录 * 1. 环境准备 * 2. 数据处理与清洗 * 2.1 导入数据 * 2.2 数据清洗 * 示例:处理缺失值 * 示例:处理异常值 * 2.3 数据转换 * 3. 数据分析 * 3.1 描述性统计 * 3.2 分组分析 * 示例:按年龄分组计算工资的平均值 * 3.3 时间序列分析 * 4. 数据可视化 * 4.1 基本绘图 * 示例:柱状图 * 4.2 使用 Seaborn 绘制图表 * 示例:箱型图 * 4.3 高级可视化技巧 * 示例:热力图

By Ne0inhk
Python RESTful API设计终极指南:从理论到企业级实战

Python RESTful API设计终极指南:从理论到企业级实战

目录 摘要 1 引言:为什么RESTful API设计如此重要 1.1 RESTful API的核心价值定位 1.2 RESTful API演进路线图 2 RESTful API设计核心技术原理 2.1 资源设计哲学与实践 2.1.1 资源识别与建模 2.1.2 资源关系建模 2.2 统一接口原则深度解析 2.2.1 HTTP方法语义化使用 2.2.2 状态码语义化设计 2.3 HATEOAS超媒体驱动设计 2.3.1 HATEOAS原理与实现 2.3.2 HATEOAS客户端工作流程

By Ne0inhk