C++类与对象完整学习路线(上)
文章导航前序一.类的定义1.类定义格式1.1 访问限定符默认规则1.2 类域二.实例化到底是什么1.实例化2. 对象的大小三.你了解this指针多少大家好我是小沐。最近持续深耕C基础语法今天也是刚好来到了“类与对象”这一板块我也刚好整理了一些知识点对新手友好适合刚入门的同学查缺补漏。类的定义、实例化和this指针一.类的定义1.类定义格式C中用class和struct两个关键字来定义类{}中为类的主体结束时加上分号即可和C语言中的结构体写法一模一样。那我们不经问类到底是什么类是一种自定义的数据类型把自变量和函数作为主体即封装称里面的自变量为成员变量或属性称函数为成员函数或方法。那小白肯定会有疑惑的刚从C语言过渡只见过内置的数据类型如int 、char、double和struct等甚至都不知道一直在用的struct也是一种数据类型那你一个类里面又装函数又装变量的既然也是一种数据类型这时候看到这里脑子里面就会懵懵的。是的类就是一种数据类型。class zhangsan { void fuct1() { cout 1 endl; } }; struct lisi { void fuct2() { cout 2 endl; } };两种类定义和使用方法一模一样也算沿用C语言结构体的方式了。我们继续看下面这种调用会有什么结果#include iostream using namespace std; class zhangsan { void fauct1() { cout 1 endl; } }; struct lisi { void fuct2() { cout 2 endl; } }; int main() { zhangsan zhang; lisi li; zhang.fuct1(); li.fuct2(); return 0; }答案就是编译报错。class和struct定义的类虽然调用方式一样但语法上存在差异那就是访问限定符默认规则不一样。1.1 访问限定符默认规则class与struct的访问限定符——》public 公开的访问限定符——》protect 保护性有限制的限定符——》private 私有性限定符总所周知有这三个限定符修饰的区域都会有相应的特性在里面那没有限定符修饰的区域呢从上面的例子我们知道并不是两个都可以直接访问默认区域的成员函数的。规则class的默认区域是属于private区域的类外不以直接访问。struct的默认区域是属于public区域的类外可以直接访问。在习一般情况下我们是不会把成员函数写到private中而是写到public中。那么定义在private中的成员变量外边就没有办法访问了吗——是的类外确实不能直接访问private中的成员变量但可以通过这种间接的访问获取成员变量。我们以时间类为例class Date { public: int GetYear() { return _year ; } int GetMonth() { return _month; } int GetDay() { return _day; } private: int _year; int _month; int _day; };1.2 类域上面我们说类是一种数据类型那么这种数据类型定义时就会产生一个域它的所有成员都在里面我们称这个域为 “类域”。类域和其它域一样都会影响编译器的查找规则。我们一起来看下面的例子class Stack { public: //成员函数 void Init(int n 4); private: //成员变量 int* array; size_t capacity; size_t top; }; void Init(int n) { array (int*)malloc(sizeof(int) * n); if (array nullptr) { perror(Init::malloc); return; } capacity n; top 0; } int main() { Stack st; st.Init(); return 0; }思考一下这段代码有没有问题答案有问题我们说类会定义出一个域而域要被类外访问是需要通过域访问限定符::访问的。也就是说void Stack::Init(int n) //这里需要加上Stack:: { array (int*)malloc(sizeof(int) * n); if (array nullptr) { perror(Init::malloc); return; } capacity n; top 0; }如果这里没有加入Stack::这个初始化函数就只是一个在全局变量中定义的函数缺少的各种变量编译器都会自动去全局域里面找没有找到自然就会报错了。二.实例化到底是什么1.实例化定义类定义出的具体对象叫做实例化说得这么高级其实就是用类定义一个具体对象如class Data { public: int month; int day; } int main() { Data d1; //d1就是具体对象 return 0; }这里的d1就是具体的对象。定义了具体对象后开辟了可以运用的空间这个过程我们就管它就实例化。形象比喻类定义时就像做建筑用的设计图这时建筑仅仅停留在图纸层面还不能住人。当定义了一个具体对象后就像建筑已经从设计图到完成建筑建设可以住人了。2. 对象的大小思考既然类是一种数据类型那么类的大小是多大呢是所有成员的简单相加吗在计算对象大小前我们先再弄明白一个事情类的成员函数是存储在类里面吗如果是那就是定义一个具体对象就会同时在栈帧上开辟一块空间存储函数。如果不是那成员函数会存储在哪多个对象调用时过程是怎样的为回答这个问题我们将从汇编的层面观察调用过程。以这段代码为例class Stack { public: //成员函数 void Init(int n 4) { array (int*)malloc(sizeof(int) * n); if (array nullptr) { perror(Init::malloc); return; } capacity n; top 0; } private: //成员变量 int* array; size_t capacity; size_t top; }; int main() { Stack ST1; Stack ST2; ST1.Init(); ST2.Init(); return 0; }现在我们分别在ST1和ST2调用出打断点进行调试为方便观察我们选择在x86环境进行调试。我们看到第一步push入栈第二步把ST1的地址传给寄存器ecx第三步把Stack里面的Init函数的地址计算出来然后跳转到这个函数的地址执行操作。我们画的两个红圈中明显标注着ST1和ST2调用时计算出的地址是一样的呀这说明它两调用的是同一个函数也就是说类的成员函数虽然是在类里面定义的但编译时并没有存储在类的栈区里面。既然成员函数没有存储在类的栈区里面那么类的对象的大小就不需要计算成员函数的大小。好我们回归对象大小的计算问题一起看例子求下面对象的大小:class ST1 { public: int a; char b; }; class ST2 { void fuct() { int a; } }; class ST3 { }; int main() { cout sizeof(ST1) endl; cout sizeof(ST2) endl; cout sizeof(ST3) endl; return 0; }请问这段代码输出的结果是多少A.50, 0 B.8 0, 0 C.5,1,1 D.8,1,1我们来公布答案由于编译器在运行时受到内存对齐规则的约束第一个成员放在结构体偏移量为0的位置其它成员对齐到对齐数vs的默认对齐数为8的整数倍的地址出。注对齐数 编译器默认的一个对齐数 与该成员大小的较小值。总大小 最大对齐数的整数倍那么ST1在内存中应该是这样的由于最大对齐数是整型的对齐数4故总大小应该为4的整数倍故最终结果应为8个字节。问为什么只定义了成员函数和没有成员的对象大小不为0因为如果一个字节都不给就没有办法表示它们确实存在所以这里给1字节纯粹是为了占位标识对象存在。那么问题又来了为什么要内存对齐这不是会造成内存浪费吗这和机器硬件层面有关硬件里面有一个叫做地址总线有32条或64条与机器有关每一条通过充放电表示1和0也就是2进制的表现形式。以32条地址总线的机器为例无论你数据在内存中如何存放我cpu每次读取都是按照32bit的大小的整数倍范围进行读取如果数据存放没有内存对齐有可能出现数据被截断的情况就需要在读取结束后进行拼接更加繁琐还导致性能下降。这个时候我们的选择是牺牲空间换取时间。三.你了解this指针多少上面我们有说过类的成员函数并存储在类的栈帧区域里面但一个类同时定义出多个具体对象时它们可以调用统一函数那么这个函数是如何识别是哪个具体对象在调用它呢答案就是这部分的主角this指针。class Date { public: void DATE(int year, int month, int day) //void DATE(DATE* const this, int year, int month, int day) { cout year / month / day endl; } }; int main() { Date d1; Date d2; d1.DATE(2026, 8, 3); //d1.DATE(d1,2026, 8, 3); d2.DATE(2023, 9, 1); //d2.DATE(d2,2023, 9, 1); return 0; }在类域里面定义的函数都隐藏了一个this指针,在调用函数时编译器会自动帮你把对象的地址也传过去在输出部分实际上是这样的void DATE(int year, int month, int day) //void DATE(DATE* const this, int year, int month, int day) { cout this-year / this-month / this-day endl; }只是编译器把this指针给隐藏了。C规定不能在实参和形参的位置显式的写this指针但是可以在函数体内部显式写this指针。既然是指针就有可能出现空指针解引用的情况现在我们结合前面的知识来判断下面两段代码运行结果是什么代码1class A { public: void Print() { cout Print(int a 4) endl; } private: int _a; }; class B { public: void Print() { cout Print(int a 4) endl; cout _a endl; } private: int _a; }; int main() { A* a nullptr; //B* b nullptr; a-Print(); //b-Print(); return 0; }代码2class A { public: void Print() { cout Print(int a 4) endl; } private: int _a; }; class B { public: void Print() { cout Print(int a 4) endl; cout _a endl; } private: int _a; }; int main() { //A* a nullptr; B* b nullptr; //a-Print(); b-Print(); return 0; }代码1编译报错 运行崩溃 正常运行代码2编译报错 运行崩溃 正常运行那么答案是代码1正常运行代码2运行崩溃。如果这个问题没有做对说明你对this指针还是不了解。知识点this指针传的是对象的地址不是对象指针的地址这两个定义因为a和b已经存放的是对象的地址了所以这里传值的时候默认是这样a-Print(a);//不是a-Print(a) b-Print(b);//不是b-Print(b)那我们又知道地址传过去后如果没有解引用操作编译器是不会报错的。而代码1仅仅是打印了一个字符串啊并没有解引用操作。 对于代码2就不一样了class B { public: void Print() { cout Print(int a 4) endl; cout _a endl; //这里本质就是this-_a } private: int _a; };这里面_a的打印实际就是this-_a但是我们的this指针传过去的是空指针啊对空指针解引用就导致程序崩溃。好了本篇到这里就结束了你在学习这部分的时候有没有踩过什么坑评论区聊聊我整理到下一篇里~

