c++基础语法—————默认成员函数

news2025/1/17 5:54:20

文章目录

  • 一、构造函数(初始化)
    • 1.构造函数的名称与类名相同,没有返回类型,可以有参数。
    • 2.对象实例化时,编译器自动调用构造函数进行初始化
    • 3.若类中没有显示定义一个用户的构造函数,编译器则会自动生成一个默认的构造函数
    • 4.构造函数可重载,无参函数,全缺省函数,编译器默认生成的构造函数,都可以认为时默认的构造函数,在对象实例化时自动调用
  • 二、析构函数(自动清理)
    • 1.析构函数基本用法
    • 2.编译器自动生成的析构函数
  • 三、拷贝构造函数
    • 1.形式特点
    • 2. 若未显式定义,编译器会生成默认的拷贝构造函数。
  • 四、赋值运算符重载
    • 1、定义
    • 2、形式及用法
    • 3、赋值运算符重载
  • 五、 const成员函数
  • 六、取地址及const取地址操作符重载

一、构造函数(初始化)

在C++中,构造函数是一种特殊的成员函数,用于在创建对象时初始化对象的数据成员

1.构造函数的名称与类名相同,没有返回类型,可以有参数。

在这里插入图片描述

2.对象实例化时,编译器自动调用构造函数进行初始化

因为是特殊函数,所以在实例化时,可以在此步骤进行传参。
在这里插入图片描述

3.若类中没有显示定义一个用户的构造函数,编译器则会自动生成一个默认的构造函数

  • 对于内置成员变量,如int,char…,编译器不会初始化,该数据仍是随机值
    因为没有明确定义,所以初始化大概率不符合预定
  • 对于自定义成员变量,则编译器会主动寻找它的构造函数并进行调用
class Date {
public:
	
	void print()
			{
				cout << _year << "/" << _month << "/" << _day << endl;
				
			}

private:
	int _year;
	int _month;
	int _day;

	Time _t;

};

class Time {

public:
	Time(int hour = 12, int minute = 12, int second = 12)
	{
		_hour = hour;
		_minute = minute;
		_second = second;
		cout << "自动调用" << endl;
	}

private:
	int _hour;
	int _minute;
	int _second;
};

这两个类,显然Time数据在Date类中作成员,Date未写构造函数,根据两条规则,则年月日为随机值,time _t去寻找它本身的构造函数进行初始化。
在这里插入图片描述
那么如果time也没有写呢?
则仍然遵循那两条规律,本质为总会回到用户本身书写。

4.构造函数可重载,无参函数,全缺省函数,编译器默认生成的构造函数,都可以认为时默认的构造函数,在对象实例化时自动调用

建议在含参情况下,尽量写全缺省

