一文详解构造函数和析构函数

一、对象的初始化和清理

 C++中面向对象的思想来源于现实,是对现实事物的抽象模拟,具体来说,当我们创建对象的时候,这个对象应该有一个初始状态,当对象销毁之前应该销毁自己创建的一些数据

 对象的初始化和清理也是两个非常重要的安全问题,一个对象或者变量没有初始化,对其使用后果是未知的,同样的使用完一个变量,没有及时清理,也会造成一定的安全问题,C++为了给我们提供这种问题的解决方案,构造函数和析构函数,这两个函数将会被编译器自动调用,完成对象初始化和对象清理工作。

 对象的初始化和清理工作是编译器强制我们要做的事情,即使你不提供初始化操作和清理操作,编译器也会给你增加默认的操作,只是这个默认初始化操作不会做任何事,所以编写类就应该顺便提供初始化函数

简单的案例

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:
	// 构造函数  初始化成员变量 编译器调用
	Maker()
	{
		a = 10;
		cout << "构造函数" << endl;
	}

    ~Maker()
    {
        // 析构函数
        // 对象销毁前  编译器调用
        cout<<"析构函数"<<endl

    }

public:
	int a;
};

void test01()
{
    // 创建对象 分配空间  局部变量在栈区  
    // 调用构造函数
	Maker m;// 创建对象时 调用构造函数
	int b = m.a;
	cout << b << endl;
}


int main()
{
	//cout << "hello" << endl;

	test01();

	return EXIT_SUCCESS;
}

有参数构造:

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:
	// 构造函数
	Maker()
	{
		a = 10;
		cout << "构造函数" << endl;
	}

public:
	int a;
};

void test01()
{
	Maker m;// 创建对象时 调用构造函数
	int b = m.a;
	cout << b << endl;
}

// 析构函数的作用

class Maker2
{
public:
	// 有参数构造
	Maker2(const char* name, int age)
	{
		cout << "有参数构造" << endl;

		// 从堆区进行申请
		pName = (char*)malloc(sizeof(char) * (strlen(name) + 1));// 申请字符串长度的字节个数  +1 是因为填充\0
		strcpy(pName,name);// 赋值字符串   参数直接写成字符串地址即可
		mAge = age;

	}

	void Print()
	{
		cout << "打印参数" << pName << mAge << endl;
	}


private:
	char* pName;
	int mAge;


};

void test02()
{

	Maker2 m("hh",11);
	m.Print();

}


int main()
{
	test02();
	return EXIT_SUCCESS;
}

二、析构函数

析构函数的作用就是在对象销毁之前,回收内存资源

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)
// 析构函数的作用
class Maker2
{
public:
	// 有参数构造
	Maker2(const char* name, int age)
	{
		cout << "有参数构造" << endl;

		// 从堆区进行申请
		pName = (char*)malloc(sizeof(char) * (strlen(name) + 1));// 申请字符串长度的字节个数  +1 是因为填充\0
		strcpy(pName,name);// 赋值字符串   参数直接写成字符串地址即可
		mAge = age;
	}
	void Print()
	{
		cout << "打印参数" << pName << mAge << endl;
	}

	~Maker2()
	{
		cout << "析构函数 " << endl;
		//释放堆区空间
		if (pName != NULL)
		{
			free(pName);
			pName = NULL;
		}
	}

private:
	char* pName;
	int mAge;
};

void test02()
{
	Maker2 m("hh",11);
	m.Print();
}
int main()
{
	test02();
	return EXIT_SUCCESS;
}

三、构造函数可以重载


class Maker3
{
public:
	// 构造函数可以重载
	Maker3()
	{
		// 无参构造函数
		cout
	}

	Maker3(int a)
	{
		// 有参构造函数

	}
};


构造函数必须声明为public,如果是私有化,创建对象会被报错,没办法调用构造函数

有对象产生必然会调用构造函数,有对象销毁必然会调用析构函数,有多少次对象产生就会调用多少次构造函数,有多少次对象销毁就会调用多少次析构函数

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)


class Maker3
{
public:
	// 构造函数可以重载
	Maker3()
	{
		// 无参构造函数
		cout << "无参数构造" << endl;
	}

