C++ 学习笔记(3) 封装

本文详细介绍了C++中的封装概念,包括权限控制(public、protected、private)以及其意义。接着讲解了构造函数和析构函数的作用,用于对象初始化和清理。还探讨了构造函数的分类和调用方式,如无参构造、有参构造、拷贝构造,并通过示例展示了不同构造函数的使用。最后,文章深入讨论了深拷贝和浅拷贝的区别,强调了在处理指针时深拷贝的重要性,以避免内存问题。
摘要由CSDN通过智能技术生成

C++ 学习笔记(3) 封装

封装是C++面向对象三大特性之一

1. 封装的意义与权限

封装的意义(1)

  • 将属性和行为作为一个整体,表现生活中的事物
  • 将属性和行为加以权限控制

封装的意义(2)

类在设计时,可以把属性和行为放在不同的权限下,加以控制。
在c++中,共有三种权限:
公共权限 public : 类内可以访问 类外可以访问
保护权限 protected: 类内可以访问 类外不可以访问
私有权限 private: 类内可以访问 类外不可以访问

2.成员属性设置为私有

优点1:将所有成员属性设置为私有,可以自己控制读写权限

优点2:对于写权限,我们可以检测数据的有效性

3.构造函数和析构函数

对象的初始化和清理是两个非常重要的安全问题。一个对象或者变量没有初始状态,对其使用后果是未知。同样的使用完一个对象或变量,没有及时清理,也会造成一定的安全问题

c++利用了构造函数析构函数解决上述问题,这两个函数将会被编译器自动调用,完成对象初始化和清理工作。

对象的初始化和清理工作是编译器强制要我们做的事情,因此如果我们不提供构造和析构,编译器会提供

编译器提供的构造函数和析构函数是空实现。

  • 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用,无须手动调用。
  • 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

构造函数语法:类名(){}

  1. 构造函数,没有返回值也不写void
  2. 函数名称与类名相同
  3. 构造函数可以有参数,因此可以发生重载
  4. 程序在调用对象时候会自动调用构造,无须手动调用,而且只会调用一次

析构函数语法: ~类名(){}

  1. 析构函数,没有返回值也不写void
  2. 函数名称与类名相同,在名称前加上符号 ~
  3. 析构函数不可以有参数,因此不可以发生重载
  4. 程序在对象销毁前会自动调用析构,无须手动调用,而且只会调用一次
3.1 构造函数的分类及调用

两种分类方式:

​ 按参数分为: 有参构造和无参构造

​ 按类型分为: 普通构造和拷贝构造

三种调用方式:

括号法

显示法

隐式转换法

利用有参构造函数,括号法初始化对象属性:

#include<iostream>
#include<string>
using namespace std;
class student {
public:
	student() {
		cout << "无参即默认构造函数" << endl;
	}
	student(int Age)
	{
		age = Age;
		cout << "有参构造函数" << endl;
		
	}
	student(const student & tmp)
	{
		age = tmp.age;
		cout << "自己建立的拷贝函数,即深拷贝" << endl;
	}
	~student()
	{
		cout << "默认析构函数" << endl;
	}
public:
	int age;
};
void test1()
{
	student laowang(20);
	cout << "利用有参构造函数,括号法初始化对象属性: " << laowang.age<<endl;
	
}
int main()
{
	
	test1();
}

利用有参构造函数,显示法初始化对象属性:

#include<iostream>
#include<string>
using namespace std;
class student {
public:
	student() {
		cout << "无参即默认构造函数" << endl;
	}
	student(int Age)
	{
		age = Age;
		cout << "有参构造函数" << endl;
		
	}
	student(const student & tmp)
	{
		age = tmp.age;
		cout << "自己建立的拷贝函数,即深拷贝" << endl;
	}
	~student()
	{
		cout << "默认析构函数" << endl;
	}
public:
	int age;
};
void test1()
{
	student laowang=student(30);
	cout << "利用有参构造函数,显示法初始化对象属性: " << laowang.age<<endl;
	
}
int main()
{
	
	test1();
}

