讨论C++类与对象

讨论C++类与对象

  • C语言结构体和C++类的对比
  • 类的实例化
  • 类对象的大小
    • 猜想一
    • 猜想二
    • 针对上述猜想的实践
  • `this`指针
    • 不同对象调用成员函数
  • 类的6个默认成员函数
    • 构造函数
    • 析构函数
    • 拷贝构造函数
      • 浅拷贝和深拷贝
    • 赋值运算符重载
  • 初始化列表
      • 初始化顺序

C语言结构体和C++类的对比

在C语言中,要想描述一个复杂结构,需要使用结构体。例如描述一个学生,需要有学号,学生姓名,年龄以及性别。

C语言中结构体

上述代码结果:

结构体输出结果

C语言中的结构体可以描述复杂结构,但想要修改就需要在外部定义函数,传入结构体指针,较为复杂。

void modifyStudent(struct Student* pst)
{printf("请输入想要修改的年龄:");int age = 0;scanf("%d", &age);pst->age = age;
}

修改结构体对象中的值

在C++中,引入了类的概念,它类似于C语言的结构体,可以描述一个复杂结构,不同于结构体,类中是可以定义成员函数的,可以极大方便对成员变量进行修改。

为了兼容C语言,C++中使用struct关键字可以定义类,也可以使用class关键字定义类。

struct关键字定义的类没有访问修饰限定符,默认都是public公开访问的。

class关键字定义的类可以自定访问修饰限定符,privateprotectedpublic,默认的访问权限是private私有的。类外不能访问。

class Student {
public:int _stuId;std::string _name;int _age;std::string _gender;
};

如上代码便定义出一个学生类,由于成员变量都是public公有的,所以在类外也可以访问。

类的实例化

用类类型创建对象的过程,称为类的实例化。

int main() {Student st1;st1._stuId = 101;st1._name = "张三";st1._age = 23;st1._gender = "男";std::cout << "学生> 学号:" << st1._stuId << ", 姓名:" << st1._name <<", 年龄:" << st1._age << ", 性别:" << st1._gender << std::endl;return 0;
}

对象成员变量访问

  • 如果成员变量使用private修饰,类外就不能直接进行访问,会报错。

类对象的大小

类中既有成员变量,又有成员函数,那么类对象的存储方式是什么样的呢?

猜想一

成员变量和成员函数都存储在类对象中。

class Test1 {
public:void test() {}
private:int _a;
};

类对象存储猜想1

猜想二

成员变量存储在类对象中,成员函数存储在公共代码段中,由函数表记录。

类对象存储猜想2

针对上述猜想的实践

  • 使用sizeof计算类对象的大小。如果成员函数存储在类对象中,则对象所占内存大小一定大于int所占内存大小。
int main() {Test1 t1;std::cout << sizeof(t1) << std::endl;return 0;
}

类对象所占空间大小

由此可得出结论:只有成员变量存储在类对象中,成员函数存储在公共代码段中。

类对象所占空间大小也遵循内存对齐规则。

this指针

针对上述内容的讨论,可以得知每个实例化的对象都有一份自己的成员变量,但成员函数存放在公共代码段中,是所有对象共有的,但通过代码可知,通过不同对象调用成员函数,得到的成员变量是不同的。

不同对象调用成员函数

class Student {
public:void print() {std::cout << "学生> 学号:" << _stuId << ", 姓名:" << _name <<", 年龄:" << _age << ", 性别:" << _gender << std::endl;}public:int _stuId;std::string _name;int _age;std::string _gender;
};int main() {Student st1;st1._stuId = 101;st1._name = "张三";st1._age = 23;st1._gender = "男";st1.print();Student st2;st2._stuId = 102;st2._name = "李四";st2._age = 24;st2._gender = "女";st2.print();return 0;
}

不同对象打印的值不同

  • 由此可见,在成员函数中一定有一个标识,表示不同的对象调用,这个标识就是***this指针*。

