C++面向对象编程之四:成员变量和成员函数分开存储、this指针、const修饰成员和对象
在C++中,成员变量和成员函数是分开存储的,只有非静态成员变量才存储在类中或类的对象上。通过该类创建的所有对象都共享同一个函数
#include <iostream>
using namespace std;class Monster
{public://成员函数不占对象空间,所有对象共享同一个函数Monster():m_monsterId(0){}//成员函数不占对象空间,所有对象共享同一个函数Monster(const int monsterId):m_monsterId(monsterId){}//成员函数不占对象空间,所有对象共享同一个函数Monster(const Monster &m){m_monsterId = m.m_monsterId;}//成员函数不占对象空间,所有对象共享同一个函数~Monster(){}//静态成员函数存储在全局静态区,不占对象空间static void setMonsterCounter(const int counter){ms_counter = counter;}//静态成员函数存储在全局静态区,不占对象空间static int getMonsterCounter(){return ms_counter;}private://静态成员变量存储在全局静态区,不占对象空间static int ms_counter; //计数//非静态成员变量,占对象空间int m_monsterId; //怪物id
};int Monster::ms_counter = 0;int main(int argc, char *argv[])
{cout << "sizeof(Monster) = " << sizeof(Monster) << endl;Monster m;cout << "sizeof(m) = " << sizeof(m) << endl;return 0;
}

在C++中,空类占用内存大小为一个字节,因为即使是一个空对象,也要分配存储空间来识别这个空对象,所以C++分配了一个字节大小的空间给每一个空对象。
#include <iostream>
using namespace std;class Monster
{};int main(int argc, char *argv[])
{Monster m;cout << "空类占用内存大小为:" << sizeof(Monster) << endl;cout << "空对象占用内存大小为:" << sizeof(m) << endl;return 0;
}

