C++:构造函数以及析构函数

构造函数以及析构函数

  • 对象初始化和清理
  • 构造函数以及析构函数
  • 构造函数的分类
    • 括号法
    • 显示法
    • 隐式转换法
    • 匿名对象
  • 拷贝构造函数的调用时机
  • 构造函数的调用规则
  • 深拷贝和浅拷贝
  • 初始化列表
  • 类对象作为类成员
  • 静态成员

对象初始化和清理

C++面向对象来源于生活,每个对象都会有初始化设置以及对象销毁前的清理数据的设置

构造函数以及析构函数

对象的初始化和清理是非常重要的安全问题

  • 一个对象或者变量没有初始化状态,对其使用后果也是未知
  • 使用完一个对象或者变量,没有及时清理,也会造成一定的安全问题

构造函数主要用于创造对象时为对象的成员属性赋值,构造函数由编译器自动调用,无需手动调用
析构函数主要用于销毁前系统自动调用,执行一些清理工作

构造函数语法:类名()

  • 构造函数 没有返回值 也不写void
  • 函数名称和类名相同
  • 构造函数可以有参数,因此可以发生重载
  • 程序在调用对象时自动调用构造函数,无需手动调用,且只会调用一次

析构函数语法:~类名()

  • 析构函数,没有返回值也不写void
  • 函数名称是在类名前加~
  • 析构函数不可以有参数 因此不能发生重载
  • 程序在对象销毁时自动调用析构函数,无需手动调用,且只会调用一次
#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class student
{
public:
	student();
	~student();
};
student::student(){
	cout << "构造函数" << endl;
}
student::~student() {
	cout << "析构函数" << endl;
}
int main()
{	
	student stu;

	system("pause");
	return 0;
}

C++:构造函数以及析构函数_第1张图片

构造函数的分类

两种分类方式:

  • 按参数:有参构造和无参构造
  • 按类型:普通构造和拷贝构造

三种调用方式:

  • 括号法
  • 显示法
  • 隐式转换法

调用默认构造的时候不要写括号()系统会默认成是函数的
不要利用拷贝构造函数初始化匿名对象 编译器会认为 类名(p3) ==person p3

括号法

#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class student
{
public:
	student();//无参构造
	student(int age);//有参构造
	student(const student&b);//拷贝构造
	~student();
};
student::student()
{
	cout << "无参构造" << endl;
}
student::student(int age)
{
	cout << "有参构造" << endl;
}
student::student(const student&b)
{
	cout << "拷贝构造" << endl;
}
student::~student()
{
	cout << "析构函数" << endl;
}

int main()
{	
	/*括号法*/
	student stu1;
	student stu2(18);
	student stu3(stu2);
	system("pause");
	return 0;
}

C++:构造函数以及析构函数_第2张图片

显示法

#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class student
{
public:
	student();//无参构造
	student(int age);//有参构造
	student(const student&b);//拷贝构造
	~student();
};
student::student()
{
	cout << "无参构造" << endl;
}
student::student(int age)
{
	cout << "有参构造" << endl;
}
student::student(const student&b)
{
	cout << "拷贝构造" << endl;
}
student::~student()
{
	cout << "析构函数" << endl;
}

int main()
{	
	/*显示法*/
	student stu1;
	student stu2 = student(18);
	student stu3 = student(stu2);
	system("pause");
	return 0;
}

C++:构造函数以及析构函数_第3张图片

隐式转换法

#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class student
{
public:
	student();//无参构造
	student(int age);//有参构造
	student(const student&b);//拷贝构造
	~student();
};
student::student()
{
	cout << "无参构造" << endl;
}
student::student(int age)
{
	cout << "有参构造" << endl;
}
student::student(const student&b)
{
	cout << "拷贝构造" << endl;
}
student::~student()
{
	cout << "析构函数" << endl;
}

int main()
{	
	/*隐式转换法*/
	student stu1;
	student stu2 = 10;
	student stu3 = stu2;
	system("pause");
	return 0;
}

C++:构造函数以及析构函数_第4张图片

匿名对象

匿名对象的意思就是当执行结束后系统立马收回