	Maker3(int a)
	{
		// 有参构造函数
		cout << "有参数构造" << endl;

	}

	~Maker3()
	{
		// 析构函数
		cout << "析构函数" << endl;
	}
};

void test03()
{
	Maker3 m;
	Maker3 m1(1);
}

int main()
{
	//cout << "hello" << endl;

	test03();

	return EXIT_SUCCESS;
}

注意:

构造函数和析构函数必须是共有权限,否则创建对象时,会报错
初始化用构造函数,清理使用析构函数,这两个函数是编译器调用
构造函数可以进行重载
构造函数没有返回值,不可以使用void,析构函数没有返回值,不能使用void

四、默认构造函数和默认析构函数

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker
{

public:
	// 编译器提供默认的构造函数和析构函数 函数体都是空的
	Maker()
	{

	}

	~Maker()
	{

	}


	// 编译器提供默认的构造函数和析构函数
	void printMaker()
	{
		a = 100;
		cout << a << endl;
	}

private:
	int a;
};

void test()
{
	Maker m;
	m.printMaker();
}

int main()
{
	//cout << "hello" << endl;

	test();

	return EXIT_SUCCESS;
}

五、拷贝构造函数

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker
{

public:
	// 编译器提供默认的构造函数和析构函数 函数体都是空的
	Maker()
	{
		cout << "构造函数" << endl;
		a = 20;
	}

    // 拷贝构造函数  参数是对象的引用
	Maker(const Maker &m)
	{
		cout << "拷贝构造函数" << endl;
		a = m.a;// 赋值成员变量
	}

	~Maker()
	{

	}

	// 编译器提供默认的构造函数和析构函数
	void printMaker()
	{
		a = 100;
		cout << a << endl;
	}

private:
	int a;
};

void test()
{
	Maker m;
	//m.printMaker();

	Maker m1(m);// 用已有的对象生成另一个对象  涉及到构造函数的重载
	m1.printMaker();
}

int main()
{
	//cout << "hello" << endl;

	test();

	return EXIT_SUCCESS;
}

5.1 编译器提供了默认的构造函数

C++编译器提供了默认的拷贝构造函数,默认的拷贝构造函数进行了成员变量的简单赋值

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker
{

public:
	// 编译器提供默认的构造函数和析构函数 函数体都是空的
	Maker()
	{
		cout << "构造函数" << endl;
		a = 20;
	}

 //   // 拷贝构造函数  参数是对象的引用
	//Maker(const Maker &m)
	//{
	//	cout << "拷贝构造函数" << endl;
	//	a = m.a;// 赋值成员变量
	//}

	~Maker()
	{

	}

	// 编译器提供默认的构造函数和析构函数
	void printMaker()
	{
		cout << a << endl;
	}

private:
	int a;
};

void test()
{
	Maker m;
	//m.printMaker();

	Maker m1(m);// 用已有的对象生成另一个对象  涉及到构造函数的重载
	m1.printMaker();
}

int main()
{
	//cout << "hello" << endl;

	test();

	return EXIT_SUCCESS;
}

5.2 拷贝构造函数中形参必须要用引用类型

如果拷贝构造函数中的形参不是引用类型

Maker3(const Maker3 m)
{
	cout<<"拷贝构造函数"<<endl;
}

1.Maker3 m2(m1);
2.const Maker3 m = m1;
3.const Maker3 m(m1);
4.const Mkaer3 m = m1;
5.进入死循环

六、构造函数的分类和调用

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:
	// 按照参数分类:无参数  有参数

	Maker()
	{
		cout << "无参数构造" << endl;
	}


	Maker(int a)
	{
		cout << "有参数构造" << endl;
	}

	// 按照类型:普通构造函数  拷贝构造函数
	Maker(const Maker& m)
	{
		cout << "拷贝构造函数" << endl;
	}
};


void test()
{
	Maker m;// 调用无参数构造函数
	Maker m1(10);// 调用有参数构造函数
	Maker m2(m1);// 调用拷贝构造函数
	Maker m3 = m2;// 调用拷贝构造函数
	Maker m4 = 10;// 调用有参构造
}

int main()
{
	//cout << "hello" << endl;

	test();

	return EXIT_SUCCESS;
}

