当前位置: 首页 > 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…...

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…...

ES6从入门到精通:前言

ES6简介 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript语言的重大更新&#xff0c;引入了许多新特性&#xff0c;包括语法糖、新数据类型、模块化支持等&#xff0c;显著提升了开发效率和代码可维护性。 核心知识点概览 变量声明 let 和 const 取代 var&#xf…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

SAP学习笔记 - 开发26 - 前端Fiori开发 OData V2 和 V4 的差异 (Deepseek整理)

上一章用到了V2 的概念&#xff0c;其实 Fiori当中还有 V4&#xff0c;咱们这一章来总结一下 V2 和 V4。 SAP学习笔记 - 开发25 - 前端Fiori开发 Remote OData Service(使用远端Odata服务)&#xff0c;代理中间件&#xff08;ui5-middleware-simpleproxy&#xff09;-CSDN博客…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!

简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求&#xff0c;并检查收到的响应。它以以下模式之一…...

算法岗面试经验分享-大模型篇

文章目录 A 基础语言模型A.1 TransformerA.2 Bert B 大语言模型结构B.1 GPTB.2 LLamaB.3 ChatGLMB.4 Qwen C 大语言模型微调C.1 Fine-tuningC.2 Adapter-tuningC.3 Prefix-tuningC.4 P-tuningC.5 LoRA A 基础语言模型 A.1 Transformer &#xff08;1&#xff09;资源 论文&a…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

【C++进阶篇】智能指针

C内存管理终极指南&#xff1a;智能指针从入门到源码剖析 一. 智能指针1.1 auto_ptr1.2 unique_ptr1.3 shared_ptr1.4 make_shared 二. 原理三. shared_ptr循环引用问题三. 线程安全问题四. 内存泄漏4.1 什么是内存泄漏4.2 危害4.3 避免内存泄漏 五. 最后 一. 智能指针 智能指…...

苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会

在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...

在 Spring Boot 中使用 JSP

jsp&#xff1f; 好多年没用了。重新整一下 还费了点时间&#xff0c;记录一下。 项目结构&#xff1a; pom: <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0" xmlns:xsi"http://ww…...