【C++技能树】类的六个成员函数Ⅰ --构造、析构、拷贝构造函数

这篇具有很好参考价值的文章主要介绍了【C++技能树】类的六个成员函数Ⅰ --构造、析构、拷贝构造函数。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【C++技能树】类的六个成员函数Ⅰ --构造、析构、拷贝构造函数

Halo,这里是Ppeua。平时主要更新C语言,C++,数据结构算法…感兴趣就关注我吧!你定不会失望。

【C++技能树】类的六个成员函数Ⅰ --构造、析构、拷贝构造函数

0.this指针

在开始本章内容之前,先浅浅的了解一下this指针的概念.这对理解后面的内容有着很大的帮助.

this指针顾名思义就是这个指针,我们先来看看下面这段很简单的代码

class Date{
public:
	void print()
	{
		cout<<date;
	}
private:
	int date;
};
int main()
{
	Date d1;
	d1.print();
}

首先创建了一个Date的日期类(这也是我们今天的主角),写了一个函数:在屏幕上输出date的具体值,那么this指针体现在哪呢?

每一个函数调用的时候都会隐式的传入一个this指针对象也就是作为成员函数的形式参数,他指向函数运行时调用的对象

所以这段代码也可以写成这样:

class Date{
public:
	void print()
	{
		cout<<this->date;
	}
private:
	int date;
};
int main()
{
	Date d1;
	d1.print();
}

this->date = 访问d1里的date,所以当多个对象互相调用的时候,编译器就能分清究竟谁是谁的参数了this的类型是class *const,也就是无法改变this指向的内容(这点也很好理解,如果能轻易改变,那么这个this的定义还有什么用呢?)

那么问题来了 this是存在哪里呢?

  1. 对象里面
  2. 静态区
  3. 常量区

很多uu们会选择第一个选项,对象里面.但我们回顾我们的定义,他是一个 成员函数的形式参数,那么函数的形式参数自然存储在栈当中(忘记的uu们可以看看这篇文章,会让你对函数的创建与销毁有一个更深层次的理解),所以答案是3

那么再来看看下面的代码运行会有什么效果呢?

class Date{
public:
	void print()
	{
		cout<<"Hello world";
	}
private:
	int date;
};
int main()
{
	Date *d1=nullptr;
	d1->print();
}

虽然d1被初始化为空,但调用print的时候并没有访问到this中成员.所以并不会出现访问错误特点

相对于上面的代码,下面的代码有什么问题?

#include<iostream>
using namespace std;
//this
class Date{
public:
	void print()
	{
		cout<<this->date;
	}
private:
	int date;
};
int main()
{
	Date *d1=nullptr;
	d1->print();
}

显而易见输出内容时访问了this里的内容,此时this代表的是d1,d1为空自然this也为空,所以访问其成员变量就会出现越界访问的错误

1.Class默认成员函数

了解这个之前来看看为什么要有成员对象.回顾之前所学的数据结构:链表、栈、队列…这些数据结构使用之前是不是都需要申请内存空间.虽然这是必要的,但是每次申请不是很麻烦嘛?且函数使用完时还需要进行释放内存,但比如我们需要获取这个栈顶的元素,我们就没有办法直接返回(因为返回后程序结束,内存没有释放),那返回这类值之前都需要一个变量来存储嘛?这也太不高级了

所以C++提出了默认成员函数这一个概念:也就是类里会自动生成一个帮你完成上面的创建,销毁的工作的函数,当然他的功能还远远不止这些

C++中一共有六个默认成员函数

本篇博客我们重点介绍前三个默认成员函数:构造函数、析构函数、拷贝构造函数
【C++技能树】类的六个成员函数Ⅰ --构造、析构、拷贝构造函数

2.构造函数

前面提到,如果每次使用一个类型的时候都需要使用一下Init函数未免太过繁琐.所以C++给出了一个构造函数的解决方法先来看看下面这个代码

class Date{
public:
	Date()
	{
		cout<<"Date";
	}
private:
	int date;
	int monthl;
	int year;
};
int main()
{
	Date d1;

}

这段代码仅仅是声明了一个Date对象d1,并没有调用其任何成员函数.但是此时代码运行结果会输出

Date

也就是调用了Date这个与类同名的函数,这个与类同名的函数我们就叫做构造函数.并不是完成内存的创建,仅为对对像属性的初始化.其有以下几个特点

  1. 函数名与类名相同,其在该对象生命周期之间只会被调用一次。
  2. 无返回值。
  3. 对象实例化时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。

前两个就是字面意思没什么不好理解的,我们重点来说下后两个:

调用规则:

