c++-构造函数

构造函数

  • 构造和析构概念语法
  • 构造函数的分类
  • 有参构造函数3种调用方法
  • 拷贝构造函数4种调用时机
    • 场景1和2:A a(b); A a = b;
    • 场景3:形参是一个元素,实参传递给形参
    • 场景4:函数返回值返回一个元素,匿名对象
    • 匿名对象的去和留
    • 对象的初始化 和 对象的=操作 是两个不同的概念
  • 构造和析构
    • 构造和析构概念语法
    • 构造函数的分类
    • 有参构造函数3种调用方法
    • 拷贝构造函数4种调用时机
      • 场景1和2:A a(b); A a = b;
      • 场景3:形参是一个元素,实参传递给形参
      • 场景4:函数返回值返回一个元素,匿名对象
      • 匿名对象的去和留
      • 对象的初始化 和 对象的=操作 是两个不同的概念
    • 构造函数调用规则研究(写了构造函数则必须调用)
    • 多个对象的构造 构造函数初始化列表
    • 构造函数和析构函数的调用顺序(先组合对象的构造、自己构造;析构和构造相反)
    • 深拷贝和浅拷贝
      • 问题抛出 显示的编写拷贝构造函数
      • 默认的=号操作 也是浅拷贝,解决方案重载=操作符
      • 总结:C++编译给提供的默认的拷贝构造和=操作都是浅拷贝
    • 构造和析构综合练习
      • 匿名对象:直接调用构造函数
      • 匿名对象:构造中调用构造
  • 构造函数调用规则研究(写了构造函数则必须调用)
  • 多个对象的构造 构造函数初始化列表
  • 构造函数和析构函数的调用顺序(先组合对象的构造、自己构造;析构和构造相反)
  • 深拷贝和浅拷贝
    • 问题抛出 显示的编写拷贝构造函数
    • 默认的=号操作 也是浅拷贝,解决方案重载=操作符
    • 总结:C++编译给提供的默认的拷贝构造和=操作都是浅拷贝
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>


using namespace std;

class Test
{
public:
#if 0
	void init(int x, int y)
	{
		m_x = x;
		m_y = y;
	}
#endif

	//test类的构造函数
	//在对象被创建的时候,用来初始化对象的函数
	Test()//无参数的构造函数
	{
		m_x = 0;
		m_y = 0;
	}
	Test(int x, int y)
	{
		m_x = x;
		m_y = y;
		// name = (char*)malloc(100);
		strcpy(name, "zhang3");
	}
	Test(int x)
	{
		m_x = x;
		m_y = 0;
	}

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


	//析构函数和构造函数都没有返回值,
	//析构函数没有形参
	~Test() {
		cout << "~Test()...." << endl;
		if (name != NULL) {
			// free(name);
			cout << "free succ!" << endl;
		}
	}
private:
	int m_x;
	int m_y;
	char *name;
};

void test1()
{
	Test t1(10, 20);
	t1.printT();

	//在一个对象临死之前,要自定调用析构函数
}

int main(void)
{
#if 0
	Test t1(10, 20);
	t1.printT();
	//t1.init(10, 20);

	Test t2(100);
	t2.printT();

	Test t3;//就是调用类的无参数构造函数

	t3.printT();

#endif

	test1();
	return 0;
}

拷贝构造函数

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>


using namespace std;

class Test
{
public:
	Test()
	{
		m_x = 0;
		m_y = 0;
	}
	Test(int x, int y)
	{
		m_x = x;
		m_y = y;
	}

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

#if 1
	//显示的拷贝构造函数
	Test(const Test &another)
	{
		cout << "Test(const Test &)..." << endl;
		m_x = another.m_x;
		m_y = another.m_y;
	}
#endif
#if 0
	//? 会有一个默认的拷贝构造函数
	Test(const Test &another)
	{
		m_x = another.m_x;
		m_y = another.m_y;
	}
#endif

	//=赋值操作符
	void operator=(const Test &another)
	{
		m_x = another.m_x;
		m_y = another.m_y;
	}
private:
	int m_x;
	int m_y;
};

int main(void)
{
	Test t1(100, 200); 

	Test t2(t1); 

	t2.printT();



	//构造函数是对象初始化的时候调用
	Test t3; //依然是初始化t3的时候调用t3构造函数,依然是调用t3的拷贝构造函数

	t3 = t1; //调用的不是t3拷贝构造函数,而是t3的赋值操作符函数

	return 0;
}

默认的构造函数和解析构造函数

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>


using namespace std;

class Test
{
public:
	//默认的无参构造函数
#if 0
	Test()
	{

	}
#endif
	//显示提供一个有参数的构造函数,默认的构造函数就不复存在
	Test(int x, int y)
	{
		m_x = x;
		m_y = y;
	}
	Test() {
		m_x = 0;
		m_y = 0;
	}

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

	//默认的析构函数
#if 0
	~Test()
	{

	}
#endif
	~Test() {
		cout << "~Test()..." << endl;
	}


private:
	int m_x;
	int m_y;
};

int main(void)
{
	Test t1;//调用Test无参构造
	t1.printT();
	
	return 0;
}

