C++--类与对象(二)

类的六个成员函数

如果一个类中什么成员都没有,简称为空类。
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员
函数。
默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。
class Date {}; //空类

构造函数

构造函数是一种特殊的成员函数,在C++中用于初始化对象的数据成员。当创建一个类的对象时,构造函数会自动调用,用于确保对象被正确初始化。构造函数的主要作用是为对象提供合适的初始状态,使其能够正常工作。

构造函数的概念可以总结为以下几点:

  1. 初始化对象:构造函数负责为对象的数据成员赋予合适的初始值,确保对象处于一个有效的状态。

  2. 与类同名:构造函数的名称与类名相同,因此可以用来标识对象的类型。

  3. 没有返回类型:与普通函数不同,构造函数没有返回类型,包括 void。因为它们的作用是初始化对象,而不是返回值。

  4. 自动调用:构造函数在对象创建时自动调用,无需手动调用。当对象被声明时,构造函数会立即执行。

  5. 可以有多个重载:同一个类可以有多个构造函数,它们可以根据参数的不同进行重载。这样可以提供多种不同的初始化方式。

  6. 可以带默认参数:构造函数可以像普通函数一样拥有默认参数,从而提供更灵活的对象初始化方式。

构造函数在类的设计中非常重要,它决定了对象在创建时的初始状态,为后续的操作提供了基础。

#include <iostream>
using namespace std;
class Date
{
public:
	void Print()
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1; // 编译器将调用自动生成的默认构造函数对d1进行初始化
	d1.Print();
	return 0;
}

这段代码定义了一个简单的日期类 Date,其中包含了三个私有数据成员 _year_month_day,以及一个公有成员函数 Print() 用于输出日期信息。

main() 函数中,创建了一个 Date 类型的对象 d1,由于没有显式地定义构造函数,编译器会自动生成一个默认构造函数。默认构造函数会对对象的数据成员进行默认初始化,对于基本数据类型,如 int,默认初始化会使其值未定义,即可能是随机值。然后调用对象的 Print() 函数输出日期信息。

这段代码的运行结果可能是这样的(由于 _year_month_day 的值未定义,输出的结果会有所不同)

虽然在我们不写的情况下,编译器会自动生成构造函数,但是编译器自动生成的构造函数可能达不到我们想要的效果,所以大多数情况下都需要我们自己写构造函数。

析构函数

析构函数是一种特殊的成员函数,在C++中用于释放对象占用的资源,并在对象生命周期结束时自动调用。它的作用与构造函数相反,用于清理对象在生命周期中分配的资源,以防止资源泄漏和内存泄漏。

析构函数的概念可以总结为以下几点:

  1. 释放资源:析构函数负责释放对象占用的资源,包括动态分配的内存、打开的文件、建立的网络连接等。它确保在对象被销毁之前,所有分配的资源都被正确释放,以避免资源泄漏。

  2. 与类同名:析构函数的名称由波浪号(~)后跟类名构成,与构造函数相似,但前面有一个波浪号。

  3. 没有参数:析构函数不接受任何参数,也没有返回类型,包括 void。它只负责清理对象的资源,不返回任何值。

  4. 自动调用:析构函数在对象生命周期结束时自动调用,无需手动调用。当对象离开其作用域、被删除或程序结束时,析构函数会自动执行。

  5. 只有一个:每个类只能有一个析构函数,不允许重载。如果没有显式地定义析构函数,编译器会自动生成一个默认的析构函数。

析构函数在类的设计中非常重要,它确保对象在销毁时资源被正确释放,避免内存泄漏和资源泄漏问题。

class Date
{
public:
	Date()// 构造函数
	{}
	~Date()// 析构函数
	{}
private:
	int _year;
	int _month;
	int _day;
};
  • 析构函数 ~Date():这是一个析构函数,用于在对象被销毁时释放资源。在这个示例中,析构函数也是一个空函数,没有实际的清理工作。因为在这个简单的示例中,Date 类并没有分配动态资源,所以不需要显式地释放资源。然而,通常情况下,析构函数会负责释放类对象可能持有的资源,如动态分配的内存、打开的文件句柄等。

 拷贝构造函数