在每一个成员函数中,都有一个隐藏的参数,即this指针,该指针表示当前调用的对象。

this指针

类似于如上图所示,不过这个this指针不需要我们写出来,是编译器默认生成的,这就是即使成员函数不存放在对象中,不同的对象调用成员函数所显示的值会不一样了。

类的6个默认成员函数

默认成员函数即我们不写,编译器会自动生成的成员函数。

6个默认成员函数

构造函数

对于学生类,成员变量如果设为私有,类外便不能访问,实例化对象时,就不能直接赋值。若提供对外的getter & setter接口,也只能在实例化之后再一一赋值。如何达到实例化对象中就完成对对象成员变量的初始化,这就需要构造函数来完成。

构造函数是一个特殊的成员函数,函数名和类名相同,没有返回值,实例化对象时由编译器自动调用,且在对象的生命周期中只调用一次。

class Student {
public:Student() {std::cout << "无参的构造函数调用了" << std::endl;} // 无参的构造函数Student(int stuId, std::string name, int age, std::string gender) { // 有参的构造函数std::cout << "有参的构造函数调用了" << std::endl;_stuId = stuId;_name = name;_age = age;_gender = gender;}void print() {std::cout << "学生> 学号:" << _stuId << ", 姓名:" << _name <<", 年龄:" << _age << ", 性别:" << _gender << std::endl;}private:int _stuId;std::string _name;int _age;std::string _gender;
};int main() {Student st1;st1.print();Student st2(102, "李四", 24, "女");st2.print();return 0;
}

构造函数

C++标准规定,若不对成员变量做初始化,编译器默认对内置类型不做处理,自定义类型会调用其默认的构造函数。

当然,如果我们不显示写构造函数,编译器会生成不带参数的构造函数,如果我们显示写了,编译器就不再生成不带参数的构造函数了。

class Student {
public:
//    Student() {
//        std::cout << "无参的构造函数调用了" << std::endl;
//    } // 无参的构造函数Student(int stuId, std::string name, int age, std::string gender) { // 有参的构造函数std::cout << "有参的构造函数调用了" << std::endl;_stuId = stuId;_name = name;_age = age;_gender = gender;}void print() {std::cout << "学生> 学号:" << _stuId << ", 姓名:" << _name <<", 年龄:" << _age << ", 性别:" << _gender << std::endl;}private:int _stuId;std::string _name;int _age;std::string _gender;
};int main() {Student st1; // 此处会报错,因为显示写了带参数的构造函数,编译器不再生成不带参的构造函数。st1.print();Student st2(102, "李四", 24, "女");st2.print();return 0;
}

为了省事,不写那么多构造函数,我们也可以采用参数全缺省的形式来充当默认成员函数。

class Student {
public:Student(int stuId = 101, std::string name = "张三", int age = 23, std::string gender = "男") { // 有参的构造函数std::cout << "有参全缺省的构造函数调用了" << std::endl;_stuId = stuId;_name = name;_age = age;_gender = gender;}void print() {std::cout << "学生> 学号:" << _stuId << ", 姓名:" << _name <<", 年龄:" << _age << ", 性别:" << _gender << std::endl;}private:int _stuId;std::string _name;int _age;std::string _gender;
};

实例化对象时,若给初始值,则直接采用缺省值。

全缺省构造函数

析构函数

析构函数与构造函数的作用刚好相反,对象在销毁时自动调用析构函数,完成对象中资源的清理工作。