默认的拷贝构造函数

  • 类中 会有个默认的无参构造函数:

当没有任何显示的构造函数(显示的无参构,显示有参,显示拷贝构造) 的时候,默认无参构造函数就会出现。

  • 会有默认的拷贝构造函数:
    -->当没有 **显示的拷贝构造 *** 的函数,默认的拷贝构造就会出现。

  • 会有默认的析构函数
    --> 当没有显示的析构函数的时候, 默认的析构函数就会出现

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class A
{
public:
#if 0
	A()
	{
		
	}
#endif
#if 0
	A(const A &another)
	{
		m_a = another.m_a;
		m_b = another.m_b;
	}
#endif
	A()
	{

	}
	A(int a, int b)
	{

	}
#if 0
	~A()
	{

	}
#endif
	~A()
	{
		cout << "~A()" << endl;
	}
private:
	int m_a;
	int m_b;
};

//类中 会有个默认的无参构造函数:	、
//		-->当没有任何***显示的构造函数(显示的无参构,显示有参,显示拷贝构造)*** 的时候,默认无参构造函数就会出现。

//		会有默认的拷贝构造函数:
//		-->当没有 **显示的拷贝构造 ***  的函数,默认的拷贝构造就会出现。

//     会有默认的析构函数
//      --> 当没有***显示的析构函数***的时候,  默认的析构函数就会出现。


int main(void)
{
	A a;
	
	A a1(a);
	
	return 0;
}

拷贝构造函数的应用场景

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Test
{
public:
	Test()
	{
		cout << "test()..." << endl;
		m_x = 0;
		m_y = 0;
	}
	Test(int x, int y)
	{
		cout << "Test(int x, int y)..." << endl;

		m_x = x;
		m_y = y;
	}
	Test(const Test & another)
	{
		cout << "Test(const Test &)..." << endl;
		m_x = another.m_x;
		m_y = another.m_y;
	}

	void operator=(const Test &another)
	{
		cout << "operatoer = (const Test &)" << endl;
		m_x = another.m_x;
		m_y = another.m_y;
	}

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

	~Test() {
		cout << "~Test()..." << endl;
	}
private:
	int m_x;
	int m_y;
};


//析构函数调用的顺序, 跟构造相反, 谁先构造的,谁后析构。
//场景1
void test1()
{
	Test t1(10, 20);
	Test t2(t1);//Test t2 = t1;
}

//场景2
void test2()
{
	Test t1(10, 20);
	Test t2;

	t2 = t1;//=操作符
}


void func(Test t)//Test t = t1; //Test t 的拷贝构造函数
{
	cout << "func begin..." << endl;
	t.printT();
	cout << "func end..." << endl;
}