利用有参构造函数,隐式转换法初始化对象属性:

#include<iostream>
#include<string>
using namespace std;
class student {
public:
	student() {
		cout << "无参即默认构造函数" << endl;
	}
	student(int Age)
	{
		age = Age;
		cout << "有参构造函数" << endl;
		
	}
	student(const student & tmp)
	{
		age = tmp.age;
		cout << "自己建立的拷贝函数,即深拷贝" << endl;
	}
	~student()
	{
		cout << "默认析构函数" << endl;
	}
public:
	int age;
};
void test1()
{
	student laowang=30;
	cout << "利用有参构造函数,隐式转换法初始化对象属性: " << laowang.age<<endl;
	
}
int main()
{
	
	test1();
}

利用拷贝构造函数,显示法初始化对象属性:

#include<iostream>
#include<string>
using namespace std;
class student {
public:
	student() {
		cout << "无参即默认构造函数" << endl;
	}
	student(int Age)
	{
		age = Age;
		cout << "有参构造函数" << endl;
		
	}
	student(const student & tmp)
	{
		age = tmp.age;
		cout << "自己建立的拷贝函数,即深拷贝" << endl;
	}
	~student()
	{
		cout << "默认析构函数" << endl;
	}
public:
	int age;
};
void test1()
{
	student xiaowang(10);
	student laowang(xiaowang);
	cout << "利用拷贝构造函数,显示法初始化对象属性: " << laowang.age<<endl;
	
}
int main()
{
	
	test1();
}

显示结果为:
在这里插入图片描述
其中,创建了两个对象,首先调用了一次有参构造函数,进行初始化,再利用拷贝函数对laowang这个对象进行初始化。

3.2 构造函数调用规则

默认情况下,c++编译器至少给一个类添加3个函数

  1. 默认构造函数(无参,函数体为空)

  2. 默认析构函数(无参,函数体为空)

  3. 默认拷贝构造函数,对属性进行值拷贝(也叫浅拷贝

构造函数调用规则如下:

  • 如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造

  • 如果用户定义拷贝构造函数,c++不会再提供其他构造函数

3.2 深拷贝与浅拷贝

浅拷贝:简单的赋值拷贝操作,包括默认拷贝构造函数

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

#include<iostream>
#include<string>
using namespace std;
class student {
public:
	student(int Age,int Height)
	{
		age = Age;
		height = new int(Height);
		cout << "有参构造函数" << endl;
	}
	student(const student & tmp)
	{
		age = tmp.age;
		height = tmp.height;
		//height = new int(*tmp.height);
		cout << "自己实现拷贝构造函数,实现浅拷贝" << endl;
	}
	~student()
	{
		if (height != NULL)
		{
			delete height;
			height = NULL;
		}
		cout << "析构函数释放堆中的指针数据" << endl;
	}
	//student()
public:
	int age;
	int* height;
};
int main()
{
	student a(18,180);
	student b(a);
	cout << "b.age" << b.age << endl;

}
}

上述代码没有语法错误,但是在执行时会出现异常错误。这是因为由于浅拷贝在设计指针时产生了堆区内存重复释放的问题,如下图所示:
在这里插入图片描述

解决办法:利用深拷贝,在堆中利用new再开辟一个内存区域,如下图:在这里插入图片描述
代码如下:

#include<iostream>
#include<string>
using namespace std;
class student {
public:
	student(int Age,int Height)
	{
		age = Age;
		height = new int(Height);
		cout << "有参构造函数" << endl;
	}
	student(const student & tmp)
	{
		age = tmp.age;
		//height = tmp.height;
		height = new int(*tmp.height);
		cout << "自己实现拷贝构造函数,实现深拷贝" << endl;
	}
	~student()
	{
		if (height != NULL)
		{
			delete height;
			height = NULL;
		}
		cout << "析构函数释放堆中的指针数据" << endl;
	}
	//student()
public:
	int age;
	int* height;
};
int main()
{
	student a(18,180);
	student b(a);
	cout << "b.age:" << b.age << endl;

}
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值