写构造函数的方式一般有以下几种

  1. 无参数的构造函数(默认构造函数)

    class Date{
    public:
    	Date()
    	{
    		_date=10;
    		_monthl=12;
    		_year=2023;
    	}
    	void print()
    	{
    		cout<<_date<<endl<<_monthl<<endl<<_year<<endl;
    	}
    private:
    	int _date;
    	int _monthl;
    	int _year;
    };
    int main()
    {
    	Date d1;
    	d1.print();
    }
    

    在这个函数中,构造函数并没有传入参数,所以其叫做无参数的构造函数.,只需要正常声明就会调用这个函数了

  2. 带参数的构造函数

    class Date{
    public:
    	Date(int date,int month,int year)
    	{
    		_date=date;
    		_monthl=month;
    		_year=year;
    	}
    	void print()
    	{
    		cout<<_date<<endl<<_monthl<<endl<<_year<<endl;
    	}
    private:
    	int _date;
    	int _monthl;
    	int _year;
    };
    int main()
    {
    	Date d1(10,20,30);
    	d1.print();
    }
    

    在这个函数中,构造函数传入了参数,所以叫其 带参数的构造函数,像调用函数一样声明即可调用这个函数

  3. 全缺省的构造函数(默认构造函数)

    class Date{
    public:
    	Date(int date=10,int month=10,int year=10)
    	{
    		_date=date;
    		_monthl=month;
    		_year=year;
    	}
    	void print()
    	{
    		cout<<_date<<endl<<_monthl<<endl<<_year<<endl;
    	}
    private:
    	int _date;
    	int _monthl;
    	int _year;
    };
    int main()
    {
    	Date d1(10,20,30);
    	d1.print();
    }
    

    这和带参的析构函数差不多,也是一样的调用 有参数的时候按照方式2来传参,没有参数的时候按照方式1来传参即可,

    但注意这种方法不可与无参数的构造函数同时声明,因为若没传入参数则不知道调用哪一个了

当然 半缺省的构造函数也是可以的,这里就不过多赘述了.

当用户没有自己写构造函数的时候,编译器会自动生成一个构造函数.与1 3统称为默认构造函数默认构造函数只能用有一个

但这个函数将内置类型随机赋值(C++11后打了补丁,允许用户在声明时给内置类型变量赋值),若有自定义类型,则调用自定义类型的构造函数.

这里解释下什么是自定义类型和内置类型,内置类型是语言提供的类型例如:str int double等,而自定义类型则为class struct union等

大多数情况下我们都需要手写构造函数,所以我们什么时候不需要写构造函数呢?

  1. 内置类型成员都有自己的缺省值,且初始化符合要求
  2. 全是自定义类型构造函数,且这些类型都定义了默认构造

3.析构函数

析构函数与构造函数的功能刚好相反,其也不涉及对对像本身的销毁,而是对对象销毁完后"残局的处理"

class Date{
public:
	
	Date()
	{
		a=(int*)malloc(sizeof(int)*4);
	}
	~Date()
	{
        cout<<"~Date";
		free(a);
		a=nullptr;
	}
private:
	int *a=nullptr;
};

当Date创建的对象所在的栈帧被销毁时,会自动调用这个析构函数来处理残局.

析构函数的特点如下:

  1. 其名字为~+类名
  2. 无参数无返回类型,不支持重载
  3. 对象生命周期结束的时候,会自动调用析构函数

当有动态申请空间的时候,我们就需要手写析构函数.那我们什么时候不需要写析构函数呢?

  1. 没有动态申请的资源
  2. 需要释放资源的成员都是自定义类型,

4.拷贝构造函数

当我们想用一个对象的值去初始化另一个对象的时候,我们该如何去做呢?

Date d1=d2;

C++规定了用一个对象去初始化另一个对象的时候.需要调用拷贝构造函数.拷贝构造函数时构造函数的重载,所以其也满足构造函数的规则

class Date{
public:
	
	Date(int date,int month,int year)
	{
		_date=date;
		_monthl=month;
		_year=year;
	}
	Date(const Date &d)
	{
		cout<<"copy Date";
		_date=d._date;
		_monthl=d._monthl;
		_year=d._year;
	}
	
	void print()
	{
		cout<<_date<<endl<<_monthl<<endl<<_year<<endl;
	}
private:
	int _date;
	int _monthl;
	int _year;
};
int main()
{
	Date d1(11,12,123);
	Date d2=d1;
	d2.print();
}

此时d2的初始化调用了拷贝构造函数.为什么拷贝构造函数需要的形参为值的引用呢

因为若不传值的引用,拷贝构造函数的形式参数仍为一个Date类型,传值的过程仍然是在初始化拷贝一个类对象,又会去调用其拷贝构造函数,之后就无限套娃.陷入了循环.

所以形参需要是引用

若没有自己写出拷贝函数,其调用规则为:

  1. 内置类型成员完成值拷贝/浅拷贝
  2. 自定义类型成员会调用他自己的拷贝构造函数

什么是深浅拷贝呢?这里浅浅的提一下

浅拷贝会对值进行复制,若为数组,则会创建一个指针指向原地址.也就是两个指针指向同一块空间

深拷贝则会创建两个一模一样的变量

所以浅拷贝在拷贝空间的时候会出现问题(两个变量共用一块空间),此时我们就需要自己手写拷贝构造实现深拷贝

