首页 > 编程语言 >C++——构造函数和析构函数

C++——构造函数和析构函数

时间:2024-08-13 11:26:18浏览次数:15  
标签:函数 对象 C++ class 和析构 public 构造函数

一、初识构造函数和析构函数

简单来说,有对象生成必然会调用构造函数,有对象销毁必然会调用析构函数。构造函数的作用是初始化成员变量,是由编译器去调用的,而析构函数同理也是由编译器调用,不过他的作用则是清理。可以由下面的代码体验两个函数的使用。

注意:

相同点:两个函数都没有返回值,不能用void

不同点:构造函数可以有参数,析构函数没有参数

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
	M() {//无参构造
		a = 101;
		cout << "构造函数执行" << endl;
	}
	~M()//在对象销毁前,编译器调用析构函数
	{
		cout << "析构函数执行" << endl;
	}
	int a;
};

void fun() {
	M m;
	int b = m.a;
	cout << b << endl;
}

class M2 {
public:
	//有参构造
	M2(const char *name,int age){
		cout << "有参构造" << endl;
		//从堆区空间申请
		pName = (char*)malloc(strlen(name) + 1);
		strcpy(pName,name);
		mAge = age;
	}
	void Print() {
		cout << "name=" << pName << endl;
		cout << "age=" << mAge << endl;

	}
	~M2()
	{
		cout << "析构函数执行" << endl;
		//释放堆区空间
		if (pName != NULL) {
			pName = NULL;
		}
		if (mAge != NULL) {
			mAge = NULL;
		}
	}
private:
	char* pName;
	int mAge;
};

void fun2() {
	M2 m2("卡卡",14);
	m2.Print();
}
int main() {
	
	fun();
	M m;
	cout << "***********" << endl;
	
	fun2();
	system("pause");
	return EXIT_SUCCESS;
}

运行结果:

  1. 构造函数可以重载

class M3 {
public:
	M3() {

	}
	M3(int a) {

	}
};

 2.当构造函数私有时,无法实例化对象,所以构造函数和析构函数都是公有的

class M3 {
//public:
private:
	M3() {

	}
	M3(int a) {

	}
};
void fun3() {
	M3 m3;//该行会报错
}

补充:实例化对象的时候内部操作:1.分配空间(将对象m分配到栈区)2.调用构造函数进行初始化

二、默认的构造函数和析构函数 

        现在我们已经简单了解了构造函数和析构函数,但当我们在声明类的时候没有声明这两个函数,那我们在实例化一个对象的时候还会有这两个函数的事情吗?

        答案是有的。

        前面的学习我们知道,构造函数和析构函数是由编译器去调用的,所以当我们没有声明他们的情况下,编译器会去提供默认的构造函数和析构函数。如下面的例子,程序运行可以打印a=100

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
	void pfun() {
		a = 100;
		cout << "a=" << a << endl;
	}
private:
	int a;
};

void fun() {
	M m;
	m.pfun();
}
int main() {
	
	fun();
	system("pause");
	return EXIT_SUCCESS;
}

        而所提供的默认的构造函数和析构函数的函数体是空的。

三、拷贝构造


用一个已有的对象去初始化另一个对象

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
	M() {
		cout << "M的无参构造函数" << endl;
		a = 10;
	}
	M(const M& t) {
		cout << "拷贝构造函数" << endl;
		a = t.a;
	}
	void printinform() {
		cout << "a=" <<a<< endl;
	}
private:
	int a;
};


void fun() {
	M m;
	m.printinform();
	M t(m);//用一个已有的对象去初始化另一个对象
	t.printinform();
}
int main() {
	
	fun();
	system("pause");
	return EXIT_SUCCESS;
}

运行结果:

相信大家这时候会注意到,在拷贝构造函数那里,我们用到了const和&。

const是为了保证其值不会改变,这里可有可没有,而&在这里表示的是引用。为了看出引用的的作用,我们可以在这里先去掉&,这个时候会发现编译器报错。