相关新闻

从别名到脚本:构建高效个人命令管理体系的完整指南

从别名到脚本:构建高效个人命令管理体系的完整指南

1. 从“无法识别”到高效助手:为什么你需要一个命令管理器如果你在Windows的PowerShell里敲下opencode,大概率会看到那个熟悉的红色错误:“无法将‘opencode’项识别为 cmdlet、函数、脚本文件或可运行程序的名称”。这个错误本身&#xff0c…

2026/8/5 8:16:35 阅读更多 →
AI如何真正处理数学问题:从文本理解到定理证明的工程实践

AI如何真正处理数学问题:从文本理解到定理证明的工程实践

最近在技术社区里,一个标题为“OpenAI Astra 破解数学十大难题”的消息引起了不小的讨论。乍一看,这像是一个激动人心的突破,仿佛AI即将攻克人类智慧的巅峰。但作为一名长期与各类AI工具和模型打交道的开发者,我的第一反应是&…

2026/8/5 8:16:35 阅读更多 →
微信ClawBot技术解析:开源AI模型与微信生态的平民化AI代理实践

微信ClawBot技术解析:开源AI模型与微信生态的平民化AI代理实践

1. 从一只龙虾到14亿入口:ClawBot现象的本质是什么?最近,一个叫“微信ClawBot”的东西在圈子里火得不行。你可能没听过这个名字,但你大概率在微信群里见过它的“亲戚”——那些能陪你聊天、帮你查天气、甚至能写段子的机器人。Cla…