拷贝构造函数是一种特殊的成员函数,在C++中用于通过复制已存在对象的数据创建新对象。当一个对象被传递给函数参数、以值传递方式返回或者通过赋值操作符进行对象赋值时,拷贝构造函数会被调用。

拷贝构造函数的概念可以总结为以下几点:

  1. 复制对象:拷贝构造函数的主要作用是创建一个新对象,并将已存在对象的数据成员复制到新对象中。这样可以在不修改原始对象的情况下创建一个相同状态的新对象。

  2. 参数为同类对象的引用:拷贝构造函数的参数通常是对同类对象的引用,表示要复制的对象。

  3. 对象传递和赋值时调用:拷贝构造函数会在对象被传递给函数参数、以值传递方式返回或者通过赋值操作符进行对象赋值时自动调用。

  4. 默认浅拷贝:默认情况下,拷贝构造函数执行浅拷贝,即简单地将原始对象的数据成员复制到新对象中。如果类中存在指针成员等资源,可能需要手动编写拷贝构造函数来实现深拷贝,以防止资源重复释放或指针悬空等问题。

拷贝构造函数在类的设计中非常重要,它允许我们以简单、方便的方式创建对象的副本,并在对象传递和赋值过程中确保数据的正确复制。

#include <iostream>

class MyClass {
private:
    int _data;
public:
    // 构造函数
    MyClass(int data) : _data(data) {
        std::cout << "Constructor called for object with data: " << _data << std::endl;
    }

    // 拷贝构造函数
    MyClass(const MyClass& other) : _data(other._data) {
        std::cout << "Copy constructor called for object with data: " << _data << std::endl;
    }

    // 打印数据成员
    void printData() const {
        std::cout << "Data: " << _data << std::endl;
    }
};

int main() {
    // 创建一个对象并初始化
    MyClass obj1(10);
    std::cout << "Object 1: ";
    obj1.printData();

    // 使用拷贝构造函数创建一个新对象
    MyClass obj2 = obj1;
    std::cout << "Object 2: ";
    obj2.printData();

    return 0;
}

这个示例包含了以下特点:

  1. 构造函数:类 MyClass 包含一个构造函数,用于初始化对象的数据成员 _data

  2. 拷贝构造函数:类 MyClass 包含一个拷贝构造函数,用于通过复制已存在对象的数据创建新对象。

  3. 参数为同类对象的引用:拷贝构造函数的参数是对同类对象的引用,即 const MyClass& other

  4. 对象传递时调用:拷贝构造函数会在对象被传递给函数参数时自动调用。在 main() 函数中,我们使用 MyClass obj2 = obj1; 来复制 obj1,这时拷贝构造函数会被调用。

  5. 默认浅拷贝:拷贝构造函数默认执行浅拷贝,即简单地复制 _data 的值。

  6. 输出信息:在构造函数和拷贝构造函数中,我们打印了相应对象的数据成员 _data 的值。

运行结果

Constructor called for object with data: 10
Object 1: Data: 10
Copy constructor called for object with data: 10
Object 2: Data: 10

 赋值运算符重载

赋值运算符重载是一种特殊的成员函数,用于定义用户自定义类型对象的赋值操作行为。通过重载赋值运算符,可以实现自定义类型对象之间的赋值操作,使其行为类似于内置类型。

赋值运算符重载的概念可以总结为以下几点:

  1. 定义对象赋值行为:赋值运算符重载允许程序员重新定义对象之间的赋值操作。这样,可以通过赋值运算符将一个对象的值赋给另一个对象,从而实现自定义类型对象之间的赋值行为。

  2. 成员函数:赋值运算符重载是一个成员函数,它可以在类的内部进行定义。其名称由关键字 operator 后跟赋值操作符 = 构成。

  3. 返回类型为引用:赋值运算符重载通常返回对象的引用,以支持连续赋值操作。这样可以避免不必要的对象复制。

  4. 参数为同类对象的引用:赋值运算符重载的参数通常是对同类对象的引用。这样可以将右操作数的值复制到左操作数中。

  5. 自赋值检查:在实现赋值运算符重载时,通常需要检查是否为自赋值(即左操作数和右操作数指向同一个对象),以避免出现错误。

  6. 深拷贝:在进行赋值操作时,特别是对于包含动态分配资源的自定义类型,通常需要执行深拷贝,确保资源被正确释放和管理。