//部分代码
Date(int year=1, int month=1, int day=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	

传参时
在这里插入图片描述
不传参时:
在这里插入图片描述

二、析构函数(自动清理)

1.析构函数基本用法

C++中的析构函数是一种特殊的成员函数,用于在对象被销毁时执行清理工作。析构函数的名称与类名相同,但在前面加上一个波浪号"~"。它没有参数,也不返回任何值。
析构函数在以下情况下被调用:

1、当对象超出作用域时,局部对象的析构函数会被调用。
2、当delete运算符被用于释放通过new运算符分配的对象时,
对象的析构函数会被调用。
3、当一个临时对象生命周期结束时,临时对象的析构函数会被调用。

析构函数的出现解决了用户忘记释放内存,而导致内存泄漏的问题,具有很大的实践意义
析构函数通常用于释放动态分配的资源,如释放内存、关闭文件等。如果在类中没有显式定义析构函数,编译器会生成一个默认的析构函数,该默认析构函数什么也不做。

typedef int DataType;
class Stack
{
public:
 Stack(size_t capacity = 3)
 {
 _array = (DataType*)malloc(sizeof(DataType) * capacity);
 if (NULL == _array)
 {
 perror("malloc申请空间失败!!!");
 return;
 }
 _capacity = capacity;
 _size = 0;
 }
 void Push(DataType data)
 {
 // CheckCapacity();
 _array[_size] = data;
 _size++;
 }
 // 其他方法...
 ~Stack()
 {
 if (_array)
 {
 free(_array);
 _array = NULL;
 _capacity = 0;
 _size = 0;
 }
 }
private:
 DataType* _array;
 int _capacity;
 int _size;
};
void TestStack()
{
 Stack s;
 s.Push(1);
 s.Push(2);
}

如这个栈的类,一旦成员函数显示定义析构函数,后续调用全部自动在生命周期结束时自动析构。

2.编译器自动生成的析构函数

class Time{
public:
 ~Time()
 {
 cout << "~Time()" << endl;
 }
private:
 int _hour;
 int _minute;
 int _second;
};
class Date
{
private:
 // 基本类型(内置类型)
 int _year = 1970;
 int _month = 1;
 int _day = 1;
 // 自定义类型
 Time _t;
};
int main()
{
 Date d;
 return 0;
}

如上代码,Date的类中有四个成员变量,三个内置类型,一个自定义类型_t
内置类型成员,销毁时不需要资源清理,最后系统直接将其内存回收即可;而_t是Time类对象,所以在d销毁时,要将其内部包含的Time类的_t对象销毁,所以要调用Time类的析构函数。
但是:main函数中不能直接调用Time类的析构函数,实际要释放的是Date类对象,所以编译器会调用Date类的析构函数,而Date没有显式提供,则编译器会给Date类生成一个默认的析构函数,目的是在其内部调用Time
在这里插入图片描述

三、拷贝构造函数

1.形式特点

拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

拷贝构造函数也是特殊的成员函数,其特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,
    因为会引发无穷递归调用。

错误写法:

Date (const Date d);

在这里插入图片描述
在这期间会不断引起拷贝构造无穷递归

正确写法:

Date (const Date& d);

2. 若未显式定义,编译器会生成默认的拷贝构造函数。

默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定义类型是调用其拷贝构造函数完成拷贝的。

类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。
在这里插入图片描述

四、赋值运算符重载

1、定义

C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)

为什么要引入:
目的是为了增强语言的灵活性和表达能力。通过运算符重载,我们可以自定义类的行为,使其支持类似内置数据类型的操作,从而提高代码的可读性和可维护性。

注意点:

  • 不能通过连接其他符号来创建新的操作符:比如operator@
  • 重载操作符必须有一个类类型参数
  • 用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this
  • .* :: sizeof ?: . 注意以上5个运算符不能重载。

2、形式及用法

当函数为全局函数时,参数为两个对象,至于怎么解决类的封装问题,后面会讲解友元函数的方法

bool operator==(const Date& d1, const Date& d2)
{
    return d1._year == d2._year
   && d1._month == d2._month
        && d1._day == d2._day;
}

当函数为类成员函数时,会有隐藏this指针传入

 bool operator==(const Date& d2)
 {
        return _year == d2._year;
            && _month == d2._month
            && _day == d2._day;
 }

调用方法通常直接使用运算符符号来调用已经重载的运算符,例如a + b、obj1 == obj2等。

当然也可以使用函数形式调用obj1.operator+(obj2)、obj1.operator==(obj2)等。

3、赋值运算符重载

1、函数形式

  • 参数类型:const T&,传递引用可以提高传参效率
  • 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值检测是否自己给自己赋值
  • 返回*this :要复合连续赋值的含义
 Date& operator=(const Date& d)
 {
 if(this != &d)//防止多次赋值
       {
            _year = d._year;
            _month = d._month;
            _day = d._day;
       }
        
        return *this;
 }

赋值运算符只能重载成类的成员函数不能重载成全局函数
原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。

2、注意默认
用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。
注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

所以这里和拷贝构造哪里一样若有涉及资源申请时,最好自定义显式定义否则引起程序崩溃。

五、 const成员函数

const成员函数是指在函数声明和定义中使用了const关键字的成员函数。这种函数承诺不会修改对象的状态,并且可以在const对象上调用。

class MyClass {
public:
    void regularFunction() {
        // 可以修改对象的状态
    }

    void constFunction() const {
        // 不会修改对象的状态
    }
};

这里有四点问题:

1. const对象可以调用非const成员函数吗?
2. 非const对象可以调用const成员函数吗?
3. const成员函数内可以调用其它的非const成员函数吗?
4. 4. 非const成员函数内可以调用其它的const成员函数吗?

这里就牵连到权限的放大与缩小

