当前位置: 首页 > news >正文

C++学习:类和对象(二)

一、默认成员函数

1. 什么是默认成员函数?

在C++中,每个类都有一些特殊的成员函数,如果程序员没有显式地声明,编译器会自动为类生成这些函数,这些函数称为默认成员函数

2. 默认成员函数列表

  • 默认构造函数(Default Constructor)
  • 默认析构函数(Destructor)
  • 默认拷贝构造函数(Copy Constructor)
  • 默认拷贝赋值运算符(Copy Assignment Operator)
  • 默认移动构造函数(Move Constructor,C++11引入)
  • 默认移动赋值运算符(Move Assignment Operator,C++11引入)

3. 编译器何时生成默认成员函数?

  • 显式声明:如果程序员没有提供某个默认成员函数的定义,编译器会根据需要自动生成
  • 特别注意:一旦程序员显式地声明了任何一个拷贝或移动操作,编译器将不会为该类生成移动操作,需要手动提供

4. 代码示例

#include <iostream>
using namespace std;class Example {
public:int value;// 未显式声明任何默认成员函数
};int main() {Example ex1;       // 调用默认构造函数ex1.value = 10;Example ex2 = ex1; // 调用默认拷贝构造函数Example ex3;ex3 = ex1;         // 调用默认拷贝赋值运算符cout << "ex1.value = " << ex1.value << endl;cout << "ex2.value = " << ex2.value << endl;cout << "ex3.value = " << ex3.value << endl;return 0;
}

二、构造函数

1. 什么是构造函数?

构造函数(Constructor)是在创建对象时自动调用的特殊成员函数,用于初始化对象的成员变量。构造函数的名称与类名相同

2. 特点

  • 没有返回类型(连void也没有)
  • 可以有参数(参数化构造函数)
  • 支持函数重载,即可以有多个构造函数
  • 可以在构造函数初始化列表中初始化成员变量

3. 默认构造函数

如果程序员未提供任何构造函数,编译器会为类生成一个默认构造函数,它对基本类型成员变量不进行初始化

4. 代码示例:

1.默认构造函数

#include <iostream>
using namespace std;class Person {
public:string name;int age;// 默认构造函数Person() {name = "Unknown";age = 0;}void display() const {cout << "姓名:" << name << ", 年龄:" << age << endl;}
};int main() {Person p; // 调用默认构造函数p.display();return 0;
}

2.参数化构造函数

#include <iostream>
using namespace std;class Person {
public:string name;int age;// 参数化构造函数Person(const string& n, int a) {name = n;age = a;}void display() const {cout << "姓名:" << name << ", 年龄:" << age << endl;}
};int main() {Person p("Alice", 25); // 调用参数化构造函数p.display();return 0;
}

 3.构造函数初始化列表

#include <iostream>
using namespace std;class Point {
private:int x;int y;public:// 使用初始化列表初始化成员变量Point(int xCoord, int yCoord) : x(xCoord), y(yCoord) {}void display() const {cout << "坐标:(" << x << ", " << y << ")" << endl;}
};int main() {Point pt(3, 4);pt.display();return 0;
}

5. 注意事项

  • 如果类中有const成员变量或引用类型成员,必须使用初始化列表进行初始化
  • 构造函数可以被重载,允许创建多个具有不同参数列表的构造函数

三、析构函数

1. 什么是析构函数?

析构函数(Destructor)是在对象生命周期结束时自动调用的特殊成员函数,用于释放对象占用的资源(如内存、文件等)。析构函数的名称是在类名前加上~符号

2. 特点

  • 没有参数
  • 没有返回类型
  • 每个类只有一个析构函数,不能重载
  • 编译器会自动调用析构函数,无需手动调用

3. 代码示例