【C++技能树】类的六个成员函数Ⅰ --构造、析构、拷贝构造函数

本篇文章结束啦,感兴趣的uu们可以关注一下

诸君,山顶见!文章来源地址https://www.toymoban.com/news/detail-433044.html

到了这里,关于【C++技能树】类的六个成员函数Ⅰ --构造、析构、拷贝构造函数的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】类和对象②(类的默认成员函数:构造函数 | 析构函数)

    🔥 个人主页: Forcible Bug Maker 🔥 专栏: C++ 目录 前言 类的6个默认成员函数 构造函数 概念 构造函数的特性及用法 析构函数 概念 析构函数的特性及用法 结语 本篇主要内容:类的6个默认成员函数中的 构造函数 和 析构函数 进入到类和对象内容的第二节,上篇博客中介绍了

    2024年04月16日
    浏览(41)
  • ⚡【C++要笑着学】(7) 默认成员函数:构造函数 | 析构函数 | 拷贝构造函数

    🔥 订阅量破千的火热 C++ 教程 👉 火速订阅 《C++要笑着学》   🔥 CSDN 累计订阅量破千的火爆 C/C++ 教程的 2023 重制版,C 语言入门到实践的精品级趣味教程。 了解更多: 👉  \\\"不太正经\\\" 的专栏介绍  ← 试读第一章 订阅链接: 🔗 《C语言趣味教程》 ← 猛戳订阅!   本篇

    2024年02月07日
    浏览(54)
  • 【C++】构造函数,析构函数,拷贝构造,运算符重载,const 成员

    默认成员函数:如果不显示,编译器默认生成 构造函数:是一个特殊的 成员函数 ,函数名与类名相同,专门用于 初始化类对象 函数名与类名相同 无返回值 ,没有被声明为void类型 对象实例化时 编译器自动调用 , Date d1 ,或 Date d2(2023, 4, 21) 构造函数可以重载,一个类中可以

    2023年04月24日
    浏览(57)
  • 【C++干货基地】六大默认成员函数: This指针 | 构造函数 | 析构函数

    🎬 鸽芷咕 :个人主页  🔥 个人专栏 : 《C++干货基地》《粉丝福利》 ⛺️生活的理想,就是为了理想的生活!   哈喽各位铁汁们好啊,我是博主鸽芷咕《C++干货基地》是由我的襄阳家乡零食基地有感而发,不知道各位的城市有没有这种实惠又全面的零食基地呢?C++ 本身作

    2024年03月11日
    浏览(34)
  • C++ 学习 ::【基础篇:14】:C++ 类的基本成员函数:析构函数的作用 及 自定义析构函数情形

    本系列 C++ 相关文章 仅为笔者学习笔记记录,用自己的理解记录学习!C++ 学习系列将分为三个阶段: 基础篇、STL 篇、高阶数据结构与算法篇 ,相关重点内容如下: 基础篇 : 类与对象 (涉及C++的三大特性等); STL 篇 : 学习使用 C++ 提供的 STL 相关库 ; 高阶数据结构与算

    2024年02月07日
    浏览(35)
  • 【是C++,不是C艹】 类与对象 | 默认成员函数 | 构造函数 | 析构函数

    💞💞 欢迎来到 Claffic 的博客 💞💞  👉  专栏: 《是C++,不是C艹》👈 前言: 在完成类与对象的认识后,我们接着学习类与对象的第二部分:默认成员函数,它包括构造函数,析构函数,拷贝构造,赋值重载,普通对象取地址和const对象取地址重载,放心,这一期不会都

    2024年02月09日
    浏览(31)
  • 【C++初阶】类与对象:6个默认成员函数-----构造函数和析构函数

        我们在写代码的时候经常会忘记初始化和销毁,C++的构造函数和析构函数就能避免这个问题。 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。 1.构造函数是一个特殊的成员函数; 2. 名字与类名相同 ,创建类类型对象时由 编译器自动调用

    2024年02月05日
    浏览(34)
  • 【C++】:类和对象(中)之类的默认成员函数——构造函数and析构函数

    如果一个类中什么成员都没有,简称为空类 空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数 由于编译器的优化 我们未给_a赋值 这里是不会报

    2024年02月08日
    浏览(36)
  • <c++> 类的继承 | 基类与派生类 | 构造函数与析构函数

    🚀 个人简介:CSDN「 博客新星 」TOP 10 , C/C++ 领域新星创作者 💟 作    者: 锡兰_CC ❣️ 📝 专    栏: 从零开始的 c++ 之旅 🌈 若有帮助,还请 关注➕点赞➕收藏 ,不行的话我再努努力💪💪💪 c++ 面向对象三大特性: 封装,继承,多态 。通过本文我们将了解什么是类的

    2023年04月20日
    浏览(36)
  • C++中类的6个默认成员函数 【拷贝构造函数】

    在前几章学习对象的时候,我们有的时候需要一个与已存在对象一某一样的新对象 那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢? 拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时

    2024年02月20日
    浏览(40)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包