七、匿名对象

匿名对象的声明周期在当前行

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:
	// 按照参数分类:无参数  有参数

	Maker()
	{
		cout << "无参数构造" << endl;
	}


	Maker(int a)
	{
		cout << "有参数构造" << endl;
	}

	// 按照类型:普通构造函数  拷贝构造函数
	Maker(const Maker& m)
	{
		cout << "拷贝构造函数" << endl;
	}

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

void test01()
{
	Maker();// 匿名对象的生命周期在当前行
	cout << "test01函数结束" << endl;
}

int main()
{
	test01();
	return EXIT_SUCCESS;
}

如果匿名对象前面有名字来接 那么就不是匿名对象 析构函数在函数结束之后 执行

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:
	// 按照参数分类:无参数  有参数

	Maker()
	{
		cout << "无参数构造" << endl;
	}


	Maker(int a)
	{
		cout << "有参数构造" << endl;
	}

	// 按照类型:普通构造函数  拷贝构造函数
	Maker(const Maker& m)
	{
		cout << "拷贝构造函数" << endl;
	}

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

void test01()
{
	Maker();// 匿名对象的生命周期在当前行
	cout << "test01函数结束" << endl;


	Maker m1 = Maker();// 如果匿名对象前面有名字来接  那么就不是匿名对象  析构函数在函数结束之后 执行
	cout << "函数结束" << endl;
}



int main()
{
	//cout << "hello" << endl;

	test01();

	return EXIT_SUCCESS;
}

八、拷贝构造函数的调用时机

