C++核心编程——4.2(2)对象的初始化和清理

4.2.5 深拷贝与浅拷贝

浅拷贝:编译器提供的简单的赋值拷贝操作

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

示例:

class Person {
public:
	//无参(默认)构造函数
	Person() {
		cout << "无参构造函数!" << endl;
	}
	//有参构造函数
	Person(int age ,int height) {
		
		cout << "有参构造函数!" << endl;

		m_age = age;
		m_height = new int(height); //利用关键字new把身高放在堆区,返回的是一个地址
		
	}
	//拷贝构造函数  
	Person(const Person& p) {
		cout << "拷贝构造函数!" << endl;
		//如果不利用深拷贝在堆区创建新内存,会导致浅拷贝带来的重复释放堆区问题
        //自己写一个拷贝构造函数,解决浅拷贝带来的问题:在堆区再开辟一段空间
		m_age = p.m_age;
        //m_height = p.m_height (编译器自动提供时的拷贝构造函数写法)
		m_height = new int(*p.m_height);   //深拷贝重新开辟一块内存
		      //通过传入的地址进行解引用之后,再在堆区申请一块内存存入
	}

	//析构函数
	~Person() {
//析构代码,将堆区开辟的数据做释放操作(堆区的数据需要程序员手动开辟,也需要程序员手动释放)
//在对象销毁前对堆区的数据释放掉(test01执行完了之后),所以在析构函数时把数据释放干净
		cout << "析构函数!" << endl;
		if (m_height != NULL)   //如果该指针不为空,就将其用delete删除
		{
			delete m_height;
            m_height = NULL;   //防止野指针出现,将其置空
		}
	}
public:
	int m_age;
	int* m_height;      //用指针是为了把数据开辟到堆区
};

void test01()
{
	Person p1(18, 180);

	Person p2(p1);  //当我们不提供拷贝构造函数数,编译器自动帮我们提供,并且做浅拷贝

	cout << "p1的年龄: " << p1.m_age << " 身高: " << *p1.m_height << endl;

	cout << "p2的年龄: " << p2.m_age << " 身高: " << *p2.m_height << endl;
}

int main() {

	test01();

	system("pause");

	return 0;
}

具体差别如下图所示:

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

4.2.6 初始化列表

作用:

C++提供了初始化列表语法,为类中的属性进行初始化(类似于构造函数的初始化)

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

示例:

class Person {
public:

	传统方式初始化,创建对象同时赋值
	//Person(int a, int b, int c) {
	//	m_A = a;
	//	m_B = b;
	//	m_C = c;
	//}

	//初始化列表方式初始化
	Person(int a, int b, int c) :m_A(a), m_B(b), m_C(c) {}
	// 写法2:Person() :m_A(1), m_B(2), m_C(3) {}  但是值被固定,不够灵活
    void PrintPerson() {
		cout << "mA:" << m_A << endl;
		cout << "mB:" << m_B << endl;
		cout << "mC:" << m_C << endl;
	}
private:
	int m_A;
	int m_B;
	int m_C;
};

int main() {

	Person p(1, 2, 3);
    //对应类中的写法2:Person p; 
	p.PrintPerson();

	system("pause");
	return 0;
}

4.2.7 类对象作为类成员

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

构造函数:先构造类中的成员(调用类中成员的构造),再构造本类

析构函数:与构造顺序相反

例如:

class A {}
class B
{
    A a;
}

 示例:

class Phone
{
public:
	Phone(string name)
	{
		m_PhoneName = name;
		cout << "Phone构造" << endl;
	}

	~Phone()
	{
		cout << "Phone析构" << endl;
	}

	string m_PhoneName;

};


class Person
{
public:

	//初始化列表可以告诉编译器调用哪一个构造函数
    //相当于 Phone m_Phone = pName 隐式转换法用pName创建对象
	Person(string name, string pName) :m_Name(name), m_Phone(pName)
	{                                
		cout << "Person构造" << endl;
	}

	~Person()
	{
		cout << "Person析构" << endl;
	}
	
