C++类与对象(构造函数以及析构函数)

目录

类的六个默认成员函数

1.构造函数

2.析构函数

本篇讲述上述两种默认成员函数。

当我们创建一个空类时,里面真的什么都没有吗?不是的,任何一个类,在我们不写的情况下,都会自动生成下面6个默认成员函数
1.构造函数:主要完成类成员初始化
2.析构函数:主要完成清理资源工作
3.拷贝构造函数:用已经存在的一个对象,初始化创建另一个同类的对象
4.赋值重载函数:把一个对象赋值给另一个对象
5.取地址重载:取普通对象地址
6.取地址重载:取const对象地址

构造函数

我们看下面这个类

class A1
{
public:
	void set(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
	void display()
	{
		cout<<this->_a<<" "<<this->_b<<endl;
	}
private:
	int _a;
	double _b;
};
int main()
{
	A1 A,B;
	A.set(10,10.5);
	B.set(15,15.5);
	A.display();
	B.display();
}

我们可以通过set这个共有的成员函数给每个对象赋值,但是,如果没创建一个对象都用该函数赋值的话,就会很麻烦,如果在对象创建的时候,就直接赋值给这个对象,那么便十分简单,这里便有了构造函数

构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,保证每个数据成员 都有 一个合适的初始值,并且在对象的生命周期内只调用一次
对于上面的类我们用构造函数写出,如下:

class A1
{
public:
	// void set(int a = 1,double b = 0.1)
	// {
	// 	_a = a;
	// 	_b = b;
	// }
	//带参构造函数
	A1(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
	void display()
	{
		cout<<this->_a<<" "<<this->_b<<endl;
	}
private:
	int _a;
	double _b;
};
int main()
{
	A1 A(2,2.6);//对象A中_a=2,_b=2.6
	A1 B;//通过构造函数对象B中_a=1,_b=0.1
}

上面是我们显式定义的构造函数,如果不显式定义,我们也可以成功创建一个对象,并且通过类的默认构造函数为我们初始化这个对象,只不过对象成员变量为随机值。如下图:
C++类与对象(构造函数以及析构函数)_第1张图片
构造函数也可以重载,即无参构造函数和带参构造函数

class A1
{
public:
	A1()
	{}
	//带参构造函数
	A1(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
	void display()
	{
		cout<<this->_a<<" "<<this->_b<<endl;
	}
private:
	int _a;
	double _b;
};
int main()
{
	A1 A(2,2.6);//调用带参构造
	A1 B;//调用无参构造
}

这里需要注意,如果调用无参函数时,对象后面不能加(),如果加上(),就称为申明一个函数,比如还是上述类

int main()
{
	A1 A(2,2.6);//调用带参构造
	A1 B;//调用无参构造
	//下面定义相当于申明了一个C函数,它的返回值为A1类型的对象
	A1 C();
}

有人会说,类的默认构造函数,初始化的话也是随机值,还不如自己写构造函数,那么构造函数有什么好处呢?
C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语法已经定义好的类型:如 int/char…,自定义类型就是我们使用class/struct/union自己定义的类型,看看下面的程序,就会发现 编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员函数

class A1
{
public:
	//带参构造函数
	A1(int a = 1,double b = 0.1)
	{
		_a = a;
		_b = b;
	}
	void display()
	{
		cout<<this->_a<<" "<<this->_b<<endl;
	}
private:
	int _a;
	double _b;
};
class A2
{
private:
	//内置类型
	int _a;
	double _b;
	//自定义类型
	A1 _t;
};

构造函数总结:

  1. 函数名与类名相同。
  2. 无返回值。
  3. 对象创建时编译器自动调用对应的构造函数。
  4. 构造函数可以重载
  5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成
  6. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个
  7. 成员变量的命名风格,为了区别成员变量和函数形参,通常会在成员变量前加 “_”

析构函数

有了初始话的函数,也就会有清理资源的函数,这就有了析构函数
析构函数与构造函数类似,不过析构函数的函数名是类名前加上~,比如

class A1
{
public:
	~A1()//析构函数
	{}
	void display()
	{
		cout<<this->_a<<" "<<this->_b<<endl;
	}
private:
	int _a;
	double _b;
};

类中默认的析构函数是释放不了资源的,只有我们显式定义析构函数,才能释放堆上的资源,比如:

class A1
{
public:
	A1(int* a)
	{
		_a = a;
		_a = (int*)malloc(sizeof(int)*10);//开辟资源空间
	}
	~A1()//通过析构函数释放资源空间
	{
		if(_a)
		{
			free(_a);
			_a = NULL;
		}
	}
private:
	int *_a;
	double _b;
};

析构函数总结:

  1. 析构函数名是在类名前加上字符 ~。
  2. 无参数无返回值。
  3. 一个类有且只有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
  5. 与构造函数一样,编译器生成的默认析构函数,对会自定类型成员调用它的析构函数

你可能感兴趣的:(C++,c++,类)