C++中成员变量和成员函数是分开存储的,只有非静态成员才存储在类中或类的对象上。不管通过该类创建了多少对象,该类的每一个非静态成员函数只有一份,所有对象都同享非静态成员函数,那么这些非静态成员函数是如何区分是哪个对象调用自己的呢?C++通过this指针,解决这个问题。
this指针的特点:
this指针隐含在每一个非静态成员函数内,每一个非静态成员函数都隐含有一个this指针。当对象调用非静态成员函数时,this指针指向该对象。
this指针是是在非静态成员函数的开始前构造,并在非静态成员函数的结束后清除的,不需要声明,直接使用即可。
this指针的本质是指针常量,存储了调用该非静态成员函数的对象的地址,所以this指针的指向是不可以修改的。
注意:这里我们一直强调:每一个非静态成员函数都隐含有一个this指针,而静态成员函数的函数体内只能访问静态成员变量和静态成员函数,不能访问非静态成员变量和非静态成员函数,所以静态成员函数是没有this指针的。
this指针的作用:
在类的非静态成员函数中,形参和成员变量同名时,可以通过this指针来指明是对象的成员,还是形参名。
在类的非静态成员函数中需要返回该对象时,通过使用:return *this; 返回该对象自身。
#include <iostream>
using namespace std;class Monster
{public:Monster():monsterId(0){}//这里通过对象初始化列表的方式,是可以区分:monsterId是成员变量,(monsterId)是形参的//而且对象初始化列表中不能用:this->monsterId(monsterId)Monster(const int monsterId):monsterId(monsterId){}Monster(const Monster &m):monsterId(m.monsterId){}~Monster(){}Monster& getSelf(){return *this; //返回对象本身}// static Monster& getSelfByStatic()// {// return *this; //错误:非静态成员函数没有this指针// }void setMonsterId(const int monsterId){this->monsterId = monsterId; //形参和成员变量同名,所以需要用this指针区分,不然编译器不知道monsterId是成员变量还是形参}int getMonsterId(){return monsterId;}private:int monsterId;
};int main(int argc, char *argv[])
{Monster m(10001);cout << "怪物id = " << m.getMonsterId() << endl;m.setMonsterId(10002);cout << "怪物id = " << m.getSelf().getMonsterId() << endl;return 0;
}
注意:通过对象初始化列表的方式,是可以区分:monsterId是成员变量,(monsterId)是形参的,而且对象初始化列表中不能用:this->monsterId(monsterId),编译器会报错的
//这里通过对象初始化列表的方式,是可以区分:monsterId是成员变量,(monsterId)是形参的
//而且对象初始化列表中不能用:this->monsterId(monsterId),编译器会报错的
Monster(const int monsterId):monsterId(monsterId)
{}
C++中是允许空指针调用成员函数的,这时this = NULL;所以在非静态成员函数中,如果用到this指针,应该在用到this指针前,加以判断this指针是否为NULL。但是在程序设计的过程中,我们应该尽量禁用用空指针调用成员函数,稍微不注意,可能会导致我们的程序出现崩掉的情况。
const修饰的类成员
常量成员变量:在成员变量前,用const修饰该的成员变量(eg:const int m_monsterId;)。常量成员变量只能在构造函数中用初始化列表进行初始化,并且初始化后不能再修改。
常量成员函数:在成员函数后加上const修饰的成员函数(eg:void getMonsterId() const),也叫常函数。常量成员函数不能修改普通的成员属性,但常量成员函数可以对有mutable修饰的成员属性进行修改。
常对象
const修饰的对象叫常对象,常对象只能调用常函数
#include <iostream>
using namespace std;class Monster
{public:Monster():m_monsterId(0), m_name("怪物"), m_blood(500){}Monster(const int monsterId, const string name, const int blood):m_monsterId(monsterId), m_name(name), m_blood(blood){}Monster(const Monster &m):m_monsterId(m.m_monsterId), m_name(m.m_name), m_blood(m.m_blood){//m_name = m.m_name; //错误:常量成员属性只能用初始化列表进行初始化,这句调用编译器会报错}~Monster(){}void setMonsterId(const int monsterId){m_monsterId = monsterId;}int getMonsterId() const{//m_monsterId = 0; //错误:常函数不能修改普通成员变量的值return m_monsterId;}void setName(const string name){//m_name = name; //错误:m_name是常量成员属性,不能修改}string getName() const{return m_name;}void setBlood(const int blood) const{m_blood = blood; //正确:常函数可以修改用mutable修饰的成员属性}int getBlood(){return m_blood;}int getCounter(){return ms_counter;}private:int m_monsterId; //怪物idconst string m_name; //怪物名字 常量成员属性mutable int m_blood; //血量static int ms_counter;
};
int Monster::ms_counter = 0;int main(int argc, char *argv[])
{Monster m1(10001, "雪女", 10000);cout << "怪物id = " << m1.getMonsterId() << ",怪物名字 = " << m1.getName() << ",怪物血量 = " << m1.getBlood() << endl;const Monster m2(20001, "紫衣仙子", 20000);cout << "怪物id = " << m2.getMonsterId() << endl; //正确:常对象可以调用常函数//m2.setMonsterId(20002); //错误:常对象不可以调用普通成员函数//m2.getCounter(); //错误:常对象不可以调用静态成员函数return 0;
}
类的静态(static)成员和常量(const)成员是两个不同的概念,我们不应该混淆
类的静态成员
static成员变量
所有对象共享一份数据
在编译阶段分配内存
类内声明,类外初始化
有(public,protected,private)访问权限
static成员函数(在成员函数前加 static)
所有对象共享一个函数
静态成员函数的函数体内只能访问静态成员变量或静态成员函数,不能访问非静态成员变量和非静态成员函数
有(public,protected,private)权限
相关文章:

C++面向对象编程之四:成员变量和成员函数分开存储、this指针、const修饰成员和对象
在C中,成员变量和成员函数是分开存储的,只有非静态成员变量才存储在类中或类的对象上。通过该类创建的所有对象都共享同一个函数#include <iostream> using namespace std;class Monster {public://成员函数不占对象空间,所有对象共享同…...

卷积神经网络(CNN)基础知识
文章目录CNN的组成层卷积层卷积运算卷积的变种分组卷积转置卷积空洞卷积可变形卷积卷积层的输出尺寸和参数量CNN的组成层 在卷积神经⽹络中,⼀般包含5种类型的⽹络层次结构:输入层、卷积层、激活层、池化层和输出层。 输入层(input layer&a…...
opencv+python 常见图像预处理
import os import cv2 import numpy as np import pandas as pd from PIL import Image import matplotlib.pylab as plt """图像预处理"""#缩放 #灰度化 #二值化-otsu,自定义,自适应 #均值滤波 #中值滤波 #自定义滤波 #高斯/双倍滤波…...
如何实现一个单例模式
目录 前言 1.饿汉式 2.懒汉式 3.双重检测 4.静态内部类 5.枚举 总结: 前言 单例模式是我们日常开发过程中,遇到的最多的一种设计模式。通过这篇文章主要分享是实现单例的几种实现方式。 1.饿汉式 饿汉式的实现方式比较简单。在类加载的时候&#…...

传输线的物理基础(四):传输线的驱动和返回路径
驱动一条传输线对于将信号发射到传输线的高速驱动器,传输线在传输时间内的输入阻抗将表现得像一个电阻,相当于线路的特性阻抗。鉴于此等效电路模型,我们可以构建驱动器和传输线的电路,并计算发射到传输线中的电压。等效电路如下图…...

Java多态性
文章目录对象的多态性多态的理解举例7.2 多态的好处和弊端7.3 虚方法调用(Virtual Method Invocation)7.4 成员变量没有多态性7.5 向上转型与向下转型7.6 为什么要类型转换呢?7.7 如何向上转型与向下转型7.8 instanceof关键字7.9 复习:类型转换7.10 练习…...

算法拾遗二十七之窗口最大值或最小值的更新结构
算法拾遗二十七之窗口最大值或最小值的更新结构滑动窗口题目一题目二题目三题目四滑动窗口 第一种:R,R右动,数会从右侧进窗口 第二种:L,L右动,数从左侧出窗口 题目一 arr是N,窗口大小为W&…...

【带你搞定第二、三、四层交换机】
01 第二层交换机 OSI参考模型的第二层叫做数据链路层,第二层交换机通过链路层中的MAC地址实现不同端口间的数据交换。 第二层交换机主要功能,就包括物理编址、错误校验、帧序列以及数据流控制。 因为这是最基本的交换技术产品,目前桌面…...

C++基础了解-22-C++ 重载运算符和重载函数
C 重载运算符和重载函数 一、C 重载运算符和重载函数 C 允许在同一作用域中的某个函数和运算符指定多个定义,分别称为函数重载和运算符重载。 重载声明是指一个与之前已经在该作用域内声明过的函数或方法具有相同名称的声明,但是它们的参数列表和定义…...
BatchNormalization
目录 Covariate Shift Internal Covariate Shift BatchNormalization Q1:BN的原理 Q2:BN的作用 Q3:BN的缺陷 Q4:BN的均值、方差的计算维度 Q5:BN在训练和测试时有什么区别 Q6:BN的代码实现 Covariate Shift 机器学习中&a…...
vue 中安装插件实现 rem 适配
vue 中实现 rem 适配vue 项目实现页面自适应,可以安装插件实现。 postcss-pxtorem 是 PostCSS 的插件,用于将像素单元生成 rem 单位。 autoprefixer 浏览器前缀处理插件。 amfe-flexible 可伸缩布局方案替代了原先的 lib-flexible 选用了当前众多浏览…...

Hadoop学习
1.分布式与集群 hosts文件: 域名映射文件 2.Linux常用命令 ls -a:查看当前目录下所有文件mkdir -p:如果没有对应的父文件夹,会自动创建rm -rf:-f:强制删除 -r:递归删除cp -r:复制文…...

Golang反射源码分析
在go的源码包及一些开源组件中,经常可以看到reflect反射包的使用,本文就与大家一起探讨go反射机制的原理、学习其实现源码 首先,了解一下反射的定义: 反射是指计算机程序能够在运行时,能够描述其自身状态或行为、调整…...

Qt之悬浮球菜单
一、概述 最近想做一个炫酷的悬浮式菜单,考虑到菜单展开和美观,所以考虑学习下Qt的动画系统和状态机内容,打开QtCreator的示例教程浏览了下,大致发现教程中2D Painting程序和Animated Tiles程序有所帮助,如下图所示&a…...

易优cms attribute 栏目属性列表
attribute 栏目属性列表 attribute 栏目属性列表 [基础用法] 标签:attribute 描述:获取栏目的属性列表,或者单独获取某个属性值。 用法: {eyou:attribute typeauto} {$attr.name}:{$attr.value} {/eyou:attri…...

表格中的table-layout属性讲解
表格中的table-layout属性讲解 定义和用法 tableLayout 属性用来显示表格单元格、行、列的算法规则。 table-layout有三个属性值:auto、fixed、inherit。 fixed:固定表格布局 固定表格布局与自动表格布局相比,允许浏览器更快地对表格进行布…...

【MFA】windows环境下,使用Montreal-Forced-Aligner训练并对齐音频
文章目录一、安装MFA1.安装anaconda2.创建并进入虚拟环境3.安装pyTorch二、训练新的声学模型1.确保数据集的格式正确2.训练声音模型-导出模型和对齐文件3.报错处理1.遇到类似: Command ‘[‘createdb’,–host‘ ’, ‘Librispeech’]’ returned non-zero exit sta…...

C语言实验小项目实例源码大全订票信息管理系统贪吃蛇图书商品管理网络通信等
wx供重浩:创享日记 对话框发送:c项目 获取完整源码源文件视频讲解环境资源包文档说明等 包括火车订票系统、学生个人消费管理系统、超级万年历、学生信息管理系统、网络通信编程、商品管理系统、通讯录管理系统、企业员工管理系统、贪吃蛇游戏、图书管理…...
电脑图片损坏是怎么回事
电脑图片损坏是怎么回事?对于经常使用电脑的我们,总是会下载各种各样的图片,用于平时的使用中。但难免会遇到莫名其妙就损坏的图片文件,一旦发生这种情况,要如何才能修复损坏的图片呢?下面小编为大家带来常用的修复方…...

【论文研读】无人机飞行模拟仿真平台设计
无人机飞行模拟仿真平台设计 摘要: 为提高飞行控制算法的研发效率,降低研发成本,基于数字孪生技术设计一个无人机硬件在环飞行模拟仿真平台。从几何、物理和行为3个方面研究无人机数字模型构建方法,将物理实体以数字化方式呈现。设计一种多元融合场景建模法,依据属…...
谷歌浏览器插件
项目中有时候会用到插件 sync-cookie-extension1.0.0:开发环境同步测试 cookie 至 localhost,便于本地请求服务携带 cookie 参考地址:https://juejin.cn/post/7139354571712757767 里面有源码下载下来,加在到扩展即可使用FeHelp…...

【WiFi帧结构】
文章目录 帧结构MAC头部管理帧 帧结构 Wi-Fi的帧分为三部分组成:MAC头部frame bodyFCS,其中MAC是固定格式的,frame body是可变长度。 MAC头部有frame control,duration,address1,address2,addre…...
线程与协程
1. 线程与协程 1.1. “函数调用级别”的切换、上下文切换 1. 函数调用级别的切换 “函数调用级别的切换”是指:像函数调用/返回一样轻量地完成任务切换。 举例说明: 当你在程序中写一个函数调用: funcA() 然后 funcA 执行完后返回&…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践
6月5日,2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席,并作《智能体在安全领域的应用实践》主题演讲,分享了在智能体在安全领域的突破性实践。他指出,百度通过将安全能力…...

【OSG学习笔记】Day 16: 骨骼动画与蒙皮(osgAnimation)
骨骼动画基础 骨骼动画是 3D 计算机图形中常用的技术,它通过以下两个主要组件实现角色动画。 骨骼系统 (Skeleton):由层级结构的骨头组成,类似于人体骨骼蒙皮 (Mesh Skinning):将模型网格顶点绑定到骨骼上,使骨骼移动…...

网络编程(UDP编程)
思维导图 UDP基础编程(单播) 1.流程图 服务器:短信的接收方 创建套接字 (socket)-----------------------------------------》有手机指定网络信息-----------------------------------------------》有号码绑定套接字 (bind)--------------…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)
Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败,具体原因是客户端发送了密码认证请求,但Redis服务器未设置密码 1.为Redis设置密码(匹配客户端配置) 步骤: 1).修…...
DeepSeek 技术赋能无人农场协同作业:用 AI 重构农田管理 “神经网”
目录 一、引言二、DeepSeek 技术大揭秘2.1 核心架构解析2.2 关键技术剖析 三、智能农业无人农场协同作业现状3.1 发展现状概述3.2 协同作业模式介绍 四、DeepSeek 的 “农场奇妙游”4.1 数据处理与分析4.2 作物生长监测与预测4.3 病虫害防治4.4 农机协同作业调度 五、实际案例大…...

回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
高防服务器价格高原因分析
高防服务器的价格较高,主要是由于其特殊的防御机制、硬件配置、运营维护等多方面的综合成本。以下从技术、资源和服务三个维度详细解析高防服务器昂贵的原因: 一、硬件与技术投入 大带宽需求 DDoS攻击通过占用大量带宽资源瘫痪目标服务器,因此…...