#include <iostream>
using namespace std;class Resource {
public:Resource() {cout << "资源已分配。" << endl;}~Resource() {cout << "资源已释放。" << endl;}
};int main() {cout << "进入main函数。" << endl;{Resource res; // 创建对象,调用构造函数} // 离开作用域,调用析构函数cout << "退出main函数。" << endl;return 0;
}

4. 在析构函数中释放资源

当类中使用了动态内存分配(如使用new关键字),需要在析构函数中释放内存,防止内存泄漏

#include <iostream>
using namespace std;class Array {
private:int* data;int size;public:Array(int s) : size(s) {data = new int[size];cout << "数组已分配。" << endl;}~Array() {delete[] data;cout << "数组已释放。" << endl;}
};int main() {Array arr(10);// 使用数组...return 0;
}

5. 注意事项

  • 析构函数必须为公有成员函数,否则对象在离开作用域时无法正确销毁
  • 避免在析构函数中抛出异常,这可能导致程序不可预测的行为

四、拷贝构造函数

1. 什么是拷贝构造函数?

拷贝构造函数(Copy Constructor)是使用同类的另一个对象来初始化新对象时调用的构造函数。它用于定义对象的拷贝行为

2. 语法

ClassName(const ClassName& other);

参数为同类对象的引用,通常为const引用,避免不必要的拷贝

3. 默认拷贝构造函数

  • 如果程序员未提供拷贝构造函数,编译器会自动生成默认的拷贝构造函数,执行浅拷贝
  • 对于没有动态内存分配的类,默认的拷贝构造函数通常够用

4. 浅拷贝与深拷贝

  • 浅拷贝(Shallow Copy):拷贝对象的成员变量值,对于指针成员,仅拷贝指针值,两个对象指向同一内存位置
  • 深拷贝(Deep Copy):在拷贝指针成员时,为新对象分配独立的内存空间,并复制内容

5. 示例

1.默认拷贝构造函数(浅拷贝)

#include <iostream>
using namespace std;class Shallow {
public:int* data;Shallow(int val) {data = new int(val);}~Shallow() {delete data;}
};int main() {Shallow obj1(5);Shallow obj2 = obj1; // 调用默认拷贝构造函数cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;// 修改obj1的数据*(obj1.data) = 10;cout << "修改obj1后:" << endl;cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;return 0;
}

问题:

由于是浅拷贝,obj1obj2data指向同一内存,当一个对象被析构时,内存被释放,另一个对象再使用时会导致悬空指针

2.自定义拷贝构造函数(深拷贝)

#include <iostream>
using namespace std;class Deep {
public:int* data;Deep(int val) {data = new int(val);}// 自定义拷贝构造函数Deep(const Deep& other) {data = new int(*(other.data));}~Deep() {delete data;}
};int main() {Deep obj1(5);Deep obj2 = obj1; // 调用自定义拷贝构造函数cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;// 修改obj1的数据*(obj1.data) = 10;cout << "修改obj1后:" << endl;cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;return 0;
}

6. 注意事项

  • 拷贝构造函数的参数必须是引用,否则会导致无限递归
  • 当类中有指针成员,且需要独立的内存空间,必须提供自定义的拷贝构造函数(深拷贝)

五、赋值运算符函数

1. 什么是赋值运算符函数?

赋值运算符函数(Assignment Operator Function)用于定义对象间赋值行为(operator=)。类似于拷贝构造函数,它也需要考虑浅拷贝和深拷贝

2. 语法

ClassName& operator=(const ClassName& other);
  • 返回类型为引用,返回当前对象自身*this,以支持链式赋值
  • 参数为同类对象的**const引用**

3. 默认赋值运算符

  • 如果程序员未提供赋值运算符函数,编译器会生成默认的赋值运算符,执行浅拷贝

4. 示例

1.默认赋值运算符(浅拷贝)

#include <iostream>
using namespace std;class Shallow {
public:int* data;Shallow(int val) {data = new int(val);}~Shallow() {delete data;}
};int main() {Shallow obj1(5);Shallow obj2(10);obj2 = obj1; // 使用默认赋值运算符cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;// 修改obj1的数据*(obj1.data) = 15;cout << "修改obj1后:" << endl;cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;return 0;
}

2.自定义赋值运算符函数(深拷贝)

#include <iostream>
using namespace std;class Deep {
public:int* data;Deep(int val) {data = new int(val);}Deep(const Deep& other) {data = new int(*(other.data));}// 自定义赋值运算符函数Deep& operator=(const Deep& other) {if (this == &other) {return *this; // 检查自赋值}delete data; // 释放原有内存data = new int(*(other.data)); // 分配新内存并拷贝return *this;}~Deep() {delete data;}
};int main() {Deep obj1(5);Deep obj2(10);obj2 = obj1; // 使用自定义赋值运算符cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;// 修改obj1的数据*(obj1.data) = 15;cout << "修改obj1后:" << endl;cout << "obj1.data = " << *(obj1.data) << endl;cout << "obj2.data = " << *(obj2.data) << endl;return 0;
}

5. 注意事项

  • 检查自赋值:在赋值运算符函数中,应检查thisother是否为同一对象,避免释放自己
  • 释放原有资源:在进行赋值前,应释放对象原有的资源,防止内存泄漏
  • 返回*this的引用,支持链式赋值

六、const成员函数

1. 什么是const成员函数?

const成员函数是指在函数声明后加上const关键字的成员函数,表示该函数不会修改对象的成员变量(除非成员变量被声明为mutable

2. 语法

返回类型 函数名(参数列表) const;

3. 特点

  • const成员函数只能调用其他const成员函数,不能调用非const成员函数
  • 可以被const对象调用,而非const成员函数不能被const对象调用

4. 代码示例

#include <iostream>
using namespace std;class Sample {
private:int value;public:Sample(int v) : value(v) {}int getValue() const {return value;}void setValue(int v) {value = v;}
};int main() {const Sample s(10); // 常量对象cout << "值是:" << s.getValue() << endl;// s.setValue(20); // 错误,不能调用非const成员函数return 0;
}

5. const对象和成员函数

  • **const对象:**对象被声明为const,只能调用其const成员函数,不能修改成员变量
  • **非const对象:**可以调用所有成员函数,包括const和非const

6. 成员函数重载

可以根据const性对成员函数进行重载
代码示例:

#include <iostream>
using namespace std;class Example {
public:void func() {cout << "非const版本的func()" << endl;}void func() const {cout << "const版本的func()" << endl;}
};int main() {Example e;e.func(); // 调用非const版本const Example ce;ce.func(); // 调用const版本return 0;
}

七、取地址及const取地址操作符重载

1. 取地址操作符operator&

默认情况下,对象的取地址操作会返回对象的内存地址。可以通过重载operator&来改变取地址操作的行为

2. 为什么需要重载取地址操作符?

  • 在某些情况下,我们希望隐藏对象的内部地址,或提供特殊的地址计算方式
  • 可以用于智能指针的实现

3. 语法

ClassName* operator&();
const ClassName* operator&() const;

4. 示例

1.重载取地址操作符

#include <iostream>
using namespace std;class MyClass {
public:int value;MyClass(int v) : value(v) {}// 重载取地址操作符MyClass* operator&() {cout << "自定义取地址操作符被调用。" << endl;return this;}// 重载const版本const MyClass* operator&() const {cout << "自定义const取地址操作符被调用。" << endl;return this;}
};int main() {MyClass obj(10);MyClass* ptr = &obj; // 调用自定义取地址操作符cout << "value = " << ptr->value << endl;const MyClass cobj(20);const MyClass* cptr = &cobj; // 调用自定义const取地址操作符cout << "const value = " << cptr->value << endl;return 0;
}

5. 注意事项

  • 小心使用:重载取地址操作符可能导致代码难以理解和维护,应该谨慎使用
  • 避免陷阱:重载后,可能会影响模板代码或标准库的使用,需要确保兼容性

相关文章:

C++学习:类和对象(二)

一、默认成员函数 1. 什么是默认成员函数&#xff1f; 在C中&#xff0c;每个类都有一些特殊的成员函数&#xff0c;如果程序员没有显式地声明&#xff0c;编译器会自动为类生成这些函数&#xff0c;这些函数称为默认成员函数 2. 默认成员函数列表 默认构造函数&#xff08…...

深度学习(五):语音处理领域的创新引擎(5/10)

一、深度学习在语音处理中的崛起 在语音处理领域&#xff0c;传统方法如谱减法、维纳滤波等在处理复杂语音信号时存在诸多局限性。这些方法通常假设噪声是平稳的&#xff0c;但实际噪声往往是非平稳的&#xff0c;导致噪声估计不准确。同时&#xff0c;为了去除噪声&#xff0…...

双曲函数(Hyperbolic functuons)公式

在python等语言里有双曲函数库和反双曲函数库&#xff0c;但是并没有包含所有的双曲函数。以numpy为例子&#xff0c;numpy只提供了sinh、cosh、tanh、arcsinh、arccosh、arctanh六种函数&#xff0c;那么其余的就需要用公式计算了。 转换公式 对于函数库不能直接计算的&#…...

【CSS/SCSS】@layer的介绍及使用方法

目录 基本用法layer 的作用与优点分离样式职责&#xff0c;增强代码可读性和可维护性防止无意的样式冲突精确控制样式的逐层覆盖提高复用性 兼容性实际示例&#xff1a;使用 import 管理加载顺序实际示例&#xff1a;混入与 layer 结合使用 layer 是 CSS 中用于组织和管理样式优…...

我为什么投身于青少年AI编程?——打造生态圈(三)

第五部分 青少年AI编程生态圈 一、生态圈 主要涵盖家庭、社区/中小学、高校高职、主管部门。 1、家庭 我们与社区/中小学一道打造让家长满意的模式。 教得好&#xff1a; 费用少&#xff1a; 家门口&#xff1a; 2、社区/中小学 社区党群服务中心和中小学都有大面积科普…...

出海要深潜,中国手机闯关全球化有了新标杆

经济全球化的大势之下&#xff0c;中国科技企业开拓海外市场已成为一种必然选择。 对于国内手机企业来说&#xff0c;推进全球商业版图扩张&#xff0c;业务潜力巨大&#xff0c;海外市场是今后的关键增长引擎。 当前中国手机厂商在海外市场的发展&#xff0c;有收获也有坎坷…...

百度SEO中的关键词密度与内容优化研究【百度SEO专家】

大家好&#xff0c;我是百度SEO专家&#xff08;林汉文&#xff09;&#xff0c;在百度SEO优化中&#xff0c;关键词密度和关键词内容的优化对提升页面排名至关重要。关键词的合理布局与内容的质量是确保网页在百度搜索结果中脱颖而出的关键因素。下面我们将从关键词密度和关键…...

如何用fastapi集成pdf.js 的viewer.html ,并支持 mjs

fastapi 框架 集成pdf.js 的 viewer.html?file=***,支持跨域,支持.mjs .wasm .pdf 给出完整示例代码 要在 FastAPI 框架中集成 pdf.js 的 viewer.html,并支持跨域访问以及 .mjs、.wasm、.pdf 文件的正确加载,可以按照以下步骤进行。下面提供一个完整的示例,包括项目结构…...

文件相对路径与绝对路径

前言&#xff1a; 在写代码绘制图像的过程中&#xff0c;发现出现cant read input file的异常&#xff0c;而且输出框没有绘制图片&#xff0c;所以寻找解决方案。先贴上之前写的简洁版绘制图像代码 1.BackGround类 import java.awt.image.BufferedImage;public class BackG…...

Linux 重启命令全解析:深入理解与应用指南

Linux 重启命令全解析&#xff1a;深入理解与应用指南 在 Linux 系统中&#xff0c;掌握正确的重启命令是确保系统稳定运行和进行必要维护的关键技能。本文将深入解析 Linux 中常见的重启命令&#xff0c;包括功能、用法、适用场景及注意事项。 一、reboot 命令 功能简介 re…...

【北京迅为】《STM32MP157开发板嵌入式开发指南》-第六十七章 Trusted Firmware-A 移植

iTOP-STM32MP157开发板采用ST推出的双核cortex-A7单核cortex-M4异构处理器&#xff0c;既可用Linux、又可以用于STM32单片机开发。开发板采用核心板底板结构&#xff0c;主频650M、1G内存、8G存储&#xff0c;核心板采用工业级板对板连接器&#xff0c;高可靠&#xff0c;牢固耐…...

`a = a + b` 与 `a += b` 的区别

在 Java 中&#xff0c;a a b 和 a b 都用于将 b 的值加到 a 上&#xff0c;但它们之间存在一些重要的区别&#xff0c;尤其是在类型转换和操作行为方面。 使用 操作符时&#xff0c;Java 会自动进行隐式类型转换&#xff0c;而使用 则不会。这意味着在 a b 的情况下&am…...

mysqld.log文件过大,清理后不改变所属用户

#1024程序员节# 一、背景 突然有一天&#xff0c;我的mysql报磁盘不足了。仔细查看才发现&#xff0c;是磁盘满了。而MySQL的日志文件占用了91个G.如下所示&#xff1a; [roothost-172-16-14-128 mysql]# ls -lrth 总用量 93G -rw-r----- 1 mysql mysql 1.1G 7月 30 2023 m…...

v4.7+版本用户充值在交易统计中计算双倍的问题修复

app/services/statistic/TradeStatisticServices.php 文件中 $whereInRecharge[recharge_type] no_system; $whereInRecharge[recharge_type] system; app/model/user/UserRecharge.php 中 修改此搜索器内容 public function searchRechargeTypeAttr($query, $value){ if…...

[GXYCTF 2019]Ping Ping Ping 题解(多种解题方式)

知识点: 命令执行 linux空格绕过 反引号绕过 变量绕过 base64编码绕过 打开页面提示 "听说php可以执行系统函数&#xff1f;我来康康" 然后输入框内提示输入 bjut.edu.cn 输入之后回显信息,是ping 这个网址的信息 输入127.0.0.1 因为提示是命令…...

MODSI EVI 数据的时间序列拟合一阶谐波模型

目录 简介 函数 ee.Reducer.linearRegression(numX, numY) Arguments: Returns: Reducer ee.Image.cat(var_args) Arguments: Returns: Image hsvToRgb() Arguments: Returns: Image 代码 结果 简介 MODIS/006/MOD13A1数据是由美国国家航空航天局(NASA)的MODIS…...

Java:String类(超详解!)

一.常用方法 &#x1f94f;1.字符串构造 字符串构造有三种方法&#xff1a; &#x1f4cc;注意&#xff1a; 1. String是引用类型&#xff0c;内部并不存储字符串本身 如果String是一个引用那么s1和s3应该指向同一个内容&#xff0c;s1和s2是相等的&#xff0c;应该输出两…...

【日志】力扣13.罗马数字转整数 || 解决泛型单例热加载失败问题

2024.10.28 【力扣刷题】 13. 罗马数字转整数 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/roman-to-integer/description/?envTypestudy-plan-v2&envIdtop-interview-150这题用模拟的思想可以给相应的字母赋值&#xff0c;官方的答案用的是用一…...

Mybatis高级

系列文章目录 高级Mybatis&#xff0c;一些结果映射&#xff0c;引入新的注解 目录 系列文章目录 文章目录 一、结果映射 1.ResultType 2.ResultMap 基础应用&#xff1a; 二、一对一 嵌套结果和嵌套查询 嵌套结果 嵌套查询 区别 三、一对多 四、多对多 五、注解补充 1.一对一…...

【spark】spark structrued streaming读写kafka 使用kerberos认证

spark版本:2.4.0 官网 Spark --files使用总结 Spark --files理解 一、编写jar import org.apache.kafka.clients.CommonClientConfigs import org.apache.kafka.common.config.SaslConfigs import org.apache.spark.sql.SparkSession import org.apache.spark.sql.streaming.T…...

网络编程(Modbus进阶)

思维导图 Modbus RTU&#xff08;先学一点理论&#xff09; 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议&#xff0c;由 Modicon 公司&#xff08;现施耐德电气&#xff09;于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…...

第19节 Node.js Express 框架

Express 是一个为Node.js设计的web开发框架&#xff0c;它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用&#xff0c;和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...

进程地址空间(比特课总结)

一、进程地址空间 1. 环境变量 1 &#xff09;⽤户级环境变量与系统级环境变量 全局属性&#xff1a;环境变量具有全局属性&#xff0c;会被⼦进程继承。例如当bash启动⼦进程时&#xff0c;环 境变量会⾃动传递给⼦进程。 本地变量限制&#xff1a;本地变量只在当前进程(ba…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

Java 8 Stream API 入门到实践详解

一、告别 for 循环&#xff01; 传统痛点&#xff1a; Java 8 之前&#xff0c;集合操作离不开冗长的 for 循环和匿名类。例如&#xff0c;过滤列表中的偶数&#xff1a; List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

中南大学无人机智能体的全面评估!BEDI:用于评估无人机上具身智能体的综合性基准测试

作者&#xff1a;Mingning Guo, Mengwei Wu, Jiarun He, Shaoxian Li, Haifeng Li, Chao Tao单位&#xff1a;中南大学地球科学与信息物理学院论文标题&#xff1a;BEDI: A Comprehensive Benchmark for Evaluating Embodied Agents on UAVs论文链接&#xff1a;https://arxiv.…...

《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)

CSI-2 协议详细解析 (一&#xff09; 1. CSI-2层定义&#xff08;CSI-2 Layer Definitions&#xff09; 分层结构 &#xff1a;CSI-2协议分为6层&#xff1a; 物理层&#xff08;PHY Layer&#xff09; &#xff1a; 定义电气特性、时钟机制和传输介质&#xff08;导线&#…...

将对透视变换后的图像使用Otsu进行阈值化,来分离黑色和白色像素。这句话中的Otsu是什么意思?

Otsu 是一种自动阈值化方法&#xff0c;用于将图像分割为前景和背景。它通过最小化图像的类内方差或等价地最大化类间方差来选择最佳阈值。这种方法特别适用于图像的二值化处理&#xff0c;能够自动确定一个阈值&#xff0c;将图像中的像素分为黑色和白色两类。 Otsu 方法的原…...

Rust 异步编程

Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...

C# SqlSugar:依赖注入与仓储模式实践

C# SqlSugar&#xff1a;依赖注入与仓储模式实践 在 C# 的应用开发中&#xff0c;数据库操作是必不可少的环节。为了让数据访问层更加简洁、高效且易于维护&#xff0c;许多开发者会选择成熟的 ORM&#xff08;对象关系映射&#xff09;框架&#xff0c;SqlSugar 就是其中备受…...