2026/8/5 8:16:35 阅读更多 →

最新新闻

一个关于显示器的笑话

一个关于显示器的笑话

一个嵌入式工程师买了台新显示器,回家发现画面一直闪。老婆问:"是不是线松了?"工程师:"不是。我抓 I2C 总线看了,EDID 读出来的时序参数是 1920x108060Hz,但显卡驱动硬要输出 144Hz。DDC/CI…

2026/8/5 9:02:54 阅读更多 →
STM32内部Flash模拟EEPROM:原理、HAL库实现与避坑指南

STM32内部Flash模拟EEPROM:原理、HAL库实现与避坑指南

1. 项目缘起:为什么需要关注STM32的内部Flash? 很多刚开始玩STM32的朋友,拿到一块像STM32F103C8T6这样的“蓝板”或者最小系统板,第一件事就是点灯、调串口,把程序下载进去跑起来。程序通常是通过ST-Link或者串口&…

2026/8/5 9:02:54 阅读更多 →
本地部署Qwen3.6-27B大模型:llama.cpp实战指南与性能实测

本地部署Qwen3.6-27B大模型:llama.cpp实战指南与性能实测

这次我们来看一个在本地部署大语言模型的实用方案:使用 llama.cpp 在本地运行 Qwen3.6-27B 模型。对于很多开发者来说,在个人电脑或服务器上部署一个 270 亿参数的大模型,最关心的不是它的理论性能,而是“我的显卡能不能跑起来”、…