赋值运算符重载允许程序员自定义类型的赋值操作,使其更加灵活和符合实际需求。通过适当地重载赋值运算符,可以实现对象之间的赋值行为,从而提高代码的可读性和可维护性。

#include <iostream>
using namespace std;

class Date {
public:
    // 构造函数
    Date(int year = 0, int month = 1, int day = 1) {
        _year = year;
        _month = month;
        _day = day;
    }

    // 赋值运算符重载函数
    Date& operator=(const Date& d) {
        if (this != &d) {
            _year = d._year;
            _month = d._month;
            _day = d._day;
        }
        return *this;
    }

    // 打印函数
    void Print() {
        cout << _year << "年" << _month << "月" << _day << "日" << endl;
    }

private:
    int _year;
    int _month;
    int _day;
};

int main() {
    // 创建日期对象并打印
    Date d1(2024, 5, 8);
    cout << "Original date: ";
    d1.Print();

    // 使用赋值运算符重载将一个日期对象赋值给另一个日期对象
    Date d2;
    d2 = d1;

    // 打印赋值后的日期对象
    cout << "Assigned date: ";
    d2.Print();

    return 0;
}

 重载了赋值运算符 =,使得可以将一个 Date 对象的值赋给另一个 Date 对象。在函数中,我们首先进行自赋值检查,然后将右操作数对象的年、月和日分别赋值给左操作数对象。

const成员

onst修饰类的成员函数
 我们将const修饰的类成员函数称之为const成员函数,const修饰类成员函数,实际修饰的是类成员函数隐含的this指针,表明在该成员函数中不能对this指针指向的对象进行修改。 

例如,我们可以对类成员函数中的打印函数进行const修饰,避免在函数体内不小心修改了对象:

	void Print()const// cosnt修饰的打印函数
	{
		cout << _year << "年" << _month << "月" << _day << "日" << endl;
	}

思考下面几个问题(经典面试题):
1.const对象可以调用非const成员函数吗?
2.非const对象可以调用const成员函数吗?
3.const成员函数内可以调用其他的非const成员函数吗?
4.非cosnt成员函数内可以调用其他的cosnt成员函数吗?

答案是:不可以、可以、不可以、可以
解释如下:
 1.非const成员函数,即成员函数的this指针没有被const所修饰,我们传入一个被const修饰的对象,用没有被const修饰的this指针进行接收,属于权限的放大,函数调用失败。
 2.const成员函数,即成员函数的this指针被const所修饰,我们传入一个没有被const修饰的对象,用被const修饰的this指针进行接收,属于权限的缩小,函数调用成功。
 3.在一个被const所修饰的成员函数中调用其他没有被const所修饰的成员函数,也就是将一个被const修饰的this指针的值赋值给一个没有被const修饰的this指针,属于权限的放大,函数调用失败。
 4.在一个没有被const所修饰的成员函数中调用其他被const所修饰的成员函数,也就是将一个没有被const修饰的this指针的值赋值给一个被const修饰的this指针,属于权限的缩小,函数调用成功。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

pixhawk无人机飞控解锁

飞控解锁 GitBook 左手油门的遥控解锁是油门右下角拨&#xff0c;右手油门是油门最低&#xff0c;方向最右。 飞控如何加锁? 左手油门&#xff1a;油门左下角 右手油门&#xff1a;油门最低&#xff0c;方向最左 飞控解锁成功后&#xff0c;不推油门的情况下&#xff0c;…

2005-2022年各省居民人均可支配收入数据(含城镇居民人均可支配收入、农村居民人均可支配收入)(无缺失)