8.1 对象以值的方式给函数参数

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {
public:
	// 按照参数分类:无参数  有参数
	Maker()
	{
		cout << "无参数构造" << endl;
	}
	Maker(int a)
	{
		cout << "有参数构造" << endl;
	}
	// 按照类型:普通构造函数  拷贝构造函数
	Maker(const Maker& m)
	{
		cout << "拷贝构造函数" << endl;
	}

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

// 对象以值的方式给函数参数
void func(Maker m)
{
	// 以拷贝构造函数的形式进行赋值
}

void test01()
{
	Maker m1;
	func(m1); // Maker m = m1
}

int main()
{
	//cout << "hello" << endl;
	test01();
	return EXIT_SUCCESS;
}

8.2 vs debug模式下的函数局部对象返回值

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:
	// 按照参数分类:无参数  有参数

	Maker()
	{
		cout << "无参数构造" << endl;
	}


	Maker(int a)
	{
		cout << "有参数构造" << endl;
	}

	// 按照类型:普通构造函数  拷贝构造函数
	Maker(const Maker& m)
	{
		cout << "拷贝构造函数" << endl;
	}

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

// 对象以值的方式给函数参数
void func(Maker m)
{
	// 以拷贝构造函数的形式进行赋值
}

// 拷贝构造函数的方式调用
void test01()
{
	Maker m1;
	func(m1); // Maker m = m1
}

// 函数的局部对象以值的方式从函数返回
Maker func2()
{
	// 局部对象
	Maker m;// 无参数构造
	cout << "局部对象的地址:" << &m << endl;

	return m;
}


// vs 的Debug模式下  会调用拷贝构造  
void test03()
{
	Maker m1 = func2();// 调用拷贝构造函数   vs debug模式下  fun2()中的对象已经释放   m1是新的地址
	cout << "m1的对象的地址" << &m1 << endl;  // 这里会发现  两个地址不一样  因为函数内部的局部对象 在函数结束之后  会释放内存
}


int main()
{
	//cout << "hello" << endl;

	test03();

	return EXIT_SUCCESS;
}

8.3 vs Release模式下函数局部对象以值的方式从函数返回

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:
	// 按照参数分类:无参数  有参数

	Maker()
	{
		cout << "无参数构造" << endl;
	}


	Maker(int a)
	{
		cout << "有参数构造" << endl;
	}

	// 按照类型:普通构造函数  拷贝构造函数
	Maker(const Maker& m)
	{
		cout << "拷贝构造函数" << endl;
	}

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

// 对象以值的方式给函数参数
void func(Maker m)
{
	// 以拷贝构造函数的形式进行赋值
}

// 拷贝构造函数的方式调用
void test01()
{
	Maker m1;
	func(m1); // Maker m = m1
}

// 函数的局部对象以值的方式从函数返回
Maker func2()
{
	// 局部对象
	Maker m;// 无参数构造
	cout << "局部对象的地址:" << &m << endl;

	return m;
}


// vs 的Relase模式下  不会调用拷贝构造  
void test03()
{
	Maker m1 = func2();// 未调用拷贝构造函数  地址相同   
	cout << "m1的对象的地址" << &m1 << endl;  // 这里会发现  两个地址一样  release为了节约内存  没有释放函数内部的对象
}


int main()
{
	//cout << "hello" << endl;

	test03();

	return EXIT_SUCCESS;
}

九、构造函数的调用规则

9.1 如果程序员提供有参数构造,那么编译器不会提供默认构造函数,但是会提供默认的拷贝构造函数

#include<iostream>
using namespace std;
# define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker
{
public:
	Maker(int a)
	{
		cout << "有参数构造函数" << endl;
	}


};

// 如果程序员提供了有参数构造函数   那么编译器不会提供默认的构造函数  函数重载
void test01()
{
	//Maker m;// 报错
	Maker m(10);// 调用有参构造函数
	Maker m1(m);// 编译器提供默认的拷贝构造函数
}

int main()
{
	test01();

	return EXIT_SUCCESS;
}

9.2 如果程序员提供了拷贝构造函数 那么编译器不会提供默认的构造函数和默认的拷贝构造函数

#include<iostream>
using namespace std;
# define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker
{
public:
	Maker(const Maker& m)
	{
		cout << "拷贝构造函数" << endl;
	}


};

// 如果程序员提供了有参数构造函数   那么编译器不会提供默认的构造函数  函数重载
void test01()
{
	//Maker m;// 报错
}

// 如果程序员提供了拷贝构造函数  那么编译器不会提供默认构造函数和默认的拷贝构造函数
void test02()
{
	Maker m;
}

int main()
{


	return EXIT_SUCCESS;
}

十、多个对象的构造函数和析构函数

10.1 多个对象的构造函数和析构函数的规则

  • 如果类有成员对象 那么先调用成员对象的构造函数 在调用本身的构造函数
  • 析构函数的调用顺序相反
  • 成员对象的构造函数调用和定义顺序一样
  • 如果有成员对象 那么实例化对象时,必须保证成员对象的构造和析构能被调用
#include<iostream>
using namespace std;
# define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class BMW
{
public:
	BMW()
	{
		cout << "BMW() 构造" << endl;
	}

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


class Buiker
{
public:
	Buiker()
	{
		cout << "Buiker() 构造" << endl;
	}

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

class Maker
{
public:
	Maker()
	{
		cout << "Maker构造" << endl;
	}

	~Maker()
	{
		cout << "maker析构函数" << endl;
	}

private:
	BMW bmw;//成员对象
	Buiker bui;


};

void test01()
{
	// 如果类有成员对象  那么先调用成员对象的构造函数  在调用本身的构造函数
	// 析构函数的调用顺序相反
	// 成员对象的构造函数调用和定义顺序一样
	// 如果有成员对象  那么实例化对象时,必须保证成员对象的构造和析构能被调用
	Maker m;
}


int main()
{

	test01();


	return EXIT_SUCCESS;
}

10.2 多个对象初始化列表

#include<iostream>
using namespace std;
# define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class BMW
{
public:
	BMW(int a)
	{
		cout << "BMW() 构造" << a<<endl;
	}

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


class Buiker
{
public:
	Buiker()
	{
		cout << "Buiker() 构造" << endl;
	}

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

class Maker
{
public:
	// 初始化列表
	// 注意:初始化列表只能写在构造函数
	Maker() :bmw(10)
	{
		cout << "Maker构造" << endl;
	}

	~Maker()
	{
		cout << "maker析构函数" << endl;
	}

private:
	BMW bmw;//成员对象
	Buiker bui;
};

void test01()
{
	// 如果类有成员对象  那么先调用成员对象的构造函数  在调用本身的构造函数
	// 析构函数的调用顺序相反
	// 成员对象的构造函数调用和定义顺序一样
	// 如果有成员对象  那么实例化对象时,必须保证成员对象的构造和析构能被调用
	Maker m;
}

// 初始化列表是调用成员对象的指定构造函数
void test02()
{
	Maker m;
}


int main()
{

	test02();


	return EXIT_SUCCESS;
}

或者:构造函数需要加上参数

#include<iostream>
using namespace std;
# define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class BMW
{
public:
	BMW(int a)
	{
		cout << "BMW() 构造" << a<<endl;
	}

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


class Buiker
{
public:
	Buiker()
	{
		cout << "Buiker() 构造" << endl;
	}

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

class Maker
{
public:
	// 初始化列表
	// 注意:初始化列表只能写在构造函数

	// 构造函数可以写参数  初始化直接写入参数
	Maker(int a) :bmw(a)
	{
		cout << "Maker构造" << endl;
	}

	~Maker()
	{
		cout << "maker析构函数" << endl;
	}

private:
	BMW bmw;//成员对象
	Buiker bui;


};

// 初始化列表是调用成员对象的指定构造函数
void test02()
{
	Maker m(1);
}


int main()
{

	test02();


	return EXIT_SUCCESS;
}

注意:如果使用了初始化列表,那么所有的构造函数都要写初始化列表

#include<iostream>
using namespace std;
# define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class BMW
{
public:
	BMW(int a)
	{
		cout << "BMW() 构造" << a<<endl;
	}

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


class Buiker
{
public:
	Buiker()
	{
		cout << "Buiker() 构造" << endl;
	}

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

class Maker
{
public:
	// 初始化列表
	// 注意:初始化列表只能写在构造函数

	// 构造函数可以写参数  初始化直接写入参数
	Maker(int a) :bmw(a)
	{
		cout << "Maker构造" << endl;
	}
	
	// 拷贝构造函数也要协商初始化列表
	Maker(const Maker& m) :bmw(4)
	{
		// 注意 如果使用了初始化列表 那么所有的构造函数都要写
	}

	~Maker()
	{
		cout << "maker析构函数" << endl;
	}

private:
	BMW bmw;//成员对象
	Buiker bui;


};



// 初始化列表是调用成员对象的指定构造函数
void test02()
{
	Maker m(1);
}


int main()
{
	test02();
	return EXIT_SUCCESS;
}

#include<iostream>
using namespace std;
# define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class BMW
{
public:
	BMW(int a)
	{
		cout << "BMW() 构造" << a<<endl;
	}

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


class Buiker
{
public:
	Buiker(int b)
	{
		cout << "Buiker() 构造" << endl;
	}

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

class Maker
{
public:
	// 初始化列表
	// 注意:初始化列表只能写在构造函数
	// 构造函数可以写参数  初始化直接写入参数
	Maker(int a) :bmw(a),bui(1)
	{
		cout << "Maker构造" << endl;
	}

	Maker(const Maker& m) :bmw(4),bui(1)
	{
		// 注意 如果使用了初始化列表 那么所有的构造函数都要写
	}

	~Maker()
	{
		cout << "maker析构函数" << endl;
	}

private:
	BMW bmw;//成员对象
	Buiker bui;


};


// 初始化列表是调用成员对象的指定构造函数
void test02()
{
	Maker m(1);
}


int main()
{
	test02();
	return EXIT_SUCCESS;
}

构造函数的参数填写所有参数,初始化列表写成参数

#include<iostream>
using namespace std;
# define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class BMW
{
public:
	BMW(int a)
	{
		cout << "BMW() 构造" << a<<endl;
	}

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


class Buiker
{
public:
	Buiker(int b)
	{
		cout << "Buiker() 构造" <<b<< endl;
	}

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

class Maker
{
public:
	// 初始化列表
	// 注意:初始化列表只能写在构造函数
	// 构造函数可以写参数  初始化直接写入参数
	Maker(int a,int b) :bmw(a),bui(b)
	{
		cout << "Maker构造" << endl;
	}

	Maker(const Maker& m) :bmw(4),bui(1)
	{
		// 注意 如果使用了初始化列表 那么所有的构造函数都要写
	}

	~Maker()
	{
		cout << "maker析构函数" << endl;
	}

private:
	BMW bmw;//成员对象
	Buiker bui;

};

// 初始化列表是调用成员对象的指定构造函数
void test02()
{
	Maker m(1,2);
}

int main()
{
	test02();
	return EXIT_SUCCESS;
}

总结:

  • 初始化列表是干什么用的,指定调用成员对象的某个构造函数
  • 初始化列表只能写在构造函数旁边
  • 如果使用了初始化列表 那么所有的构造函数都要写初始化列表
  • 如果有多个对象需要指定调用某个构造函数,需要使用逗号隔开
  • 可以使用对象的构造函数参数传递数值给成员对象的变量

十一、对象的深浅拷贝

11.1 默认的拷贝构造函数进行了简单的赋值操作

拷贝构造函数只是复制值 没有复制内存空间

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:

	Maker(int a, int b)
	{
		id = a;
		age = b;
	}

	void print()
	{
		cout << "id = " << id << " age = " << age << endl;
	}


private:
	int id;
	int age;


};

void test01()
{
	Maker a(1, 1);
	a.print();

	Maker b(a);// 拷贝构造函数  浅复制
	b.print();
}

int main()
{
	test01();

	return EXIT_SUCCESS;
}

浅拷贝的问题:同一块内存空间被释放两次

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:

	Maker(int a, int b)
	{
		id = a;
		age = b;
	}

	void print()
	{
		cout << "id = " << id << " age = " << age << endl;
	}


private:
	int id;
	int age;


};

class Student {
public:
	Student(const char* name, int Age)
	{
		pName = (char*)malloc(strlen(name) + 1);// 申请堆区空间
		strcpy(pName,name);// 复制内容
		age = Age;
	}

	// 申请堆区空间 一定要释放
	~Student()
	{
		if (pName != NULL)
		{
			free(pName);
			pName = NULL;
		}
	}

	void print()
	{
		cout << "名字 = " << pName << "年纪 = " << age << endl;
	}

private:
	char* pName;
	int age;
};

void test01()
{
	Maker a(1, 1);
	a.print();

	Maker b(a);// 拷贝构造函数  浅复制
	b.print();
}


void test02()
{
	Student a("xxx",1);
	a.print();

	// 复制的是地址

	// 导致同一块内存地址空间被析构函数销毁两次
	Student b(a);
	b.print();
}

int main()
{
	test02();

	return EXIT_SUCCESS;
}

11.2 深拷贝

重写拷贝构造函数即可,本质上还是重新申请一块堆区空间

#include<iostream>
using namespace std;
#define _CRT_SECURE_NO_WARNINGS
#pragma warning(disable:4996)

class Maker {

public:

	Maker(int a, int b)
	{
		id = a;
		age = b;
	}

	void print()
	{
		cout << "id = " << id << " age = " << age << endl;
	}


private:
	int id;
	int age;


};

class Student {
public:
	Student(const char* name, int Age)
	{
		pName = (char*)malloc(strlen(name) + 1);// 申请堆区空间
		strcpy(pName,name);// 复制内容
		age = Age;
	}

	// 重载拷贝构造函数
	Student(const Student& stu)
	{
		cout << "自己的拷贝构造函数" << endl;
		// 重新申请一块内存空间
		pName = (char*)malloc(sizeof(char) * (strlen(pName) + 1));
		// 拷贝数据
		strcpy(pName,stu.pName);
		age = stu.age;
	}


	// 申请堆区空间 一定要释放
	~Student()
	{
		if (pName != NULL)
		{
			free(pName);
			pName = NULL;
		}
	}

	void print()
	{
		cout << "名字 = " << pName << "年纪 = " << age << endl;
	}

private:
	char* pName;
	int age;
};

void test01()
{
	Maker a(1, 1);
	a.print();

	Maker b(a);// 拷贝构造函数  浅复制
	b.print();
}


void test02()
{
	Student a("xxx",1);
	a.print();

	// 复制的是地址

	// 导致同一块内存地址空间被析构函数销毁两次
	Student b(a);
	b.print();
}

int main()
{
	test02();

	return EXIT_SUCCESS;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少写代码少看论文多多睡觉

求打赏,求关注,求点赞

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值