2026/8/5 9:02:54 阅读更多 →
商标设计注册被驳回商标还能继续用吗?

商标设计注册被驳回商标还能继续用吗?

“提交了大半年,等来一纸驳回通知”——很多创业者收到驳回后的第一反应是:这个商标是不是彻底不能用了?答案并不绝对,取决于驳回的具体原因和你后续的应对策略。法律上:驳回不等于“禁止使用”首先要澄清一个常见误区…

2026/8/5 9:02:54 阅读更多 →
数字FM调制原理与Python实现:从音频到无线电波的软件定义广播

数字FM调制原理与Python实现:从音频到无线电波的软件定义广播

1. 项目概述:从数字音频到调频广播的桥梁如果你手头有一段数字音频,比如从麦克风录制的WAV文件,或者一段MP3解码后的PCM数据,你有没有想过,如何让它像传统的FM广播电台那样,通过无线电波发射出去&#xff1…

2026/8/5 9:02:54 阅读更多 →
Python零基础入门实战:从环境搭建到爬虫与数据分析项目整合

Python零基础入门实战:从环境搭建到爬虫与数据分析项目整合

这类教程最值得先看的不是它覆盖了多少个知识点,而是能不能帮你从零开始,把环境搭稳、把基础语法跑通、把第一个项目跑起来,最后能独立完成爬虫和数据分析这类实际任务。很多新手卡在第一步——环境配置和工具选择上,或者学了一堆…

2026/8/5 9:01:54 阅读更多 →

日新闻

Java缓存框架:JetCache

Java缓存框架:JetCache

TOC 一、简介 JetCache 是一个 Java 缓存抽象框架,为不同的缓存解决方案提供了统一的使用方式。 它提供的注解比 Spring Cache 更加强大。 JetCache 的注解支持原生 TTL、两级缓存以及在分布式环境中的自动刷新功能,同时你也可以通过代码直接操作 Cach…

2026/8/5 0:00:43 阅读更多 →
AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

AD 铺铜设置十字连接,过孔全连接,新版AD的简单设置

需求:通孔焊盘 十字花;过孔 Via 实心直连;贴片焊盘按需设置 AD 测试版本AD24 很多工程师踩坑:全部统一十字,导致接地过孔阻抗高、大电流发热! 一、快捷键打开规则 PCB 界面按下:D R 展开…

2026/8/5 0:00:43 阅读更多 →
AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

AI素描转换技术深度拆解(2024最新论文+工业级落地代码):从Stable Diffusion ControlNet到LoRA微调全链路解析

更多请点击: https://kaifayun.com 第一章:AI生成素描效果 AI生成素描效果是计算机视觉与风格迁移技术融合的典型应用,其核心在于将彩色照片或RGB图像转换为具有手绘质感、明暗对比强烈、边缘清晰的单色素描图像。该过程通常依赖于深度学习模…

2026/8/5 0:00:43 阅读更多 →

周新闻

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

最大流算法详解:从水管网络到Ford-Fulkerson与Dinic实战

1. 从水管网络到最大流:一个核心问题的诞生想象一下,你是一个城市供水系统的总工程师。你的城市有多个水源(水库),需要通过一个复杂的地下管道网络,将水输送到各个居民区。每条管道都有其最大通水能力&…

2026/8/4 13:24:41 阅读更多 →
基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

基于Springboot的企业门户网站(源码+LW+调试文档+讲解)

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

2026/8/4 11:41:39 阅读更多 →
MATLAB xcorr函数详解:从互相关原理到四大实战应用

MATLAB xcorr函数详解:从互相关原理到四大实战应用

1. 从一次信号“找茬”说起:为什么我们需要互相关几年前,我在处理一组声学传感器数据时遇到了一个棘手的问题。我有两个麦克风记录了一段相同的音频信号,理论上它们接收到的声音波形应该非常相似,只是由于麦克风位置不同&#xff…

2026/8/4 5:26:40 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/4 13:38:24 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/4 11:09:16 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/4 13:38:40 阅读更多 →