c++之构造函数,析构函数(五千字长文详解!)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++之构造函数,析构函数(五千字长文详解!)相关的知识,希望对你有一定的参考价值。

c++之类和对象——构造函数,析构函数

类的六个默认成员函数

如果一个类中什么成员都没有,简称为空类。

空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。

默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

class date
;

构造函数

构造函数特征

  1. 函数名与类名相同。

  2. 无返回值。//甚至连void类型都不是!

  3. 对象实例化时编译器==自动调用==对应的构造函数。

  4. 构造函数可以重载。//函数名相同参数不同

    可以提供多个构造函数多种初始化方式!

class date

public:

	date(int year, int month, int day)//构造函数没有返回值!类型名就是函数名!
	
		cout << "Iint success!" << endl;
		_year = year;
		_month = month;
		_day = day;
	
    date()//构造函数支持函数重载!
	
		cout << "Iint success!" << endl;
		_year = 1;
		_month = 1;
		_day = 1;
	
    //既可以传参也可以不传参!
    
    /*	
    date(int year = 1, int month = 1, int day = 1)//构造函数没有返回值!类型名就是函数名!
	
		cout << "Iint success!" << endl;
		_year = year;
		_month = month;
		_day = day;
	我们同时也要注意函数重载和缺省值使用的时候避免调用函数的二义性!
	全缺省和无参函数同时存在会出现二义性
    */

private:
	int _year;
	int _month;
	int _day;
;


int main()

	date a(2000, 1, 1);
	date b;//在定义对象后悔自动的去调用!
	return 0;

**我们可以看到我们只是定义一个对象,但是构造函数却已经成功的调用了!**1

//关于无参的一个错误写法
date c();
//编译器不清楚这究竟是一个对象声明,还是一个函数声明!
//无参定义不可以加()

在c++下栈的写法

class stack

public:
	stack(int newcapcacity = 4)
	
		int* temp = (int*)malloc(sizeof(int) * newcapcacity);
		if (temp == nullptr)
		
			perror("malloc fail");
			exit(-1);
		
		_a = temp;
		_top = 0;
		_capacity = newcapcacity;
	
	void Push(int x)
	
		if (_top == _capacity)
		
			int newcapacity = 2 * _capacity;
			int* temp = (int*)realloc(_a, sizeof(int) * newcapacity);
			if (temp == nullptr)
			
				perror("realloc fail");
				exit(-1);
			
			_a = temp;
			_capacity = newcapacity;
		
		_a[_top++] = x;
	
private:
	int* _a;
	int _top;
	int _capacity;
;

int main()

	stack a;
	a.Push(1);
	a.Push(2);
	a.Push(3);
	a.Push(4);
	a.Push(5);
    //我们可以很明显的看出来方便了很多!
	return 0;

5.如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦 用户显式定义编译器将不再生成。(体现了默认特性!)

class date

public:
	void print()
	
		cout << _year << " " << _month << " " << _day << endl;
	
private:
	int _year;
	int _month;
	int _day;
;
int main()

	date A;
	A.print();
	return 0;

class A 

public:
    A()
    
        _a = 0;
        cout << "A()构造函数成功!" << endl;
    
private:
    int _a;
;
class Date

public:
    void print()
    
        cout << _year << "-" << _month << "-" << _day << endl;
    
private:
    //内置类型!
    int _year;
    int _month;
    int _day;
    //什么都没有做,只是增加了它的一个自定义类型!
    A _aa;
;
int main()

    Date A;
    A.print();
    return 0;

我们可以看出来虽然依旧没有处理内置函数,但是自定义类型的aa的默认构造被成功调用了!被Date的默认构造函数成功的调用了!

那这个除了初始化自定义类型的成员函数还有什么意义呢?不是还是要写一个构造函数用来初始化自定义类型吗?而且这样还会导致默认构造函数无法生成去调用自定义类型默认构造函数去初始化,这样不就是都要重写吗?这有什么意义呢?

例如下面这种类型:

class stack

public:
	stack(int newcapcacity = 4)
	
		int* temp = (int*)malloc(sizeof(int) * newcapcacity);
		if (temp == nullptr)
		
			perror("malloc fail");
			exit(-1);
		
		_a = temp;
		_top = 0;
		_capacity = newcapcacity;
	
	~stack()//这就是栈的析构函数!
	
		free(_a);
		_a = nullptr;
		_top = 0;
		_capacity = 0;
	
	void Push(int x)
	
		if (_top == _capacity)
		
			int newcapacity = 2 * _capacity;
			int* temp = (int*)realloc(_a, sizeof(int) * newcapacity);
			if (temp == nullptr)
			
				perror("realloc fail");
				exit(-1);
			
			_a = temp;
			_capacity = newcapacity;
		
		_a[_top++] = x;
	
private:
	int* _a;
	int _top;
	int _capacity;
;

class MyQuene

public:
	void Push(int x)
	
		_PushST.Push(x);
	
    //......剩下读者可以加自己实现
private:
	stack _PopST;
	stack _PushST;
;
int main()

	MyQuene mq;
	mq.Push(1);
	mq.Push(2);

	return 0;


我们可以看出mq完全不需要写构造函数,因为默认构造函数已经够用了!mq的默认构造函数去调用了stack的默认构造函数去初始化了!mq的两个变量!所以完全不需要自己去写构造函数

==那如果遇到要同时使用自定义类型和内置类型又想要使用默认构造去初始化自定义类型的时候我们应该怎么办?==

==答案是可以使用缺省值!==

class stack

    //....