2005-2022年各省居民人均可支配收入数据&#xff08;含城镇居民人均可支配收入、农村居民人均可支配收入&#xff09;&#xff08;无缺失&#xff09; 1、时间&#xff1a;2005-2022年 2、来源&#xff1a;国家统计局、统计年鉴 3、指标&#xff1a;全体居民人均可支配收入、…

【GlobalMapper精品教程】080:WGS84转UTM投影

参考阅读:ArcGIS实验教程——实验十:矢量数据投影变换 文章目录 一、加载实验数据二、设置输出坐标系三、数据导出一、加载实验数据 打开配套案例数据包中的data080.rar中的矢量数据,如下所示: 查看源坐标系:双击图层的,图层投影选项卡,数据的已有坐标系为WGS84地理坐标…

WEB后端复习——Servlet

Servlet是运行在Web服务器或应用服务器上的java程序&#xff0c;它是一个中间层&#xff0c;负责连接来自web浏览器或其他HTTP客户程序和[HTTP服务器]上应用程序 Servlet执行下面的任务: 1&#xff09;读取客户发送的显示数据。 2&#xff09;读取由浏览器发送的隐式请求数据。…

(CVE-2012-1823)PHP-CGI远程代码执行漏洞(80端口)

&#xff08;CVE-2012-1823&#xff09;PHP-CGI远程代码执行漏洞&#xff08;80端口&#xff09; 一、介绍二、漏洞影响三、原理四、漏洞复现 一、介绍 php-cgi是一个类似于消息的“传递者”&#xff0c;它接收web容器收到的http数据包&#xff0c;并把里面的数据交给PHP解释器…

涉案财物管理系统|DW-S405系统全国都有案例

涉案财物管理系统&#xff08;智财物&#xff1a;DW-S404&#xff09;是一套成熟系统&#xff0c;依托互3D技术、云计算、大数据、RFID技术、数据库技术、AI、视频分析技术对涉密载体进行统一管理、分析的信息化、智能化、规范化的系统。 涉案财物管理系统主要实现对涉案物品进…

栈和队列OJ练习题及解答

前言 上一篇博客已经讲到了栈和队列的数据结构&#xff0c;概括一下&#xff1a;栈后进先出&#xff08;Last In First Out&#xff09;、队列先进先出&#xff08;First In First Out&#xff09;。那么&#xff0c;接下来就来讲讲&#xff0c;关于栈和队列的相关练习题&#…

维护祖传项目Tomcat部署war包

文章目录 1. 安装tomcat2. 解决Tomcat启动日志乱码3. idea配置启动war包 1. 安装tomcat 选择免安装版本&#xff0c;只需要在系统变量里面配置一下。 新增系统变量 CATALINA_HOME D:\Users\common\tomcat\apache-tomcat-8.5.97-windows-x64\apache-tomcat-8.5.97 编辑追加Path…

vue3 自定义国际化、elementPlus 国际化

自定义国际化 1. 引入 vue-i18n 插件 pnpm install vue-i18nnext 2. 页面添加语言文件目录&#xff0c;添加自定义的语言文件 3.语言目录里添加 index.ts&#xff0c; 内容如下 import { createI18n } from "vue-i18n";// 自定义语言文件 import zhCN from "…

【Gitlab远程访问本地仓库】Gitlab如何安装配置并结合内网穿透实现远程访问本地仓库进行管理

文章目录 前言1. 下载Gitlab2. 安装Gitlab3. 启动Gitlab4. 安装cpolar5. 创建隧道配置访问地址6. 固定GitLab访问地址6.1 保留二级子域名6.2 配置二级子域名 7. 测试访问二级子域名 前言 GitLab 是一个用于仓库管理系统的开源项目&#xff0c;使用Git作为代码管理工具&#xf…

【Qt-CMake】QT中cmak编译出现CMake Error: The source.. does not match the soused

QT中cmak编译出现CMake Error: The source… does not match the soused 分析 前提是该项目是从另一个路径的项目复制过来的&#xff0c;编写代码时发现无论怎样修改代码&#xff0c;运行后都没有任何变化&#xff0c;以为是qtbug&#xff0c;重构重启都没用&#xff0c;最后…

