构造和析构函数

目录

默认构造函数

构造函数与析构函数

构造函数的三种调用方法

为什么需要构造和析构函数

copy构造函数的调用时机

匿名对象的去和留

构造函数的调用规则研究


默认构造函数

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>

using namespace std;

class Test
{
public:
	//构造函数(构造器), 是为了给对象提供初始化而出现的。
	//函数名字跟类型是一样的,没有返回值,并且可以重载

	//无参数的构造函数
	Test()
	{
		m_x = 0;
		m_y = 0;
		p = (char*)malloc(100);
		strcpy(p, "123");
	}

	//带参数的构造函数
	Test(int x, int y)
	{
		m_x = x;
		m_y = y;
	}

	//一个参数的构造函数
	Test(int x)
	{
		m_x = x;
		m_y = 0;
	}


	//析构函数 : ~+类型  没有任何的参数
	~Test()
	{
		cout << "Test 的析构函数~Test() 被调用了" << endl;
		if (p != NULL) {
			cout << "p的堆空间被释放了" << endl;
			free(p);
			p = NULL;
		}
	}


	void printT()
	{
		cout << "x : " << m_x << ", y: " << m_y << endl;
	}

	void init(int x, int y)
	{
		m_x = x;
		m_y = y;
	}
private:
	int m_x;
	int m_y;
	char *p;
};

//给对象搭建一个舞台,研究对象的行为
void test1()
{
	Test t1; //调用无参数的构造函数
	//t1 是一个局部变量, 生命周期是test1()一样的, 在test1()函数执行完毕需要 先销毁t1变量
	//t1对象销毁之前,系统就会默认的调用t1的析构函数
	t1.printT();


	return;
}

int main(void)
{
	Test t1; //t1 在开辟内存之后,t1中的m_x  m_y 是随机值
	
	t1.init(10, 20); //每次都需要显示的调用一个初始化的函数。

	//能不能提供一个 在创建一个对象的时候就给他初始化呢?

//	test1();

	//Test t1;  //创建一个对象, 这个对象会直接调用无参数的构造函数。

	//Test t2(10, 20); //在创建对象完毕之后, 就已经将对象的一些成员变量初始化了

	//Test t3(10);

	return 0;
}

构造函数与析构函数

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>

using namespace std;

class Test
{
public:
	//默认构造函数。 就是一个无参数的构造函数,
	//如果不显示提供构造函数,系统就是调用默认的构造函数
	/*
	Test() {} 默认的构造函数,已经手动提供,默认就被隐藏
	*/

	//如果我们提供了一个显示的构造函数,那么默认的构造函数就被隐藏掉了。
	//构造函数一旦手动提供, 默认将不复存在。
	Test(int x, int y)
	{

		m_x = x;
		m_y = y;
		cout << "调用了有参数的构造函数" << endl;
	}

	//无参数的构造函数
	Test(){
		m_x = 0;
		m_y = 0;
		cout << "调用了无参数的构造函数" << endl;
	}


	//拷贝构造函数 ,想通过另一个Test对象 another 将本对象进行拷贝
	Test(const Test & another)
	{
		m_x = another.m_x;
		m_y = another.m_y;
		cout << "调用了拷贝构造函数" << endl;
	}

	//等号操作符
	void operator = (const Test &t)
	{
		m_x = t.m_x;
		m_y = t.m_y;
	}

	void printT()
	{
		cout << "x : " << m_x << ", y : " << m_y << endl;
	}

	//提供一个析构函数
	~Test()
	{
		cout << "~Test()析构函数被执行了" << endl;
		cout << "(" << m_x << ", " << m_y << ")" << "被析构了" << endl;
	}

private:
	int m_x;
	int m_y;
};

int main(void)
{
	Test t1; //调用无参的构造函数
	Test t2(10, 20);
	//Test t3(10, 20, 30);
	t2.printT();
	Test t3(t2); //调用t3的拷贝构造函数  //调用拷贝构造函数的方式
	t3.printT();
	//Test t4 = t2; // 依然是调用t4的拷贝构造函数,

	Test t4(100, 200); //调用t4 的两个参数的构造函数

	Test t5; //先调用无惨构造。
	t5 = t2; //不会调用拷贝构造函数 //调用=号重载操作符  赋值操作符


	//析构函数的调用顺序, 跟对象的构造顺序相反, 谁先构造,谁最后一个被析构。

	return 0;
}