#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class student
{
public:
	student();//无参构造
	student(int age);//有参构造
	student(const student&b);//拷贝构造
	~student();
};
student::student()
{
	cout << "无参构造" << endl;
}
student::student(int age)
{
	cout << "有参构造" << endl;
}
student::student(const student&b)
{
	cout << "拷贝构造" << endl;
}
student::~student()
{
	cout << "析构函数" << endl;
}

int main()
{	
	/*匿名对象*/
	student(1);
	system("pause");
	return 0;
}

C++:构造函数以及析构函数_第5张图片

拷贝构造函数的调用时机

调用时机

  • 使用一个已经穿件完毕的对象来初始化一个新的对象
  • 以值传递的方式给函数参数传值
  • 以值方式返回局部对象
#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class student
{
public:
	student();//无参构造
	student(int age);//有参构造
	student(const student&b);//拷贝构造
	~student();
};
student::student()
{
	cout << "无参构造" << endl;
}
student::student(int age)
{
	cout << "有参构造" << endl;
}
student::student(const student&b)
{
	cout << "拷贝构造" << endl;
}
student::~student()
{
	cout << "析构函数" << endl;
}

void test1(student stu)
{

}
student test2()
{
	student stu;
	cout << &stu << endl;
	return stu;
}
int main()
{	
	/*使用一个已经创建完毕的对象来初始化一个新对象*/
	student stu(18);
	student stu1(stu);
	/*以值传递的方式给函数传递值*/
	test1(stu);
	/*以值的方式返回局部对象*/
	student stu2 = test2();
	cout << &stu2 << endl;
	system("pause");
	return 0;
}

C++:构造函数以及析构函数_第6张图片
上面的代码输出的地址也表示了 拷贝构造函数是拷贝一个新的构造函数,所以地址会不同

构造函数的调用规则

默认情况下,c++编译器至少给1个类添加3个函数

  • 默认构造函数(无参,函数体为空)
  • 默认析构函数(无参,函数体为空)
  • 默认拷贝构造函数,对属性进行值拷贝

构造函数调用规则:

  • 如果用户定义有参构造函数,c++不提供默认无参构造函数,但依然会提供默认拷贝构造
  • 如果用户定义拷贝构造函数,c++不会再提供其他构造函数

下面几张截图就可以充分说明上述构造函数调用规则:
1. 只定义有参构造,声明无参构造会报错 声明拷贝构造不会报错
C++:构造函数以及析构函数_第7张图片

2. 只定义拷贝构造,声明无参构造和有参构造都会报错
C++:构造函数以及析构函数_第8张图片

3. 定义了无参构造和有参构造,声明拷贝构造不会报错
C++:构造函数以及析构函数_第9张图片

深拷贝和浅拷贝

浅拷贝:简单的赋值拷贝操作
深拷贝:在堆区重新申请空间,进行拷贝操作

先把代码放上来,然后说一下区别

#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class student
{
public:
	int age;
	int *hight;
	student();//无参构造
	student(int xage,int xhight);//有参构造
	student(const student&b);//拷贝构造
	~student();
};
student::student()
{
	cout << "无参构造" << endl;
}
student::student(int xage, int xhight)
{
	age = xage;
	hight = new int(xhight);
	cout << "有参构造" << endl;
}
student::student(const student&b)
{
	cout << "拷贝构造" << endl;
	age = b.age;
	hight = b.hight;//浅拷贝
	hight = new int(*b.hight);//深拷贝
}
student::~student()
{
	if (hight != NULL)
	{
		delete hight;
		hight = NULL;
	}
	cout << "析构函数" << endl;
}

int main()
{	
	student stu(18, 180);
	cout << stu.age << endl;
	cout << stu.hight << endl;
	student stu1(stu);
	cout << stu1.age << endl;
	cout << stu1.hight << endl;
	system("pause");
	return 0;
}

上面代码不可直接使用,在深拷贝和浅拷贝哪里应该要注释一个,现在我来贴出不同情况下运行后的结果
浅拷贝
C++:构造函数以及析构函数_第10张图片
深拷贝
C++:构造函数以及析构函数_第11张图片
首先肯定的是,这个代码在浅拷贝的时候运行出错了。首先我们可以看到,拷贝之后的heigh的地址指向的是一样。那么在程序结束的时候,析构函数会delete这个指针,但是由于浅拷贝中hight中2个函数指向的地址一样,所以析构函数相当于delete一个相同的指针2次,那么必然会出错的。
深拷贝是自己在堆区重新开辟的一个新的空间,自然而然2个hight指向的地址不是一个,这个我们打印的结果也看到了,所以在析构函数释放的时候自然不会报错

