对象的初始化与清理部分_2

五、深拷贝与浅拷贝

浅拷贝:简单的拷贝赋值操作

深拷贝:在堆区重新开辟空间,进行拷贝操作

下面举例解释:

创建person类与测试函数

class person
{
public:
	person()
	{
		cout << "person默认构造函数调用" << endl;
	}
	person(int age, int height)
	{
		m_age = age;
		m_height = new int(height);
		cout << "person有参构造函数调用" << endl;
	}

	~person()
	{
		cout << "person析构函数调用" << endl;
	}

	int m_age;
	int* m_height;
};

void test01()
{
	person p1(22,179);
	cout << "年龄为" << p1.m_age << "身高为" << *p1.m_height << endl;

	person p2(p1);
	cout << "年龄为" << p2.m_age << "身高为" << *p2.m_height << endl;
}

对象的初始化与清理部分_2_第1张图片

此时p1/p2的各个属性都是相同

而此时,由于属性中m_height是我们new出的堆区的数据,需要我们手动释放,因此我们在析构函数中写出释放的部分

	~person()
	{
		if (m_height != NULL)
		{
			delete m_height;
			m_height = NULL;
		}
		cout << "person析构函数调用" << endl;
	}

再次运行

对象的初始化与清理部分_2_第2张图片

 程序直接崩了

因为编译器自己的拷贝构造函数是浅拷贝操作

对象的初始化与清理部分_2_第3张图片

 浅拷贝带来的问题就是堆区内存重复释放

因此,使用深拷贝解决,我们自己创建一块堆区保存数据,即自己实现拷贝构造函数

person(const person& p)
	{
		m_age = p.m_age;
		//m_height = p.m_height; //编译器默认实现,即浅拷贝
		m_height = new int(*p.m_height);
		cout << "person拷贝构造函数调用" << endl;
	}

对象的初始化与清理部分_2_第4张图片

 成功实现

 总结:如果属性有在堆区开辟的,自己要提供拷贝构造函数,防止浅拷贝带来问题

六、初始化列表

作用:使用初始化列表语法来初始化属性

语法:

构造函数() : 属性1(值1),属性2(值2),属性3(值3)...
{
	;
}

例:

一般情况下,我们初始化是创建对象同时赋值

class person
{
public:

	person(int a, int b, int c)
	{
		m_a = a;
		m_b = b;
		m_c = c;
	}

	int m_a;
	int m_b;
	int m_c;
};
void test01()
{
	person p(10, 20, 30);
	cout << p.m_a << endl;
	cout << p.m_b << endl;
	cout << p.m_c << endl;
}

接下来使用初始化列表的方式初始化值

class person
{
public:

	person() :m_a(30), m_b(20), m_c(10)
	{
		;
	}
	int m_a;
	int m_b;
	int m_c;
};
void test01()
{
	person p;
	cout << p.m_a << endl;
	cout << p.m_b << endl;
	cout << p.m_c << endl;
}

这样就实现了列表初始化值,不过这样初始化的值是固定的,可以进一步优化

七、类对象作为类成员

C++中某个类的成员可以是另一个类的对象,称该成员为对象成员


创建2个类:person类与car类,在person中定义2个属性,1个是人名,1个是车名,而车名来自于car类

class car // 车类
{
public:
	car(string car)
	{
		c_car = car;
		cout << "car的执行" << endl;
	}
	string c_car;
};
class person // 人类
{
public:
	person(string name, string c_car) :m_name(name), m_car(c_car)
	{
		cout << "person的执行" << endl;
	}

	string m_name;
	car m_car;
};
void test01()
{
	person p("Joyce", "BMW");
	cout << p.m_name << "开着" << p.m_car.c_car << endl;
}
int main()
{
	test01();
	return 0;
}

而两个类,哪个先执行,哪个先销毁

分别在2个类中增加一句person/car的执行,即可得知哪个先执行

分别在2个类中增加析构函数并输出内容,即可得知哪个先销毁

class car
{
public:
	car(string car)
	{
		c_car = car;
		cout << "car的执行" << endl;
	}
	~car()
	{
		cout << "car析构的执行" << endl;
	}
	string c_car;
};
class person
{
public:
	person(string name, string c_car) :m_name(name), m_car(c_car)
	{
		cout << "person的执行" << endl;
	}
	~person()
	{
		cout << "person析构的执行" << endl;
	}
	string m_name;
	car m_car;
};

对象的初始化与清理部分_2_第5张图片

总结:

①先调用对象成员的构造,再调用本类的构造

②析构刚好相反 

八、静态成员

含义:即在成员变量和成员函数前加上关键字static,称为静态成员

分类:

静态成员变量 所有对象共享同一份数据
在编译阶段分配内存
类内声明,类外初始化
静态成员函数 所有对象共享同一个函数
静态成员函数只能访问静态成员变量

例①:静态成员变量

class person
{
public:
	static int m_age;
};
void test01()
{
	person p;
	cout << p.m_age << endl;
}
int main()
{
	test01();
	return 0;
}

简单创建p,尝试运行p中的静态成员变量,会直接报错,因为编译不过去

	//	①通过对象进行访问
	person p;
	cout << p.m_age << endl;

	//	②通过类名进行访问
	cout << person::m_age << endl;

 这时需要加上类外初始化

类外随便加一句

int person::m_age = 52;

同时,静态成员变量有2种访问方式

①通过对象进行访问

②通过类名进行访问

	//	①通过对象进行访问
	person p;
	cout << p.m_age << endl;

	//	②通过类名进行访问
	cout << person::m_age << endl;

而对象访问这里我们再创建一个变量,即可验证静态成员变量共享同一块数据

void test02()
{
	//	①通过对象进行访问
	person p;
	cout << p.m_age << endl;

	person p2;
	p2.m_age = 66;
	cout << p.m_age << endl;
}

2次都输出p.m_age

对象的初始化与清理部分_2_第6张图片


同时,静态成员变量也有访问权限

class person
{
private:
	int m_a;
};
int person::m_a = 22;

尝试cout输出

对象的初始化与清理部分_2_第7张图片

 例②:静态成员函数

整体与静态成员变量规则相同,只不过在函数前加上static

class person
{
public:
	static	void func()
	{
		m_a = 55;
		cout << "func的调用" << endl;
	}
	static int m_a;
};
int person::m_a = 50;
void test01()
{
	// 通过对象访问
	person p;
	p.func();

	// 通过类名访问
	person::func();
}
int main()
{
	test01();
	return 0;
}

对象的初始化与清理部分_2_第8张图片


不过,首先静态成员函数只能访问静态成员变量

class person
{
public:
	static	void func() // 静态成员函数
	{
		m_a = 55;
		m_b = 10;
		cout << "func的调用" << endl;
	}
	static int m_a; // 静态成员变量
	int m_b;	// 普通成员变量
};

对象的初始化与清理部分_2_第9张图片

 直接报错


同时,静态成员函数也有访问权限

class person
{
private: // 私有权限
	static	void func2() // 静态成员函数
	{
		cout << "func2的调用" << endl;
	}
};

对象的初始化与清理部分_2_第10张图片

不可访问 

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