//场景3
void test3()
{
	cout << "test3 begin..." << endl;
	Test t1(10, 20);

	func(t1);

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


//场景4
Test func2()
{
	cout << "func2 begin..." << endl;
	Test temp(10, 20);
	temp.printT();

	cout << "func2 end..." << endl;

	return temp;
}//匿名的对象 = temp  匿名对象.拷贝构造(temp)

void test4()
{
	cout << "test4 being.. " << endl;
	func2();// 返回一个匿名对象。 当一个函数返回一个匿名对象的时候,函数外部没有任何
			//变量去接收它, 这个匿名对象将不会再被使用,(找不到), 编译会直接将个这个匿名对象
			//回收掉,而不是等待整改函数执行完毕再回收.
	//匿名对象就被回收。
	
	cout << "test4 end" << endl;
}

void test5()
{
	cout << "test 5begin.. " << endl;
	Test t1 = func2(); //会不会触发t1拷贝构造来   t1.拷贝(匿名)?
						//并不会触发t1拷贝,而是 将匿名对象转正 t1,
						//把这个匿名对象 起了名字就叫t1.

	cout << "test 5 end.." << endl;
}

//场景6
void test6()
{
	cout << "test6 begin..." << endl;
	Test t1;//t1已经被初始化了。

	t1 = func2(); //t1已经被初始化了,所以func2返回的匿名对象不会再次转正,而依然是匿名对象。
					//所以t1会调用等号操作符,t1.operator=(匿名对象), 然后编译器会立刻回收掉匿名对象

	t1.printT();

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


int main(void)
{
	//test1();
	//test2();
	//test3();
	//test4();
	//test5();
	test6();

	return 0;
}

深拷贝和浅拷贝

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Test
{
public:
	Test()
	{
		cout << "test()..." << endl;
		m_x = 0;
		m_y = 0;
	}
	Test(int x, int y)
	{
		cout << "Test(int x, int y)..." << endl;

		m_x = x;
		m_y = y;
	}
	Test(const Test & another)
	{
		cout << "Test(const Test &)..." << endl;
		m_x = another.m_x;
		m_y = another.m_y;
	}

	void operator=(const Test &another)
	{
		cout << "operatoer = (const Test &)" << endl;
		m_x = another.m_x;
		m_y = another.m_y;
	}

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

	~Test() {
		cout << "~Test()..." << endl;
	}
private:
	int m_x;
	int m_y;
};


//析构函数调用的顺序, 跟构造相反, 谁先构造的,谁后析构。
//场景1
void test1()
{
	Test t1(10, 20);
	Test t2(t1);//Test t2 = t1;
}

//场景2
void test2()
{
	Test t1(10, 20);
	Test t2;

	t2 = t1;//=操作符
}


void func(Test t)//Test t = t1; //Test t 的拷贝构造函数
{
	cout << "func begin..." << endl;
	t.printT();
	cout << "func end..." << endl;
}

//场景3
void test3()
{
	cout << "test3 begin..." << endl;
	Test t1(10, 20);

	func(t1);

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


//场景4
Test func2()
{
	cout << "func2 begin..." << endl;
	Test temp(10, 20);
	temp.printT();

	cout << "func2 end..." << endl;

	return temp;
}//匿名的对象 = temp  匿名对象.拷贝构造(temp)

void test4()
{
	cout << "test4 being.. " << endl;
	func2();// 返回一个匿名对象。 当一个函数返回一个匿名对象的时候,函数外部没有任何
			//变量去接收它, 这个匿名对象将不会再被使用,(找不到), 编译会直接将个这个匿名对象
			//回收掉,而不是等待整改函数执行完毕再回收.
	//匿名对象就被回收。
	
	cout << "test4 end" << endl;
}

void test5()
{
	cout << "test 5begin.. " << endl;
	Test t1 = func2(); //会不会触发t1拷贝构造来   t1.拷贝(匿名)?
						//并不会触发t1拷贝,而是 将匿名对象转正 t1,
						//把这个匿名对象 起了名字就叫t1.

	cout << "test 5 end.." << endl;
}

//场景6
void test6()
{
	cout << "test6 begin..." << endl;
	Test t1;//t1已经被初始化了。

	t1 = func2(); //t1已经被初始化了,所以func2返回的匿名对象不会再次转正,而依然是匿名对象。
					//所以t1会调用等号操作符,t1.operator=(匿名对象), 然后编译器会立刻回收掉匿名对象

	t1.printT();

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


int main(void)
{
	//test1();
	//test2();
	//test3();
	//test4();
	//test5();
	test6();

	return 0;
}

构造函数的初始化列表

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>

using namespace std;

class Test
{
public:
	Test()
	{
		cout << "test()..." << endl;
		m_x = 0;
		m_y = 0;
	}
	Test(int x, int y)
	{
		cout << "Test(int x, int y)..." << endl;

		m_x = x;
		m_y = y;
	}
	Test(const Test & another)
	{
		cout << "Test(const Test &)..." << endl;
		m_x = another.m_x;
		m_y = another.m_y;
	}

	void operator=(const Test &another)
	{
		cout << "operatoer = (const Test &)" << endl;
		m_x = another.m_x;
		m_y = another.m_y;
	}

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

	~Test() {
		cout << "~Test()..." << endl;
	}
private:
	int m_x;
	int m_y;
};


//析构函数调用的顺序, 跟构造相反, 谁先构造的,谁后析构。
//场景1
void test1()
{
	Test t1(10, 20);
	Test t2(t1);//Test t2 = t1;
}

//场景2
void test2()
{
	Test t1(10, 20);
	Test t2;

	t2 = t1;//=操作符
}


void func(Test t)//Test t = t1; //Test t 的拷贝构造函数
{
	cout << "func begin..." << endl;
	t.printT();
	cout << "func end..." << endl;
}

//场景3
void test3()
{
	cout << "test3 begin..." << endl;
	Test t1(10, 20);

	func(t1);

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


//场景4
Test func2()
{
	cout << "func2 begin..." << endl;
	Test temp(10, 20);
	temp.printT();

	cout << "func2 end..." << endl;

	return temp;
}//匿名的对象 = temp  匿名对象.拷贝构造(temp)

void test4()
{
	cout << "test4 being.. " << endl;
	func2();// 返回一个匿名对象。 当一个函数返回一个匿名对象的时候,函数外部没有任何
			//变量去接收它, 这个匿名对象将不会再被使用,(找不到), 编译会直接将个这个匿名对象
			//回收掉,而不是等待整改函数执行完毕再回收.
	//匿名对象就被回收。
	
	cout << "test4 end" << endl;
}

void test5()
{
	cout << "test 5begin.. " << endl;
	Test t1 = func2(); //会不会触发t1拷贝构造来   t1.拷贝(匿名)?
						//并不会触发t1拷贝,而是 将匿名对象转正 t1,
						//把这个匿名对象 起了名字就叫t1.

	cout << "test 5 end.." << endl;
}

//场景6
void test6()
{
	cout << "test6 begin..." << endl;
	Test t1;//t1已经被初始化了。

	t1 = func2(); //t1已经被初始化了,所以func2返回的匿名对象不会再次转正,而依然是匿名对象。
					//所以t1会调用等号操作符,t1.operator=(匿名对象), 然后编译器会立刻回收掉匿名对象

	t1.printT();

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


int main(void)
{
	//test1();
	//test2();
	//test3();
	//test4();
	//test5();
	test6();

	return 0;
}
原文地址:https://www.cnblogs.com/ygjzs/p/12076497.html