前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >C++ 初阶 类和对象(中)

C++ 初阶 类和对象(中)

作者头像
大海里的番茄
发布2024-01-19 13:40:03
1230
发布2024-01-19 13:40:03
举报
文章被收录于专栏:番茄_C语言番茄_C语言

前言:C++初阶系列,每一期博主都会使用简单朴素的语言将对应的知识分享给大家,争取让所有人都可以听懂,C++初阶系列会持续更新,上学期间将不定时更新,但总会更的

一、构造函数

1.1为什么要有构造函数?

在C语言的学习中,我们创建一个结构体变量之后所做的第一件事就是初始化结构体变量,我们往往会为此写上一个初始化函数,Init+被初始化的结构体名字。就拿顺序表来说,我们初始化顺序表就会写上一个InitSeqlist之类的函数。但是我们写了有时也会忘记使用它,哈哈,是不是蚌埠住了,但这就是我们经常会犯的错误,这往往会造成我们的程序与预期不符,举个例子,我们在初始化顺序表的时候应该要将顺序表首元素的指针置空或开空间,但我们若是忘记置空或者忘记开空间,就会导致我们访问到野指针,会造成不可预料的后果。

因此在C++中就诞生了一个超级好用的东西,它就是构造函数,它的作用也是很简单粗暴,那就是在你创建了一个对应的类(结构体)的时候,编译器会根据你书写的构造函数对你创建的类进行初始化。妈妈再也不用当心我忘记初始化类了~

1.2构造函数的特性

1. 无返回值。 2.函数名与类名相同。 3. 对象实例化时编译器自动调用对应的构造函数。 4. 构造函数可以重载。

先来讲一下第一点,无返回值,这里的无返回值是包括void,也就是连void都不用,直接写构造函数名就行了,这时候我们就会接触到第二点,函数名与类名相同,比方说我们要创建一个关于日期的类,我给这个类取名为Date,那么我的构造函数也得写成类。

第三点也就是之前我们强调的一点,这里就不再赘述。第四点则代表了构造函数的可塑性,它是可以重载的,那么也就代表着它能够更加灵活地根据我们的需求去构造。对于重载不是很理解的小伙伴可以去看看博主写的这篇文章。C++初阶 入门(2)-CSDN博客

1.3使用构造函数

我们拿关于日期的类举例子,年月日基本变量创建一下,再写一个构造函数和打印函数,但需要注意的一点就是构造函数的创建必须要有默认构造函数,否则在你不传变量的时候,编译器没法对其进行简单地初始化,编译器就会报下图所示错误。

什么是默认构造函数?在我看来一共有三种

1.在构造函数中写入缺省值,实现全缺省,这样就可以实现创建无参数变量依然可以初始化变量

2.使用重载的方式来缺省

3.在声明的同时进行初始化

值得一提的是,如果你已经写了构造函数,那么编译器就不会采用你写的声明,而是会去直接调用你写的构造函数,假设你这个构造函数没写完,那就会报错。如图:

屏蔽掉之后就可以正常的使用声明

总结一下:

总的来说,默认构造函数就是指不传参也可以调用的函数,如全缺省。 博主推荐使用方法1来进行构造函数的书写,方法2和方法3写的默认构造函数不是很规矩。

细节:

方法1和方法2不可以同时存在,否则编译器会出现歧义 值得一提的是,方法1和方法2都可以和声明的形式共存,这是因为一旦有了构造函数,编译器就会忽略声明的初始化而去调用构造函数的内容。

1.4内置类型和自定义类型在构造方面的细节

先来说一下什么是内置类型,内置类型就是指语言自带的类型,如int,double,float......自定义类型就很好理解了,就是用户自己定义的类型,如class出来的类。但必须要注意的一点则是,在C++中,编译器会对自定义类型调用它的默认构造函数,而不对内置类型进行处理。

代码语言:javascript
复制
#include<iostream>
#include<stdlib.h>
using namespace std;
class Stack
{
public:
	Stack(int capacity=10)
	{
		_capacity = capacity;
		_top = 0;
		_s = (int*)malloc(sizeof(int)*_capacity);
	}
private:
	int _top;//栈顶元素的位置
	int _capacity;//容量
	int* _s;//栈
};
class test
{
public:
private:
	Stack s1;
	Stack s2;
	int a;
};
int main()
{
	test t1;
}

可以看的出来,test我并没有创建属于它的析构函数,但它自己就去调用了它的自定义类型成员的默认构造函数,使得对应的数据被初始化。有细心的同学可以发现,a也被初始化了,它不应该是随机值吗?我没对它处理啊,是的,它就应该是随机值,但是博主使用的是vs2019这个编译器进行代码的编写,它过于先进了,直接就帮博主优化了,因此看不出现象,而在vs2013写这串代码,这个变量就应该是随机值。感兴趣的小伙伴可以试一下。

二、析构函数

1.为什么要有析构函数?

讲完了构造函数,那么我们就来讲一下析构函数,既然构造函数是令类创建的时候初始化,那么析构函数则是在类的生命域结束的时候将目标清理,也就是destroy,比方说,我们写了一个顺序表,它malloc了一大块空间,那么我们在程序结束之前就应该将这一大块malloc的空间释放掉,避免造成内存泄漏,因此我们需要destroy函数来对一些类进行处理。但还是那句话,写了但忘记用,是常有的事情。因此在C++中,就诞生了一个函数,它就是析构函数,它能够令对应的类出了它的生命域便销毁,从而保证了安全性。

2.析构函数的特性

1. 析构函数名是在类名前加上字符 ~。 2. 无参数无返回值类型。 3. 一若未显式定义,系统会自动生成默认的析构函数。注意:析构函数不能重载 4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。

先来说下第一点,第一点很好理解,就是在类之前在个波浪号~,第二点和构造函数差不多,但更严格,它连参数都不能有,第三点则表示一个类只能有一个析构函数

3.使用析构函数

拿栈来举例

代码语言:javascript
复制
#include<iostream>
#include<stdlib.h>
using namespace std;
class Stack
{
public:
	Stack(int capacity=10)
	{
		_capacity = capacity;
		_top = 0;
		_s = (int*)malloc(sizeof(int) * _capacity);
	}
	~Stack()
	{
		free(_s);
		_s = nullptr;
		_top = 0;
		_capacity = 0;
		cout << "以下为调用析构函数结果" << endl;
		cout << _s << endl;
		cout << _capacity << endl;
		cout << _top << endl;
	}
	void print()
	{
		cout << _s <<endl;
		cout << _capacity << endl;
		cout << _top << endl;
	}
private:
	int* _s;
	int _capacity;
	int _top;
};
int main()
{
	Stack s1;
	s1.print();
}

三、下期预告

下回我们来聊一下拷贝构造函数,运算符重载QAQ

好了,今天的分享到这里就结束了,感谢各位友友的来访和阅读,祝各位友友们前程似锦O(∩_∩)O

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2023-11-03,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、构造函数
    • 1.1为什么要有构造函数?
      • 1.2构造函数的特性
        • 1.3使用构造函数
          • 1.4内置类型和自定义类型在构造方面的细节
          • 二、析构函数
            • 1.为什么要有析构函数?
              • 2.析构函数的特性
                • 3.使用析构函数
                • 三、下期预告
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档