  • 语法:
    • 析构函数名与类名相同,在函数名前加~
    • 无返回值。
    • 一个类只能有一个析构函数,析构函数不能重载。
    • 对象生命周期结束时,编译器自动调用析构函数。
class Student {
public:Student(int stuId = 101, std::string name = "张三", int age = 23, std::string gender = "男") { // 有参的构造函数_stuId = stuId;_name = name;_age = age;_gender = gender;}void print() {std::cout << "学生> 学号:" << _stuId << ", 姓名:" << _name <<", 年龄:" << _age << ", 性别:" << _gender << std::endl;}~Student() {std::cout << "Student类的析构函数调用了" << std::endl;}private:int _stuId;std::string _name;int _age;std::string _gender;
};int main() {Student st1(102, "李四", 24, "女");st1.print();return 0;
}

析构函数

析构函数也是特殊的成员函数,因此对内置类型不做处理,自定义类型调用其析构函数。

拷贝构造函数

拷贝构造函数是构造函数的一个重载,参数只能有一个,且是类类型的引用。

拷贝构造函数

int main() {Student st1(102, "李四", 24, "女");st1.print();Student st2(st1); // 使用拷贝构造函数实例化对象st2.print();return 0;
}

拷贝构造函数打印结果

若未显示定义拷贝构造函数,编译器会自动生成默认的拷贝构造函数。对象会按照内存存储字节序完成拷贝,即浅拷贝。

浅拷贝和深拷贝

  • 如上述所说,浅拷贝只是对内存的直接复制,如果只是栈上开辟空间的变量,影响还没有那么大,但如果是在堆上开辟的空间,那么只拷贝值会影响非常大。
class Test {
public:Test() {_a = (int*)malloc(10 * sizeof(int));b = 20;}~Test() {free(_a);_a = nullptr;}
private:int* _a;int b;
};

浅拷贝

默认生成的拷贝构造函数

  • 因此,面对这种情形,默认生成的拷贝构造函数就不能满足条件了,因此就需要自己显示定义拷贝构造函数,来达到深拷贝。

深拷贝

赋值运算符重载

C++为了增强代码的可读性,引入了运算符重载。

  • 语法:
    • 返回值类型 operator==(参数列表);
class Test {
public:Test() {_a = (int*)malloc(10 * sizeof(int));b = 20;}~Test() {free(_a);_a = nullptr;}Test(const Test& t) {_a = (int*)malloc(10 * sizeof(int));for (int i = 0; i < 10; ++i) {_a[i] = t._a[i];}}// 赋值运算符重载Test& operator=(const Test& t) {for (int i = 0; i < 10; ++i) {_a[i] = t._a[i]; // 深拷贝}return *this;}
private:int* _a;int b;
};

值得注意的是,我们常常看到这样的代码Test t2 = t1。这里虽然使用了=,但并不是赋值运算符重载,赋值运算符重载的定义是已实例化的对象被赋值,这上面代码是还没有实例化对象,所以是拷贝构造。

拷贝构造调试验证

初始化列表

实例化对象时,编译器会通过构造函数来给成员变量一个初始值,这种行为只能称为赋值,并不能称为初始化,因为初始化只有一次,而构造函数中可以多次赋值。