构造函数的三种调用方法

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>

using namespace std;

class Test
{
public:
	//默认构造函数。 就是一个无参数的构造函数,
	//如果不显示提供构造函数,系统就是调用默认的构造函数
	/*
	Test() {} 默认的构造函数,已经手动提供,默认就被隐藏
	*/
	int value = 100;
	//如果我们提供了一个显示的构造函数,那么默认的构造函数就被隐藏掉了。
	//构造函数一旦手动提供, 默认将不复存在。
	Test(int x, int y)
	{

		m_x = x;
		m_y = y;
		cout << "调用了有参数的构造函数" << endl;
	}

	//无参数的构造函数
	Test(){
		m_x = 0;
		m_y = 0;
		cout << "调用了无参数的构造函数" << endl;
	}


	//拷贝构造函数 ,想通过另一个Test对象 another 将本对象进行拷贝
	Test(const Test & another)
	{
		m_x = another.m_x;
		m_y = another.m_y;
		cout << "调用了拷贝构造函数" << endl;
	}

	//等号操作符
	void operator = (const Test &t)
	{
		m_x = t.m_x;
		m_y = t.m_y;
	}

	void printT()
	{
		cout << "x : " << m_x << ", y : " << m_y << endl;
	}

	//提供一个析构函数
	~Test()
	{
		cout << "~Test()析构函数被执行了" << endl;
		cout << "(" << m_x << ", " << m_y << ")" << "被析构了" << endl;
	}

private:
	int m_x;
	int m_y;
};

int main(void)
{

	//Test t15();
	//cout << t15.value << endl;  //error写了(),就要有参数


	Test t1; //调用无参的构造函数
	Test t2(10, 20);
	//Test t3(10, 20, 30);
	t2.printT();
	Test t3(t2); //调用t3的拷贝构造函数  //调用拷贝构造函数的方式
	t3.printT();
	//Test t4 = t2; // 依然是调用t4的拷贝构造函数,

	Test t4(100, 200); //调用t4 的两个参数的构造函数

	Test t5; //先调用无参构造。
	t5 = t2; //不会调用拷贝构造函数 //调用=号重载操作符  赋值操作符


	//析构函数的调用顺序, 跟对象的构造顺序相反, 谁先构造,谁最后一个被析构。

	return 0;
}

为什么需要构造和析构函数

copy构造函数的调用时机

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>

using namespace std;

class Test
{
public:
	//默认构造函数。 就是一个无参数的构造函数,
	//如果不显示提供构造函数,系统就是调用默认的构造函数
	/*
	Test() {} 默认的构造函数,已经手动提供,默认就被隐藏
	*/

	//如果我们提供了一个显示的构造函数,那么默认的构造函数就被隐藏掉了。
	//构造函数一旦手动提供, 默认将不复存在。
	Test(int x, int y)
	{

		m_x = x;
		m_y = y;
		cout << "调用了有参数的构造函数" << endl;
	}

	//无参数的构造函数
	Test(){
		m_x = 0;
		m_y = 0;
		cout << "调用了无参数的构造函数" << endl;
	}


	//拷贝构造函数 ,想通过另一个Test对象 another 将本对象进行拷贝
	Test(const Test & another)
	{
		m_x = another.m_x;
		m_y = another.m_y;
		cout << "调用了拷贝构造函数" << endl;
	}

	//等号操作符
	void operator = (const Test &t)
	{
		cout << "调用了=号操作符" << endl;
		m_x = t.m_x;
		m_y = t.m_y;
	}

	void printT()
	{
		cout << "x : " << m_x << ", y : " << m_y << endl;
	}

	//提供一个析构函数
	~Test()
	{
		cout << "~Test()析构函数被执行了" << endl;
		cout << "(" << m_x << ", " << m_y << ")" << "被析构了" << endl;
	}

private:
	int m_x;
	int m_y;
};


//拷贝构造函数的第一个场景
void test1()
{
	Test t1(1, 2);
	Test t2(t1);
	//通过t1 给t2 进行赋值

	t2.printT();
}

//拷贝构造函数的第二场景
void test2()
{
	Test t1(1, 2);
	Test t2;
	t2 = t1; //调用的不是拷贝构造函数,调用的是 =号操作符,也能够完成将t1的值给t2 但不是调用t2的拷贝构造函数。
}


void func(Test t) //Test t = test1::t1; //会调用局部变量t的拷贝构造函数
{
	cout << "func begin..." << endl;
	t.printT();
	cout << "func end..." << endl;

}