class MyQuene

public:
	void Push(int x)
	
		_PushST.Push(x);
	
    //......剩下读者可以加自己实现
private:
	stack _PopST;
	stack _PushST;
    int a = 10;//答案是可以使用缺省值!这里不是初始化!
;

class Date

public:
    Date(int year = 1, int month = 1, int day = 1)
    
        _year = year;
        _month = month;
        _day = day;
    
private:
    int _year = 0;
    int _month = 0;
    int _day = 0;
;
//用时有缺省值和构造函数的话,还是以构造函数为主!

默认构造函数

class Date

public:
    Date(int year = 1, int month = 1, int day = 1)
    
        _year = year;
        _month = month;
        _day = day;
    
    Date()
    
        _year = 1;
        _month = 1;
        _day = 1;
    
private:
    int _year = 0;
    int _month = 0;
    int _day = 0;
;
int main()

    Date a;
	return 0;

class Date

public:
    Date(int year, int month = 1, int day = 1)
    
        _year = year;
        _month = month;
        _day = day;
    
private:
    int _year = 0;
    int _month = 0;
    int _day = 0;
;
int main()

    Date a;
	return 0;

因为已经自己写了显性的构造函数所以编译器不会自动生成的默认构造函数,但是又不是无参或者全缺省,导致了不存在默认构造函数!

class stack

public:
	stack(int newcapcacity)
	
		int* temp = (int*)malloc(sizeof(int) * newcapcacity);
		if (temp == nullptr)
		
			perror("malloc fail");
			exit(-1);
		
		_a = temp;
		_top = 0;
		_capacity = newcapcacity;
	
    //...
private:
	int* _a;
	int _top;
	int _capacity;
;

class MyQuene

public:
	void Push(int x)
	
		_PushST.Push(x);
	
    //......剩下读者可以加自己实现
private:
	stack _PopST;
	stack _PushST;
;
int main()

	MyQuene mq;
	mq.Push(1);
	mq.Push(2);

	return 0;

这种情况虽然MyQuene自身会生成默认构造函数,但是stack类没有默认构造也会导致这个问题!

如果我们不写stack的构造函数初始化仅仅使用编译器生成的默认构造函数,我们可以使用==全缺省==

class stack

private:
	//int* _a = nullptr;
    int* _a = (int*)malloc(sizeof(int)*4);//也可以使用的malloc!但是其实它现在不会去调用!只有使用的时候才会调用!
	int _top = 0;
	int _capacity = 0;
;

class MyQuene 

public:
	void Push(int x)
	
		_PushST.Push(x);
	
    //......剩下读者可以加自己实现
private:
	stack _PopST;
	stack _PushST;
;

析构函数

通过前面构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的? 析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由编译器完成的。而对象在销毁时会自动调用析构函数,完成==对象中资源==的清理工作。

析构函数的特征

析构函数是特殊的成员函数,其特征如下

  1. 析构函数名是在类名前加上字符 ~。(按位取反,就是要告诉你和构造函数的功能是相反的!)
  2. ==无参数无返回==值类型。(没有参数意味着也==不支持重载==!只有多个参数才支持重载!)
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构 函数不能重载
  4. ==对象生命周期结束时==,C++编译系统系统==自动调用析构函数==
class stack

public:
	stack(int newcapcacity = 4)
	
		int* temp = (int*)malloc(sizeof(int) * newcapcacity);
		if (temp == nullptr)
		
			perror("malloc fail");
			exit(-1);
		
		_a = temp;
		_top = 0;
		_capacity = newcapcacity;
	
	~stack()//这就是栈的析构函数!
	
		free(_a);
		_a = nullptr;
		_top = 0;
		_capacity = 0;
		cout << "destructor success!" << endl;
	//完成的资源清理工作!
	void Push(int x)
	
		if (_top == _capacity)
		
			int newcapacity = 2 * _capacity;
			int* temp = (int*)realloc(_a, sizeof(int) * newcapacity);
			if (temp == nullptr)
			
				perror("realloc fail");
				exit(-1);
			
			_a = temp;
			_capacity = newcapacity;
		
		_a[_top++] = x;
	
private:
	int* _a;
	int _top;
	int _capacity;
;

int main()

	stack a;
	stack b;
    //a,b出了函数作用域就销毁!就是main函数!
    //出了之后会自动调用析构函数!主要用于销毁第三类由malloc生成的变量!
    //像是日期类就不用析构函数了,但是非要写一个是允许的!
	return 0;

  1. 如果类中没有显式定义析构函数,则C++编译器会自动生成一析构函数,一旦 用户显式定义编译器将不再生成。(体现了默认特性!)
class A

public:
	~A()
	
		free(_a);
		cout << "A()析构函数成功!" << endl;
	
	A()
	
		_a = (int*)malloc(sizeof(int) * 4);
	
private:
	int* _a;
;


class date

public:
	void print()
	
		cout << _year << " " << _month << " " << _day << endl;
	
private:
	int _year;
	int _month;
	int _day;
	A _aa;
;

以上是关于c++之构造函数,析构函数(五千字长文详解!)的主要内容,如果未能解决你的问题,请参考以下文章

c++之引用(五千字长文详解!)

拷贝构造,赋值运算符重载(六千字长文详解!)

c++之类和对象——类的定义,存储方式,this指针!(五千字长文详解!)

STL之list底层简单实现(七千字长文详解!)

五千字长文详解Istio实践之熔断和限流工作原理

初步认识c++之命名空间详解(千字长文带你刨析你命名空间的细节)