	string m_Name;
	Phone m_Phone;

};
void test01()
{
	//当类中成员是其他类对象时,我们称该成员为 对象成员
	//构造的顺序是 :先调用对象成员的构造,再调用本类构造
	//析构顺序与构造相反
	Person p("张三" , "华为mate60 Pro");
	cout << p.m_Name << " 使用" << p.m_Phone.m_PhoneName << " 手机! " << endl;

}


int main() {

	test01();

	system("pause");
	return 0;
}

4.2.8 静态成员

静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员;包括静态成员变量和静态成员函数。

静态成员变量 静态成员函数
特点
  • 所有对象共享同一份数据 (不属于任何一个对象上的)

(在内存中只有一个值,其他函数修改之后再调用也会变成修改后的值)

  • (程序还没有运行)在编译阶段分配内存

  • 类内声明,类外初始化(必须初始化否则无法使用)

  • 也是有访问权限的区别的

  • 所有对象共享同一个函数(同静态成员变量)

  • 静态成员函数只能访问静态成员变量(无法访问非静态成员变量)

  • 也有访问权限

调用方式(静态成员函数的调用要增加作用域)
  1. 通过对象进行访问(像之前一样正常通过 类名.变量名 进行访问)

  2. 通过类名进行访问(直接用变量的名字进行访问)

示例1 :静态成员变量

class Person
{
	
public:

	static int m_A; //静态成员变量(类内声明)

private:
	static int m_B; //静态成员变量也是有访问权限的
};
int Person::m_A = 10;   //类外初始化(为了说明是Person下的要写作用域Person::)
int Person::m_B = 10;

void test01()
{
	//静态成员变量两种访问方式

	//1、通过对象
	Person p1;
	p1.m_A = 100;
	cout << "p1.m_A = " << p1.m_A << endl;

	Person p2;
	p2.m_A = 200;           //用p2去修改m_A的值
	cout << "p1.m_A = " << p1.m_A << endl; //共享同一份数据
	cout << "p2.m_A = " << p2.m_A << endl;

	//2、通过类名
	cout << "m_A = " << Person::m_A << endl;


	//cout << "m_B = " << Person::m_B << endl; //私有权限访问不到
}

int main() {

	test01();

	system("pause");
	return 0;
}

示例2:静态成员函数

class Person
{

public:
	
	static void func()             //静态成员函数
	{
		cout << "func调用" << endl;
		m_A = 100;    //只能访问静态成员变量
		//m_B = 100; //错误,不可以访问非静态成员变量
        //非静态成员变量必须通过创建对象才能够调用,当调用静态成员函数(程序中只有一份值)不知道改变的是哪一个对象上面的非静态成员变量(无法区分)
	}

	static int m_A; //静态成员变量(类内声明)
	int m_B;       // 非静态成员变量
private:

	//静态成员函数也是有访问权限的
	static void func2()
	{
		cout << "func2调用" << endl;
	}
};
int Person::m_A = 10;  //(类外初始化)


void test01()
{
	//静态成员变量两种访问方式

	//1、通过对象
	Person p1;
	p1.func();

	//2、通过类名
	Person::func();    //不用对象直接通过类名进行调用(但是要写明作用域)


	//Person::func2(); //私有权限访问不到
}

int main() {

	test01();

	system("pause");
	return 0;
}

相关推荐

  1. C++核心编程:类对象 笔记

    2024-04-04 14:42:03       46 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-04 14:42:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-04 14:42:03       101 阅读
  3. 在Django里面运行非项目文件

    2024-04-04 14:42:03       82 阅读
  4. Python语言-面向对象

    2024-04-04 14:42:03       91 阅读

热门阅读

  1. 【数据结构与算法】动态规划

    2024-04-04 14:42:03       37 阅读
  2. Day20.

    2024-04-04 14:42:03       34 阅读
  3. LocalDateTime 前后端传输问题

    2024-04-04 14:42:03       34 阅读
  4. 从零开始学RSA:低加密指数攻击2

    2024-04-04 14:42:03       30 阅读
  5. 七、c++代码中的安全风险-strcpy

    2024-04-04 14:42:03       39 阅读
  6. 黑客常用端口利用总结

    2024-04-04 14:42:03       32 阅读