计算机毕业设计 | vue+springboot线上考试 在线测试系统(附源码)

1&#xff0c;项目介绍 项目背景 在线考试借助于网络来进行&#xff0c;传统考试所必备的考场和监考对于在线考试来说并不是必要项目&#xff0c;因此可以有效减少组织考试做需要的成本以及设施。同时&#xff0c;由于在线考试系统本身具有智能阅卷的功能&#xff0c;也大大减…

RWA会成为下一个风口吗?有哪些值得关注的项目?

随着加密货币市场的迅速发展和成熟&#xff0c;现实世界资产&#xff08;Real World Assets&#xff0c;RWA&#xff09;正逐渐引起人们的关注&#xff0c;并有望成为下一个加密货币领域的风口。本文将探讨RWA的潜力&#xff0c;以及当前值得关注的项目。 RWA的潜力 RWA代表着…

IB 公式解析

公式 3.2. Influence Function 影响函数允许我们在移除样本时估计模型参数的变化&#xff0c;而无需实际移除数据并重新训练模型。 3.3 影响平衡加权因子 3.4 影响平衡损失 3.5 类内重加权 m代表一个批次&#xff08;batch&#xff09;的大小&#xff0c;这意味着公式对一个批…

阮怀俊参与五龙乡黄沙村村企联办“强村公司”

为走好海岛县高质量发展共同富裕特色之路&#xff0c;探索村级集体经济发展新路径、扶持新模式、运行新机制&#xff0c;嵊泗县五龙乡黄沙村股份经济合作社与杭州山舍乡建乡村产业发展有限责任公司联办成“强村公司”。 创始人阮怀俊表示&#xff0c;双方就融合乡域发展和文旅产…

科林Linux_4 信号

#include <signal.h> 信号signal&#xff1a;Linux或Unix系统支持的经典的消息机制&#xff0c;用于处置进程&#xff0c;挂起进程或杀死进程 kill -l #查看系统支持的信号 1~31 Unix经典信号&#xff08;软件开发工程师&#xff09; 32、33信号被系统隐藏&#xf…

虚拟化数据恢复—误还原虚拟机快照怎么办?怎么恢复最新虚拟机数据?

虚拟化技术原理是将硬件虚拟化给不同的虚拟机使用&#xff0c;利用虚拟化技术可以在一台物理机上安装多台虚拟机。误操作或者物理机器出现故障都会导致虚拟机不可用&#xff0c;虚拟机中的数据丢失。 虚拟化数据恢复环境&#xff1a; 有一台虚拟机是由物理机迁移到ESXI上面的&a…

数据库管理-第188期 23ai:怎么用PGQL创建图(20240511)

数据库管理188期 2024-05-10 数据库管理-第188期 23ai:怎么用PGQL创建图&#xff08;20240511&#xff09;1 PGQL创建属性图1.1 PGQL属性图的元数据表1.2 创建一个PGQL属性图1.3 获取PGQL属性图的元数据 2 PGQL属性图3 官方示例演示3.1 插入数据3.2 创建PGQL属性图3.3 通过PGQL…

SpringBoot:SpringBoot原理

SpringBoot高级 SpringBoot配置 配置文件优先级 按照yaml>yml>properties的顺序加载 存在相同配置项,后加载的会覆盖先加载的 加载顺序越靠后,优先级越高 SpringBoot存在其他的多种方式进行配置,如下所示,越靠下优先级越高 1. Default properties (specified by s…

vm虚拟机安装网络适配器驱动卡死/无响应/无限等待状态

大部分原因都是以前的vm没有卸载干净所导致的&#xff0c;只需要使用CCleaner清楚干净就好 使用控制面板里的卸载把VM卸载干净 使用CCleaner软件删除干净注册表&#xff0c;这个软件百度很容易找到&#xff0c;只有十兆左右 打开下载好的软件&#xff0c;不需要注册码&#xff…