int main() {
    const MyClass obj1;
    MyClass obj2;

    obj1.regularFunction();  
    // 错误,无法调用非const成员函数,权限放大了
    obj1.constFunction();   
     // 可以调用const成员函数

    obj2.regularFunction();  
    // 可以调用非const成员函数
    obj2.constFunction();    
    // 可以调用const成员函数,权限缩小
    return 0;
}

总结:
成员函数,如果只对成员变量进行访问,那么建议使用const成员函数
如果对成员变量进行修改访问,不建议加const

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

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

class A
{ 
public :
 Date* operator&()
 {
 return this ;
 }
 const Date* operator&()const
 {
 return this ;
 }

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需要重载,比如想让别人获取到指定的内容!

本期内容分享到这里!感谢收看
在这里插入图片描述

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

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

相关文章

[LVGL]:MACOS下使用LVGL模拟器

如何在MACOS下使用lvgl模拟器 1.安装必要环境 brew install sdl2查看sdl2安装位置&#xff1a; (base) ➜ ~ brew list sdl2 /opt/homebrew/Cellar/sdl2/2.30.1/bin/sdl2-config /opt/homebrew/Cellar/sdl2/2.30.1/include/SDL2/ (78 files) /opt/homebrew/Cellar/sdl2/2.3…

计算机系统·浮点数

浮点数 理解含有小数值的二进制数 定点表示方法 十进制&#xff1a;以小数点为分界线&#xff0c;小数点左边数字的权重是10的正幂&#xff0c;小数点右边数字的权重是10的负幂。如图所示 二进制&#xff1a;小数点左边数字的权重是2的正幂&#xff0c;小数点右边数字的权重…

免费阅读篇 | 芒果YOLOv8改进111:注意力机制CBAM:轻量级卷积块注意力模块,无缝集成到任何CNN架构中,开销可以忽略不计

&#x1f4a1;&#x1f680;&#x1f680;&#x1f680;本博客 改进源代码改进 适用于 YOLOv8 按步骤操作运行改进后的代码即可 该专栏完整目录链接&#xff1a; 芒果YOLOv8深度改进教程 该篇博客为免费阅读内容&#xff0c;YOLOv8CBAM改进内容&#x1f680;&#x1f680;&am…

Exam in MAC [容斥]

题意 思路 正难则反 反过来需要考虑的是&#xff1a; (1) 所有满条件一的(x,y)有多少对&#xff1a; x 0 时&#xff0c;有c1对 x 1 时&#xff0c;有c对 ...... x c 时&#xff0c;有1对 以此类推 一共有 (c2)(c1)/2 对 (2) 符合 x y ∈ S的有多少对&#xff1a…

深度学习每周学习总结P1(pytorch手写数字识别)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 目录 0. 总结1. 数据导入部分2. 模型构建部分3. 训练前的准备4. 定义训练函数5. 定义测试函数6. 训练过程 0. 总结 总结: 数据导入部分&a…

Jmeter进行http接口测试

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 本文主要针对http接口进行测试&#xff0c;使用 jmeter工具实现…

Jenkins自定义镜像推送到Harbor仓库

之前Jenkins需要推送jar包到远程到目标服务器再进行构建 现在Jenkins容器内部可以直接使用Docker了 直接在Jenkins构建好推送到Harbor仓库上&#xff0c;然后不管是哪台目标服务器&#xff0c;只需要去Harbor仓库拉取镜像即可。 修改Jenkins任务 将代码检测下面的远程服务器步…

UI 学习 三 可访问性 UX

设计、交流和实现不同领域内容的易访问性决策&#xff0c;涉及到一系列考虑因素&#xff0c;以达到更容易访问的产品体验。 Material使用的框架借鉴了WCAG标准和行业最佳实践&#xff0c;以帮助任何人预测、计划、记录和实现可访问体验。 下面描述的三个阶段有助于将可视化UI…

SIMATIC C7-635西门子触摸屏维修6ES7635-2EB02-0AE3

西门子工控机触摸屏维修C7-626/P西门子控制面板维修DP Panel 6ES7626-1DG03-0AE3&#xff1b;6ES7626-2DG04-0AE3 SIMATIC HMI移动面板维修&#xff08;西门子面板&#xff09;可轻松进行电源管理与操作&#xff0c;成为移动应用的可能之选。该面板支持线缆或 Wi-Fi 通信&…

Weblogic 常规渗透测试环境

测试环境 本环境模拟了一个真实的weblogic环境&#xff0c;其后台存在一个弱口令&#xff0c;并且前台存在任意文件读取漏洞。分别通过这两种漏洞&#xff0c;模拟对weblogic场景的渗透。 Weblogic版本&#xff1a;10.3.6(11g) Java版本&#xff1a;1.6 弱口令 环境启动后…

数字孪生与智慧城市:实现城市治理现代化的新路径

随着信息技术的迅猛发展&#xff0c;智慧城市已成为城市发展的必然趋势。数字孪生技术作为智慧城市建设的重要支撑&#xff0c;以其独特的优势为城市治理现代化提供了新的路径。本文将探讨数字孪生技术在智慧城市中的应用&#xff0c;以及如何实现城市治理的现代化。 一、数字…

OJ_还是畅通工程

题干 #include <iostream> #include <vector> #include <algorithm> using namespace std;//并查集的应用&#xff1a;判断图的连通性int set[10001]; //i下标是集合数据编号,set[i]是i的父亲的编号 //若i是根&#xff0c;可令set[i] i void InitDisjointSe…

Docker容器化技术(使用Dockerfile制作Nginx镜像)

编写Dockerfile制作Web应用系统nginx镜像&#xff0c;生成镜像名为nginx:v1.1&#xff0c;并推送其到私有仓库。 1、基于centos7基础镜像&#xff1b; 2、指定作者为Chinaskill&#xff1b; 3、安装nginx服务&#xff0c;将提供的dest目录传到镜像内&#xff0c;并将de…

案例分析篇00-【历年案例分析真题考点汇总】与【专栏文章案例分析高频考点目录】(2024年软考高级系统架构设计师冲刺知识点总结-案例分析篇-先导篇)

专栏系列文章&#xff1a; 2024高级系统架构设计师备考资料&#xff08;高频考点&真题&经验&#xff09;https://blog.csdn.net/seeker1994/category_12593400.html 案例分析篇01&#xff1a;软件架构设计考点架构风格及质量属性 案例分析篇11&#xff1a;UML设计考…

YOLO学习

至少不比原来差 网格大小&#xff1a;13、26、52 不同感受野匹配 损失函数是对数 二分类

通过路由器监控,优化网络效率

路由器是网络的基本连接组件&#xff0c;路由器监控涉及将路由器网络作为一个整体进行管理&#xff0c;其中持续监控路由器的性能、运行状况、安全性和可用性&#xff0c;以确保更好的操作和最短的停机时间&#xff0c;因此监控路由器至关重要。 为什么路由器监控对组织很重要…

面试相关问题准备

一.MySql篇 1优化相关问题 1.1MySql中如何定位慢查询&#xff1f; 慢查询的概念&#xff1a;在MySQL中&#xff0c;慢查询是指执行时间超过一定阈值的SQL语句。这个阈值是由long_query_time参数设定的&#xff0c;它的默认值是10秒1。也就是说&#xff0c;如果一条SQL语句的执…

物联网技术在农药化肥行业的远程监控解决方案

物联网技术在农药化肥行业的远程监控解决方案 随着物联网技术的日益成熟&#xff0c;其在农药化肥行业的应用呈现出广阔的前景。通过物联网远程监控解决方案&#xff0c;可以实现生产、存储和施用环节的全程智能化管理&#xff0c;大大提高行业效率和环保水平。 通过物联网云…

CleanMyMac X2024永久免费的强大的Mac清理工具

作为产品功能介绍专员&#xff0c;很高兴向您详细介绍CleanMyMac X这款强大的Mac清理工具。CleanMyMac X具有广泛的清理能力&#xff0c;支持多种文件类型的清理&#xff0c;让您的Mac始终保持最佳状态。 系统垃圾 CleanMyMac X能够深入系统内部&#xff0c;智能识别并清理各种…

软件设计师:12 - 下午题历年真题

章节章节01-计算机组成原理与体系结构07 - 法律法规与标准化与多媒体基础02 - 操作系统基本原理08 - 设计模式03 - 数据库系统09 - 软件工程04 - 计算机网络10 - 面向对象05 - 数据结构与算法11 - 结构化开发与UML06 - 程序设计语言与语言处理程序基础12 - 下午题历年真题End -…