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

文章目录

  • 一、构造函数(初始化)
    • 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.mfbz.cn/a/458867.html

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

相关文章

MCM箱模型的运行及结果分析,MCM建模技巧与参数设置、EKMA曲线绘制、大气O3来源解析

目录 一、大气中O3形成知识基础、MCM和Atchem 2原理及Linux系统安装 二、MCM建模、数据输入、模型运行及结果输出 三、O3形成途径、生成潜势及其敏感性分析 EKMA曲线及大气O3来源解析 更多应用 臭氧污染不仅对气候有重要影响&#xff0c;而且对人体健康、植物生长均有严重…

大门对楼梯,怎么办?

​ 中国是一个非常重视风水的国家&#xff0c;风水学发扬和流传已有几千年的历史&#xff0c;很多懂风水的人都知道&#xff0c;大门风水是其中非常重要的一环&#xff0c;因为大门风水直接影响全家人的各种运势。大门风水好&#xff0c;能帮助你一臂之力&#xff1b;若大门风…

加密货币在网络违法犯罪活动中的利用情况调查

一、调查背景 区块链基于分布式共识和经济激励等手段&#xff0c;在开放式、无许可的网络空间中&#xff0c;为价值的确立、存储、转移提供了新的解决方案。然而随着加密生态在过去若干年的快速发展&#xff0c;加密货币也越来越多地被用于各类风险活动&#xff0c;为网络赌博…

了解什么是 Redis 的雪崩、穿透和击穿?Redis 崩溃之后会怎么样?系统该如何应对这种情况?如何处理 Redis 的穿透?

目录 一、面试官心理分析 二、面试题剖析 1. 缓存雪崩 2. 缓存穿透 3. 缓存击穿 一、面试官心理分析 其实这是问到缓存必问的&#xff0c;因为缓存雪崩和穿透&#xff0c;是缓存最大的两个问题&#xff0c;要么不出现&#xff0c;一旦出现就是致命性的问题&#x…

发票OCR-国税可进行的发票查验种类-接口文档

发票查验内容包括发票种类名称、发票代码、发票号码、金额、销售方名称、购买方名称等信息。可以在国家税务总局全国增值税发票查验平台上进行查验&#xff0c;也可以进入发票所属省、直辖市税务局官方网站的“我要查询-发票查询”模块进行查验&#xff0c;企业也可以通过发…

vue生命周期函数原理解析,vue阻止事件冒泡方法实现

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

#15封装vue3+el-table表格数据请求函数

目录 1、useTableData 2、util 3、使用 开箱即用&#xff0c;理解容易。 1、useTableData import { reactive } from vue import { getType } from /utils/utilsexport const useTableData (api) > {if (typeof api ! function && getType(api) ! Promise) {th…

Unity类银河恶魔城学习记录10-1 10-2 P89,90 Character stats - Stat script源代码

Alex教程每一P的教程原代码加上我自己的理解初步理解写的注释&#xff0c;可供学习Alex教程的人参考 此代码仅为较上一P有所改变的代码 【Unity教程】从0编程制作类银河恶魔城游戏_哔哩哔哩_bilibili Stat.cs using System.Collections; using System.Collections.Generic; us…

【MAC】OpenResty安装

首先官方网站&#xff1a;http://openresty.org/cn/download.html 安装&#xff1a; 我是安装官网去执行的安装命令 配置环境变量 1.打开配置文件 vim ~/.bash_profile2.粘贴进去变量配置 #OPENRESTY export NGINX_HOME/opt/homebrew/etc/openresty export PATH$PATH:$NGI…

【面试精讲】String是如何实现的?String源码分析

【面试精讲】String是如何实现的&#xff1f;String源码分析 目录 一、String实现机制 二、String不可变性&#xff08;使用final修饰&#xff09; 三、String 和 StringBuilder、StringBuffer 的区别 四、和equals的区别 五、String创建对象与JVM辨析 六、String源码解…

Mybatis 动态sql环境搭建(学习笔记16)

什么是动态sql:根据不同的条件生成不同的sql语句 借助功能强大的基于 OGNL 的表达式&#xff0c;MyBatis 3 替换了之前的大部分元素&#xff0c;大大精简了元素种类&#xff0c;现在要学习的元素种类比原来的一半还要少。 ifchoose (when, otherwise)trim (where, set)foreac…

拆解Spring boot:Springboot为什么如此丝滑而简单?源码剖析解读自动装配

&#x1f389;&#x1f389;欢迎光临&#xff0c;终于等到你啦&#x1f389;&#x1f389; &#x1f3c5;我是苏泽&#xff0c;一位对技术充满热情的探索者和分享者。&#x1f680;&#x1f680; &#x1f31f;持续更新的专栏《Spring 狂野之旅&#xff1a;从入门到入魔》 &a…

Screaming Frog SEO Spider:网站优化利器,轻松掌握网络爬虫精髓

在数字时代&#xff0c;网络爬虫已成为各行各业获取数据、分析趋势的重要工具。而在众多网络爬虫开发工具中&#xff0c;Screaming Frog SEO Spider以其强大的功能和易用性脱颖而出&#xff0c;成为众多网站优化师和SEO从业者的首选。 Screaming Frog SEO Spider是一款适用于M…

笔记本电脑数据恢复:如何轻松地从笔记本电脑恢复文件

不小心从笔记本电脑中删除了一些重要文件&#xff1f;或者恶意软件和其他不可控因素是否导致您的文件消失&#xff1f;人们很容易认为这些文件已经永远消失&#xff0c;并且无法恢复。但这与事实相差甚远。通过遵循正确的数据恢复礼仪并使用良好的数据恢复工具&#xff0c;您可…

英语翻译报价,千字英语翻译报价

众所周知&#xff0c;英语作为全球通用的语言&#xff0c;其翻译需求量极大。无论是欧美国家的日常交流&#xff0c;还是小语种的翻译工作&#xff0c;英语都常常作为中介语言&#xff0c;扮演着桥梁的角色。那么&#xff0c;英语翻译公司是如何定价的&#xff1f;每千字的英语…

Qt中进行客户端开发框架

在Qt中进行客户端开发是一种常见的做法&#xff0c;Qt是一个跨平台的C框架&#xff0c;提供了丰富的工具和类库&#xff0c;用于开发图形用户界面&#xff08;GUI&#xff09;应用程序、网络应用程序以及其他类型的软件。以下是一些常用的Qt客户端开发框架和技术&#xff0c;希…

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…

Qt客户端开发的技术难点

在Qt客户端开发中&#xff0c;可能会遇到一些技术难点&#xff0c;这些难点可能与UI设计、性能优化、跨平台兼容性等方面有关。以下是一些可能的技术难点&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作…

虚拟游戏理财 - 华为OD统一考试(C卷)

OD统一考试&#xff08;C卷&#xff09; 分值&#xff1a; 100分 题解&#xff1a; Java / Python / C 题目描述 在一款虚拟游戏中生活&#xff0c;你必须进行投资以增强在虚拟游戏中的资产以免被淘汰出局。 现有一家Bank&#xff0c;它提供有若干理财产品m&#xff0c;风险及…

将SQL数据库转换为Mysql数据库

一、准备工作 1、SQL server安装包与已经有数据的mdf、ldf数据库文件&#xff1b; 2、.net Framework安装包&#xff1b;&#xff08;用于支持SQL Server安装的组件&#xff09; 3、MySql安装包&#xff1b;&#xff08;用于目标数据库的环境安装&#xff09; 4、navicat安装包…
最新文章