下面情况下,当对象以值的方式给函数参数时,调用的也是拷贝函数

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
	M(int x) {
		cout << "M的有参构造函数" << endl;
	}
	M() {
		cout << "M的无参构造函数" << endl;
	}
	M(const M& t) {
		cout << "拷贝构造函数" << endl;
	}
	~M()
	{
		cout << "析构函数" << endl;
	}

};

void f0(M x) {//对象以值的方式给函数参数

}

void fun() {
	M m;
	f0(m);//对象以值的方式给函数参数
	
}
int main() {
	
	fun();
	system("pause");
	return EXIT_SUCCESS;
}

 运行:

另外,拷贝构造也可以这样调用,但不常用

M t = m;

注意区别赋值操作和拷贝构造

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
	M() {
		cout << "M的无参构造函数" << endl;
		a = 10;
	}
	M(const M& t) {
		cout << "拷贝构造函数" << endl;
		a = t.a;
	}
	void printinform() {
		cout << "a=" <<a<< endl;
	}
private:
	int a;
};


void fun() {
	M m;
	m.printinform();
	M t(m);//用一个已有的对象去初始化另一个对象
	t.printinform();
	M t2;
	t2 = t;//赋值操作!!!!
	t2.printinform();

	
}
int main() {
	
	fun();
	system("pause");
	return EXIT_SUCCESS;
}

可见,构造函数大概分成了以下三种。

有了拷贝构造,那么编译器提供的默认构造函数和之前有什么区别呢?

四、构造函数的调用

1.如果提供了有参构造,编译器不会提供默认构造函数,但会提供拷贝构造函数

2.如果提供了拷贝构造函数,那么编辑器不会提供默认的构造函数和默认的拷贝构造函数

五、类中有多个对象的函数调用情况

当在一个类中有多个其他类声明对象的情况下,构造函数和析构函数又是怎样调用呢?

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class A {
public:

	A() {
		cout << "A的无参构造函数" << endl;
	}
	A(const A& t) {
		cout << "A的拷贝构造函数" << endl;
	}
	~A()
	{
		cout << "A的析构函数" << endl;
	}
};
class B {
public:

	B() {
		cout << "B的无参构造函数" << endl;
	}
	B(const B& t) {
		cout << "B的拷贝构造函数" << endl;
	}
	~B()
	{
		cout << "B的析构函数" << endl;
	}
};
class M {
public:
	M(int x) {
		cout << "M的有参构造函数" << endl;
	}
	M() {
		cout << "M的无参构造函数" << endl;
	}
	M(const M& t) {
		cout << "M的拷贝构造函数" << endl;
	}
	~M()
	{
		cout << "M的析构函数" << endl;
	}
	
private:
	A m1;
	B m2;
};


void fun() {
	M m;
}
int main() {
	fun();
	system("pause");
	return EXIT_SUCCESS;
}

 

由此可见,当对象m运行时候,先是按照顺序运行 m内声明的对象a和b,分别调用其构造函数,并按照栈的顺序调用析构函数

六、匿名对象

匿名对象就是没有给根据类声明的对象命名,如有一个类M,

M();(而不像之前声明实例对象M m)便是一个匿名对象

而匿名对象的生命周期与之前的不同,该周期是在当先行,对比下面代码的匿名对象和m对象的运行结果。

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
using namespace std;
class M {
public:
	M(int x) {
		cout << "M的有参构造函数" << endl;
		a = 10;
	}
	M() {
		cout << "M的无参构造函数" << endl;
		a = 10;
	}
	M(const M& t) {
		cout << "拷贝构造函数" << endl;
		a = t.a;
	}
	~M()
	{
		cout << "析构函数" << endl;
	}
	void printinform() {
		cout << "a=" <<a<< endl;
	}
private:
	int a;
};


void fun() {
	M();//匿名对象
	cout << "1111111111111" << endl;
	cout << "******************************" << endl;
	M m;
	cout << "2222222222" << endl;
	
}
int main() {
	
	fun();
	system("pause");
	return EXIT_SUCCESS;
}

注意:匿名对象有名字的话,就不是匿名对象,如下面的m1