  • 语法:
    • :开始,用,分割数据成员列表,每个成员变量后面跟初始值(初始值)

初始化列表

初始化顺序

class Test {
public:Test(): _b(6), _a(_b) {}void print() {std::cout << _a << " " << _b << std::endl;}private:int _a;int _b;
};int main() {Test t;t.print();return 0;
}

如上述代码,按照初始化列表顺序初始化,则应是a = b = 6这个结果。

初始化列表初始化顺序

而真实的结果是_a是随机值,_b是预期值6

可得出结论: 成员变量的初始化顺序和初始化列表顺序无关,和声明顺序有关。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/25817.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

对猫毛过敏?怎么有效的缓解过敏症状,宠物空气净化器有用吗?

猫过敏是一种常见的过敏反应&#xff0c;由猫的皮屑、唾液或尿液中的蛋白质引起。这些蛋白质被称为过敏原&#xff0c;它们可以通过空气传播&#xff0c;被人体吸入后&#xff0c;会触发免疫系统的过度反应。猫过敏是宠物过敏中最常见的类型之一&#xff0c;对许多人来说&#…

xilinx的Aurora8B10B的IP仿真及上板测试(高速收发器十七)

前文讲解了Aurora8B10B协议原理及xilinx相关IP&#xff0c;本文讲解如何设置该IP&#xff0c;并且通过示例工程完成该IP的仿真和上板。 1、生成Aurora8B10B IP 如下图所示&#xff0c;首先在vivado的IP catalog中输入Aurora 8B10B&#xff0c;双击该IP。 图1 查找Aurora 8B10…

基于STM32开发的智能农业监控系统

目录 引言环境准备智能农业监控系统基础代码实现&#xff1a;实现智能农业监控系统 4.1 土壤湿度传感器数据读取4.2 温湿度传感器数据读取4.3 水泵与风扇控制4.4 用户界面与数据可视化应用场景&#xff1a;农业环境监测与管理问题解决方案与优化收尾与总结 1. 引言 随着智能…

Map深度学习

Map Map是一个键值对的集合&#xff0c;和object类似&#xff0c;Map作为构造函数&#xff0c;可以通过全局对象获取到。需要通过new操作创建实例对象&#xff0c;直接调用会报错。Map构造函数接受一个iterable类型的函数&#xff0c;用来初始化Map。 var m new Map([[1, &qu…

央视频官方出品,AI高考智友助你成就高考梦想

大家好&#xff0c;我是小麦。今天分享一款由央视频官方出品的AI工具套件&#xff0c;不仅支持直接使用&#xff0c;同时还具备了开发能力&#xff0c;是一款非常不错的AI产品工具&#xff0c;该软件的名称叫做扣子。 扣子是新一代 AI 应用开发平台。无论你是否有编程基础&…

4000亿薪酬被驳回!马斯克再次讨薪

特斯拉CEO埃隆马斯克的一笔巨额财产&#xff0c;将在数日后的特斯拉股东大会上&#xff0c;由股东投票决定何去何从。 事情是这样的。 3.5研究测试&#xff1a;hujiaoai.cn 4研究测试&#xff1a;askmanyai.cn Claude-3研究测试&#xff1a;hiclaude3.com 2018年&#xff0c;特…

linux的持续性学习

安装php 第一步&#xff1a;配置yum源 第二步&#xff1a;下载php。 yum install php php-gd php-fpm php-mysql -y 第三步&#xff1a;启动php。 systemctl start php-fpm 第四步&#xff1a;检查php是否启动 lsof -i :9000 计划任务 作用&am…

智能水位监测识别报警摄像机:保障水域安全的重要利器

随着城市化进程的加速和气候变化的影响&#xff0c;对水域安全的关注日益增加。为了及时监测水位变化并采取相应措施&#xff0c;智能水位监测识别报警摄像机应运而生。本文将介绍这一创新技术的应用和优势。 传统的水位监测方法通常依赖于传感器&#xff0c;但其存在着安装位置…

java+Vue +Spring boot技术开发的UWB高精度定位技术系统源码 uwb定位系统+基站定位

javaVue Spring boot技术开发的UWB高精度定位技术系统源码 uwb定位系统基站定位 系统采用UWB高精度定位技术&#xff0c;可实现厘米级别定位。UWB作为一种高速率、低功耗、高容量的新兴无线局域定位技术&#xff0c;目前应用主要聚焦在室内高精确定位&#xff0c;例如在工业自动…

MySQL限制登陆失败次数配置

目录 一、限制登陆策略 1、Windows 2、Linux 一、限制登陆策略 1、Windows 1&#xff09;安装插件 登录MySQL数据库 mysql -u root -p 执行命令安装插件 #限制登陆失败次数插件 install plugin CONNECTION_CONTROL soname connection_control.dll;install plugin CO…

【已解决】FileNotFoundError: [Errno 3] No such file or directory: ‘xxx‘

&#x1f60e; 作者介绍&#xff1a;我是程序员行者孙&#xff0c;一个热爱分享技术的制能工人。计算机本硕&#xff0c;人工制能研究生。公众号&#xff1a;AI Sun&#xff0c;视频号&#xff1a;AI-行者Sun &#x1f388; 本文专栏&#xff1a;本文收录于《AI实战中的各种bug…

理财-商业保险

目录&#xff1a; 一、保险查询 1、金事通APP 2、商业保险APP 二、平安寿险 1、智能星 2、智富人生A 3、总结 三、保险中的掩藏项 一、保险查询 1、金事通APP 中国银行保险信息技术管理有限公司发挥金融基础设施作用&#xff0c;以“切实让数据多跑路、百姓少跑腿”为…

④-2单细胞学习-cellchat单数据代码补充版(通讯网络)

目录 通讯网络系统分析 ①社会网络分析 1&#xff0c;计算每个细胞群的网络中心性指标 2&#xff0c;识别细胞的信号流模式 ②非负矩阵分解&#xff08;NMF&#xff09;识别细胞的通讯模式 1&#xff0c;信号输出细胞的模式识别 2&#xff0c;信号输入细胞的模式识别 信…

codeforce round951 div2

A guess the maximum 问题&#xff1a; 翻译一下就是求所有相邻元素中max - 1的最小值 代码&#xff1a; #include <iostream> #include <algorithm>using namespace std;const int N 5e4;int a[N]; int n;void solve() {cin >> n;int ans 0x3f3f3f3f;…

基础数据结构 -- 堆

1. 简介 堆可以看做是一种特殊的完全二叉树&#xff0c;它满足任意节点的值都大于或小于其子节点的值。 2. 功能 插入元素&#xff1a;插入新元素时&#xff0c;先将元素放至数组末尾&#xff0c;然后通过上浮算法自底向上调整&#xff0c;使堆保持性质。删除堆顶元素&#xff…

Node安装配置

一、下载 Node官网下载地址&#xff1a;https://nodejs.org/en/ 二、安装 双击上面的msi扩展安装包开始安装&#xff0c;基本一路Next就行了 推荐安装目录自定义&#xff0c;最好不要放在C盘 检查安装是否成功 Win R 快捷键&#xff0c;输入 cmd 打开命令窗口输…

基于Java的超市进销存管理系统

开头语&#xff1a; 你好呀&#xff0c;我是计算机学长猫哥&#xff01;如果有相关需求&#xff0c;文末可以找到我的联系方式。 开发语言&#xff1a; Java 数据库&#xff1a; MySQL 技术&#xff1a; Java JSP Servlet JavaBean 工具&#xff1a; IDEA/Eclipse、…

Elasticsearch 管道查询语言 ES|QL 现已正式发布

作者&#xff1a;Costin Leau, George Kobar 今天&#xff0c;我们很高兴地宣布 ES|QL&#xff08;Elasticsearch 查询语言&#xff09;全面上市&#xff0c;这是一种从头开始设计的动态语言&#xff0c;用于转换、丰富和简化数据调查。在新的查询引擎的支持下&#xff0c;ES|Q…

大模型训练的艺术:从预训练到增强学习的四阶段之旅

文章目录 大模型训练的艺术&#xff1a;从预训练到增强学习的四阶段之旅1. 预训练阶段&#xff08;Pretraining&#xff09;2. 监督微调阶段&#xff08;Supervised Finetuning, SFT&#xff09;3. 奖励模型训练阶段&#xff08;Reward Modeling&#xff09;4. 增强学习微调阶段…

2- 简易版-日记写作软件(java)-涉及的技术点简述

环境&#xff1a; Ubuntu LinuxJDK1.8Eclipse 项目文件结构&#xff1a; 0. 涉及的技术点 1)view 包&#xff08;GUI&#xff09;&#xff1a; Eclipse SwingEclipse WindowBuilderJFileChooser(用于弹出文件选择对话框&#xff0c;进行文件或目录的选择)FileNameExtension…