//场景三
void test3()
{
	cout << "test3 begin ..." << endl;
	Test t1(10, 20); //创建了一个t1的对象。通过t1的有参数的构造函数
	func(t1);

	cout << "test3 end..." << endl;
}


int func(void)
{
	int a = 10;
	return a;
}
//场景四
Test func2()
{
	cout << "func2 begin..." << endl;
	Test temp(10, 20); //调用temp的带参数构造函数  
	cout << "func2 end.." << endl;
	return temp; // 有一个临时的匿名对象 = temp ,把temp的数据给到了临时的匿名对象,  ,会调用这个临时匿名
						//对象的拷贝构造函数, 将temp穿进去。
}

void test4() 
{
	cout << "test4 begin " << endl;
	func2();

	//匿名对象在此被析构了, 如果一个临时的匿名对象,没有任何变量去接收它,编译器认为这个临时匿名对象没有用处。
	//编译器会立刻销毁这个临时的匿名对象
	cout << "test4 end" << endl;
}

void test5()
{
	cout << "test5 begin ..." << endl;
	Test t1 = func2();//如果有一个变量去接收这个临时的匿名对象, 编译器认为这个匿名对象转正了,就不会立刻给他销毁。
							//t1 = 匿名的临时对象 为什么不会发生拷贝构造
							//	此时的t1 去接收这个匿名的临时对象不是 重新创建一个t1 而是给这个匿名对象起个名字就叫t1
							//一旦这个匿名对象有了自己的名字,编译器就不会立刻给这个匿名对象销毁了,
							//就当普通局部变量处理了

	cout << "test5 end..." << endl;

	//在此时析构的t1
}

void test6()
{
	cout << "test6 begin..." << endl;
	Test t1; //调用t1的无参数构造函数
	t1 = func2(); //调用的=号操作符 ,,t1 = 匿名对象。 调用了t1的=号操作符。
						//此时匿名没有被转正,匿名没有自己的名字, 匿名对象这个内存没有自己的别名, 编译器就会立刻销毁。
	cout << "test6 end..." << endl;
}


int main(void)
{
	
	//test3();
	//test4();

	//func();

	//test5();
	test6();


	return 0;
}

匿名对象的去和留

默认构造和默认拷贝构造

#define  _CRT_SECURE_NO_WARNINGS 
#include <iostream>

using namespace std;

class B
{
public:
	/*
	
	默认提供的函数
	B() {
		//默认的无惨构造函数
	}
	B(const B& b)
	{
		m_b = b.m_b; //默认的拷贝构造函数
		p = b.p;
	}
	~B()
	{
		//默认的析构函数
	}
	*/

	//如果显示的写了一个普通构造函数, 会隐藏默认的无惨构造函数
	//如果显示的写了一个拷贝构造函数 ,会隐藏默认的无参构造函数和默认的拷贝构造函数
	//如果显示的写了一个析构函数, 会隐藏默认的析构函数
	B(const B& b)
	{

	}
private:
	int m_b;
	char *p;
};

class A
{
public:
	/*
	默认的构造函数
	如果普通构造函数,提供了一个显示的构造, 那么这个无参的默认构造就会被隐藏。 不会把拷贝构造函数隐藏掉
	A()
	{

	}
	*/
	A(int a)
	{
		m_a = a;
	}

	/*
	默认的拷贝构造函数
	A(const A & a)
	{
	   m_a = a;
	}
	*/
	//显示的提供一个拷贝构造的函数的时候,默认的拷贝构造函数就会被隐藏
	A(const A &a) {
		cout << "显示提供的拷贝构造函数" << endl;
		m_a = a.m_a;
	}

	/*
	 默认的析构函数
	 ~A()
	 {
	 }
	*/

	//只有提供一个显示的析构函数,才会将默认的析构覆盖点
	~A()
	{
		cout << "A的析构函数 调用 " << endl;
	}
private:
	int m_a;
};

int main(void)
{
	A aObj(10); //当你不提供任何构造函数的时候, 系统会有一个默认的构造函数
	A aObj2 = aObj;  //调用了aObj2的拷贝构造函数
	//A aObj2(aObj);
	
	return 0;
}

拷贝构造函数作用用一个对象初始化另一个对象

构造函数的调用规则研究

猜你喜欢

转载自blog.csdn.net/moonlightpeng/article/details/92426861