M m1 = M();

标签:函数,对象,C++,class,和析构,public,构造函数
From: https://blog.csdn.net/immnature/article/details/141093997

相关文章

  • 基于Dango+微信小程序的广西东盟旅游资源信息管理系统+80003(免费领源码)可做计算机毕业
    django广西-东盟旅游资源信息管理系统小程序摘 要在社会快速发展和人们生活水平提高的影响下,旅游产业蓬勃发展,旅游形式也变得多样化,使旅游资源信息的管理变得比过去更加困难。依照这一现实为基础,设计一个快捷而又方便的基于小程序的旅游资源信息管理系统是一项十分重要并且......
  • c++ 字符串转 整形
    目前有两种string 转整形的方式std::atoi(constchar*);std::stoi(conststd::string);atoi()是c语言风格,而stoi()是c++11标准库中新增的函数两者的区别在atoi()的参数是constchar*,所以我们必须将字符串的类型从string转换为constchar类型才能够转换为int。str......
  • C++:内存管理
    C++内存管理的概念        C语言内存管理方式(malloc/free)在C++中可以继续使用,但有些地方就无能为力,而且使用起来比较麻烦,因此C++又提出了自己的内存管理方式:通过new和delete操作符进行动态内存管理。new/delete                    new/d......
  • C++:类与对象(下)
    再探构造函数        构造函数体赋值与初始化列表其实之前我们实现构造函数时,初始化成员变量主要使⽤函数体内赋值,构造函数初始化还有⼀种⽅式,就是初始化列表,C++规定初始化列表的使⽤⽅式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成员列表,每个"成员变量"后⾯跟......
  • C++:类与对象(中)
    类的默认成员函数:        在C++中,如果你没有显式地定义某些特定的成员函数(如构造函数、析构函数、拷贝构造函数、拷贝赋值运算符和移动构造函数),那么编译器会自动生成这些函数。这些由编译器自动生成的函数被称为默认成员函数。        构造函数   ......
  • C语言和C++中的动态内存管理------malloc和free的区别
    引言:动态内存管理:需要根据具体情况来设定需要的内存大小,同时可能需要大于1Mbyte的连续空间。此时我们无法使用静态数组。原因是因为静态数据的开辟是在栈空间,其次栈空间的大小在连续分配时不能超过1Mbyte,因此引入了动态内存管理。C语言C语言中动态内存管理的有四个函数:mal......
  • SecureCoding in C and C++(二)
    经过上期的环境搭建过后,我们将正式的学习C++系列,首先要学习的是C++的一些常用的变量从编译和连接学起似乎也是不错的选择。个人总结的一句话:编译其实就是对预处理语句进行处理后,然后对语句进行处理。对预处理语句,例如:#include之类的处理方式其实就是将文件内容复制到对应......
  • C ++ 也可以搭建Web?高性能的 C++ Web 开发框架 CPPCMS + MySQL 实现快速入门案例
    什么是CPPCMS?CppCMS是一个高性能的C++Web开发框架,专为构建快速、动态的网页应用而设计,特别适合高并发和低延迟的场景。其设计理念类似于Python的Django或RubyonRails,但针对C++提供了更细粒度的控制和更高效的性能。主要特点和优点1.高性能与并发处理​Cp......
  • C++类和对象(类的定义)
    目录一·类的定义1.1类的定义格式1.2访问限定符(public、private、protected)1.3类域一·类的定义1.1类的定义格式定义类的关键字是class,类定义结束时,后面的分号不能省略。类体中的内容称为类的成员:①类中的变量称为类的属性或成员变量;②类中的函数称为类的方......
  • 【C++面向对象】泛型编程(模板) 新手小白都能懂!
    目录泛型编程是什么?模板和泛型编程的关系?函数模板定义调用类模板定义调用总结/小注泛型编程是什么?顾名思义,“泛型”即“广泛的类型”,即不拘泥于一种特定类型的编程方法。在泛型编程时,我们通常使用一个或多个类型占位符来表示一种或多种类型,这些类型对于模板而言......