初始化列表

前面我们写的代码中有参构造,都是在函数内部实现属性和形参的赋值
这个初始化列表作用就是C++提供了初始化列表语法,用来初始化属性
语法:槽函数():属性1(值1)属性2(值2)

传统方式

#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class student
{
public:
	int a, b, c;
	student(int xa,int xb,int xc);//有参构造
	//student(int xa, int xb, int xc) :a(xa), b(xb), c(xc)
	//{}
	~student();
};

student::student(int xa, int xb, int xc)
{
	a = xa;
	b = xb;
	c = xc;
	cout << "有参构造" << endl;
}

student::~student()
{
	cout << "析构函数" << endl;
}

int main()
{	
	student stu(1, 2, 3);
	cout << stu.a << endl;
	cout << stu.b << endl;
	cout << stu.c << endl;
	system("pause");
	return 0;
}

初始化列表

#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class student
{
public:
	int a, b, c;
	//student(int xa,int xb,int xc);//有参构造
	student(int xa, int xb, int xc) :a(xa), b(xb), c(xc)
	{}
	~student();
};

//student::student(int xa, int xb, int xc)
//{
//	a = xa;
//	b = xb;
//	c = xc;
//	cout << "有参构造" << endl;
//}

student::~student()
{
	cout << "析构函数" << endl;
}

int main()
{	
	student stu(1, 2, 3);
	cout << stu.a << endl;
	cout << stu.b << endl;
	cout << stu.c << endl;
	system("pause");
	return 0;
}

类对象作为类成员

C++中类的成员可以是另外一个类,我们称改成员为对象成员
当其他类对象作为本类成员,构造时候要先构造对象,在构造自身
析构函数刚好相反

#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class phone
{
public:
	string phonename;
	phone(string a)
	{
		phonename = a;
		cout << "phone 的构造函数" << endl;
	}
	~phone()
	{
		cout << "phone 的析构函数" << endl;
	}
};
class student
{
public:
	string name;
	phone phones;
	student(string xname, string xphone):name(xname),phones(xphone)
	{
		cout << "student 的构造函数" << endl;
	}
	~student()
	{
		cout << "student 的析构函数" << endl;
	}
};


int main()
{	
	student stu("张三","华为");
	system("pause");
	return 0;
}

C++:构造函数以及析构函数_第12张图片

静态成员

静态成员就是在成员变量和成员函数前加关键字static

静态成员变量

  • 所有对象共享一份数据
  • 在编译阶段分配内存
#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class student
{
public:
	static int age;
};
int student::age = 18;

int main()
{	
	student stu1;
	cout << stu1.age << endl;

	student stu2;
	stu2.age = 20;
	cout << stu1.age << endl;

	cout << &stu1.age << endl;
	cout << &stu2.age << endl;
	system("pause");
	return 0;
}

C++:构造函数以及析构函数_第13张图片

访问方式:

  1. 通过对象访问
  2. 通过类名访问
  3. 静态成员访问权限私有情况下也访问不到C++:构造函数以及析构函数_第14张图片

类内声明,类外初始化

  • 静态成员函数
  • 所有对象共用一个函数
  • 静态成员函数只能访问静态成员变量
  • 静态成员函数权限是私有的也无法访问到
    C++:构造函数以及析构函数_第15张图片
    C++:构造函数以及析构函数_第16张图片
#include 
#include 
#include //c++中字符串需要添加这个头文件
#include 
using namespace std;

class student
{
public:
	static int age;
	static void fun1()
	{
		age = 200;
	}
private:
	static void fun2()
	{
	}
};
int student::age = 18;

int main()
{	
	student stu1;
	cout << stu1.age << endl;
	student::fun1();
	cout << stu1.age << endl;
	system("pause");
	return 0;
}

C++:构造函数以及析构函数_第17张图片

你可能感兴趣的:(C++,c++,mfc,visual,studio)