C++类与对象笔记

2023-05-16

C++类与对象笔记

本章主要讲了面向对象三大特性:封装,继承,多态

C++认为万事万物都皆为对象,对象上有其属性和行为

例如:

​ 人可以作为对象,属性有姓名、年龄、身高、体重…,行为有走、跑、跳、吃饭、唱歌…

​ 车也可以作为对象,属性有轮胎、方向盘、车灯…,行为有载人、放音乐、放空调…

​ 具有相同性质的对象,我们可以抽象称为类,人属于人类,车属于车类

1. 封装

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

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

1.1 封装的使用

​ 在设计类的时候,属性和行为写在一起,表现事物。

权限控制的关键字:

​ 1. public 公共权限 类内可以访问 类外可以访问

​ 2. private 私有权限 类内可以访问 类外不可以访问

​ 3. protected 保护权限 类内可以访问 类外不可以访问

​ 这几种关键字如果不需要则可以不写,class默认为私有。

示例:

class Person
{
//姓名  公共权限
public:
	string m_Name;
//汽车  保护权限
protected:
	string m_Car;
//银行卡密码  私有权限
private:
	int m_Password;
};
int main() {
	Person p;
	p.m_Name = "李四";
	//p.m_Car = "奔驰";  //保护权限类外访问不到
	//p.m_Password = 123; //私有权限类外访问不到
}

1.2 class 与 struct 的区别

​ 在C++中 struct和class唯一的区别就在于 默认的访问权限不同

示例:

class C1 {
	int  m_A; //默认是私有权限
};
struct C2 {
	int m_A;  //默认是公共权限
};
int main() {
	C1 c1;
	c1.m_A = 10; //错误,访问权限是私有
	C2 c2;
	c2.m_A = 10; //正确,访问权限是公共
}

1.3 成员属性设置为私有

​ 这样写可以自己控制访问权限,对于写权限,我们可以检测数据的有效性。

示例:

class Person {
public:
	// 姓名 设置可读可写
	void setName(string name) {
		m_Name = name;
	}
	string getName()
	{
		return m_Name;
	}
    // 年龄 设置可读可写
	void setAge(int age) {
		m_Age = age;
	}
    int getAge() {
		return m_Age;
	}
	// 情人设置为只写
	void setLover(string lover) {
		m_Lover = lover;
	}
private:
	string m_Name; 	//可读可写  姓名
	int m_Age; 		//只读  年龄
	string m_Lover; //只写  情人
};
int main() {
	Person p;
	//姓名设置
	p.setName("张三");
	cout << "姓名: " << p.getName() << endl;
	//年龄设置
	p.setAge(50);
	cout << "年龄: " << p.getAge() << endl;
	//情人设置
	p.setLover("苍井");
	//cout << "情人: " << p.m_Lover << endl;  //只写属性,不可以读取
}

2.对象的初始化与清理

生活中我们买的电子产品都基本会有出厂设置,在某一天我们不用时候也会删除一些自己信息数据保证安全

C++中的面向对象来源于生活,每个对象也都会有初始设置以及 对象销毁前的清理数据的设置。

2.1 构造函数与析构函数

​ 对象的初始化和清理也是两个非常重要的安全问题。

​ 1. 一个对象或者变量没有初始状态,对其使用后果是未知

​ 2. 同样的使用完一个对象或变量,没有及时清理,也会造成一定的安全问题

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

​ 1. 构造函数:主要作用在于创建对象时为对象的成员属性赋值,构造函数由编译器自动调用。

​ 2. 析构函数:主要作用在于对象销毁前系统自动调用,执行一些清理工作。

​ 如果我们不提供构造和析构,编译器会提供空实现的构造函数和析构函数。

示例:

class Person{};
int main() {	
	Person p;
    //  先执行构造函数,后执行了析构函数
}

2.2 构造函数的分类及调用

两种分类方式:

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

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

前置示例:

class Person {
public:
	//有参构造函数
	Person(int a) {
		age = a;
	}
	//拷贝构造函数
	Person(const Person& p) {
		age = p.age;
	}
	//析构函数
	~Person() {
	}
public:
	int age;
};

示例0 (无参调用法)

Person p1;
// 执行顺序:p1构造函数,p1析构函数。

示例1 (有参调用括号法)

Person p1(10);

// 注意:调用无参构造函数不能加括号,如果加了编译器认为这是一个函数声明
// Person p2();

// 执行顺序:p1构造函数,p1析构函数。

示例2 (有参调用显式法)

Person p1 = Person(10); 
Person p2 = Person(p2);	//拷贝构造
// Person(10)单独写就是匿名对象,当前行结束之后,马上析构

// 执行顺序:p1构造函数,p2拷贝函数,p2析构函数,p1析构函数。

示例3 (有参调用隐式转换法)

Person p1 = 10; // 相当于Person p1 = Person(10); 
Person p2 = p1; // 相当于Person p2 = Person(p1); //拷贝构造

// 注意:不能利用 拷贝构造函数 初始化匿名对象 编译器认为是对象声明
// Person p2(p1);

// 执行顺序:p1构造函数,p2拷贝函数,p2析构函数,p1析构函数。

2.3 拷贝构造函数调用时机

调用拷贝构造函数的三种情况:

​ 1. 一个已经创建完毕的对象来初始化一个新对象

​ 2. 值传递的方式给函数参数传值

​ 3. 以值方式返回局部对象

前置示例:

class Person {
public:
	Person() {
		mAge = 0;
	}
	Person(int age) {
		mAge = age;
	}
	Person(const Person& p) {
		mAge = p.mAge;
	}
public:
	int mAge;
};

示例1 (使用一个已经创建完毕的对象来初始化一个新对象):

Person man(100); 		//p对象已经创建完毕
Person newman(man); 	//调用拷贝构造函数
Person newman2 = man; 	//拷贝构造

//Person newman3;
//newman3 = man; 		//不是调用拷贝构造函数,赋值操作

示例2 (以值方式返回局部对象):

void func1(Person p1) {}
void func2() {
	Person p; 	//无参构造函数
	doWork(p);	//相当于Person p1 = p;
}

示例3 (以值方式返回局部对象):

Person doWork2() {
	Person p1;
	return p1;
}
void test03() {
	Person p = doWork2();	//相当于Person p = p1;
}

2.4 构造函数调用规则

类的默认函数:

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

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

​ 3.默认拷贝构造函数,对属性进行值拷贝

构造函数调用规则:

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

​ 2.如果用户定义拷贝构造函数,c++不会再提供其他默认构造函数

示例1 (用户定义有参构造):

class Person {
public:
    Person(int a) {
        age = a;
    }
public:
    int age;
}
int main() {
    Person p1;		// 会出错,编译器这种情况下不提供无参构造
    Person p2(10);	// 调用用户提供的有参构造
    Person p3(p2);	// 编译器提供的拷贝构造
}

示例2 (用户定义拷贝构造):

class Person {
public:
    Person(const Person& p) {
        age = p.age();
    }
public:
    int age;
}
int main() {
	Person p4; 		// 会出错,编译器这种情况下不提供无参构造
	Person p5(10); 	// 会出错,编译器这种情况下不提供有参构造
	Person p6(p5); 	// 用户自己提供拷贝构造
}

2.5 深拷贝与浅拷贝

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

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

示例1 (浅拷贝引发错误):

class Person {
public:
	Person(int age) {
		m_age = new int(age);	
	}
    // 默认拷贝函数好像是这样写,m_age直接指向了p.m_age;
    // Person(const Person& p) {
    //     m_age = p.m_age;
    // }
	~Person() {
		if (m_age != NULL){
			delete m_age;
			m_age = NULL;
		}
	}
	int* m_age;
};
int main() {
	Person p1(18, 180);
    Person p2(p1);
    // 由于栈区的规则是先进后出,当执行完拷贝构造函数的时候,就会执行p2的析构函数,导致释放堆区开辟的数据。因此当执行p1的析构函数时就会导致内存释放2次,程序崩溃。
}

示例 (使用深拷贝来避免错误):

class Person {
public:
	Person(int age) {
		m_age = new int(age);	
	}
    // 这样写如果执行拷贝函数则会创建一个新的空间,就不会出现重复释放的问题了
    Person(const Person& p) {
        m_age = new int(*p.m_age);
    }
	~Person() {
		if (m_age != NULL){
			delete m_age;
			m_age = NULL;
		}
	}
	int* m_age;
};
int main() {
	Person p1(18, 180);
    Person p2(p1);
    // 正常运行,没有出现程序崩溃
}

2.6 初始化列表

​ C++提供了初始化列表语法,用来初始化属性,是一种相对方便的写法。

示例:

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) {}
	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);
	p.PrintPerson();
}

2.7 类对象作为类成员

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

​ 那么当创建对象时,对象与对象成员的构造和析构的顺序是谁先谁后?

示例 :

class Test1{
};
class Test2{
    Test1 test;
};
int main(){
    Test2 good;
    // 此时的调用顺序为:Test1的构造,Test2的构造,Test2的析构,Test1的析构。
}

2.8 静态成员

​ 静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员,分为以下两种。

静态成员变量

​ 1. 所有对象共享同一份数据

​ 2. 在编译阶段分配内存

​ 3. 类内声明,类外初始化

静态成员函数

​ 1. 所有对象共享同一个函数

​ 2. 静态成员函数只能访问静态成员变量

示例1 (静态成员变量):

class Person {	
public:
	static int m_A; //静态成员变量
private:
	static int m_B; //静态成员变量也是有访问权限的
};
int Person::m_A = 10;
int Person::m_B = 10;
int main() {
	//静态成员变量两种访问方式

	//1、通过对象
	Person p1;
	p1.m_A = 100;
	cout << "p1.m_A = " << p1.m_A << endl; // 100
	Person p2;
	p2.m_A = 200;
	cout << "p1.m_A = " << p1.m_A << endl; // 200 共享同一份数据
	cout << "p2.m_A = " << p2.m_A << endl; // 200

	//2、通过类名
	cout << "m_A = " << Person::m_A << endl; // 200
	//cout << "m_B = " << Person::m_B << endl; //私有权限访问不到
}

示例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;
int main() {
	//静态成员变量两种访问方式

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

	//2、通过类名
	Person::func();
	//Person::func2(); //私有权限访问不到
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++类与对象笔记 的相关文章

  • jetson 系列 安装完jetpack/已安装 tensorrt 在虚拟环境中仍然报 no module named tensorrt >> 在虚拟环境建立软连接

    当使用虚拟环境时 xff0c 需要考虑 cv2 和 tensorrt 是一样的 更新 xff1a cv2 应该是对的 tensorrt的处理是错的 xff0c 在 使用 trt时很多方法都找不到 正确的加入虚拟环境的方法 xff1a htt
  • Tesla T4 在Ubuntu18.04上的安装使用

    Tesla T4 在Ubuntu18 04上的安装使用 在默认情况下 xff0c 安装 tesla T4 的驱动 xff0c 尝试很多版本都无法正确安装 xff0c 安装完之后会出现 xff1a nvidia smi NVIDIA SMI
  • cannot import name ‘gcd’ from ‘fractions’

    cannot import name gcd from fractions 在这里插入图片描述 在3 9
  • 【Java 实战】通过Redis 和 MQ 简单实现秒杀功能

    项目场景 实现一个商品秒杀的功能 能后台自定义秒杀时间段 商品库存等信息 一 设计思路 这里简单分享下思路 1 限流 秒杀时大量用户会在同一时间同时进行抢购 网站瞬时访问流量激增 由于只有少部分用户能够秒杀成功 所以要限制大部分流量 只允许
  • mariadb设置默认字符编码

    mariadb version 10 3 7 mariadb安装目录下找到data文件夹 xff0c 下面有个my ini文件 xff0c 该文件为mariadb服务启动加载文件 由于之前各种原因 xff0c 也搜索过博文 xff0c 但是
  • 多线程编程以及线程池相关记录

    Java 中经常需要用到多线程来处理一些业务 xff0c 非常不建议单纯使用继承Thread或者实现Runnable接口的方式来创建线程 xff0c 那样势必有创建及销毁线程耗费资源 线程上下文切换问题 同时创建过多的线程也可能引发资源耗尽
  • Spring Application Context 注入问题

    熟悉spring bean生命周期的都知道 xff0c 在其生命周期中有个很重要的接口 xff1a Aware 如果要注入application xff0c 可以用如下方式 64 Component public class SpringC
  • 解决我遇到的apt-get ,(Depends: AAA(>= BBB)but it is not going to install)的问题

    因为我直接把ubuntu16的源复制给了18的系统 xff0c 报错 xff0c 网上查说要换源我没懂啥意思 原来每个版本的源不一样 xff0c 这里贴一下清华的16和18的源 修改源文件source list xff08 1 xff09
  • IIS 网页在每天第一次打开慢的原因及解决

    今天碰到一个问题 xff0c 我们的网页在早晨的时候打开总是很慢 xff0c 其它时间有时也比较慢 开始认为是服务器性能的问题 xff0c 监测服务器资源使用后 xff0c 发现服务器的资源没有在高水平运行 xff0c 可以确定不是服务器硬
  • 【考研】操作系统——高速缓存与缓冲区、设备分配的数据结构

    一 磁盘高速缓存 操作系统中使用磁盘高速缓存技术是指利用内存中的存储空间来暂存从磁盘中读出的一系列盘块中的信息 xff0c 用以提高磁盘的 I O 速度 xff0c 对高速缓存复制的访问要比原始数据访问更为高效 二 缓冲区 xff08 一
  • Linux 系统的centos8安装jdk 1.8 教程

    卸载openjdk 查看rpm qa grep jdk 卸载yum y remove java 1 7 0 openjdk 1 7 0 75 2 5 4 2 el7 方法一 安装包手动安装 1 下载并上传 官网下载 我的备份 将我们下载好的
  • 解决Matlab2014A在win10下字体模糊的问题

    右击快捷方式 xff0c 进入属性设置 兼容性 更高高DPI设置 高DPI缩放替代 打钩 xff0c 下拉菜单选择应用程序
  • android工程师开发IOS oc浅析(14)之MRC与ARC

    1 为什么要进行内存管理 管理的是什么 内存管理 管理的是任何继承自NSObject的对象 因为一般的其他基本数据类型的局部变量都是储存在栈区的 当代码块执行结束 代码块中的局部变量出作用于就会被回收 而OC对象则不一样 OC对象类型是程序
  • Github个人主页绑定域名实操

    由于笔者在上传文件到github仓库 xff0c 由于相关操作经常会间歇性遗忘 xff08 还是不够熟悉惹的祸啊 xff09 xff0c 或者部分解决方案里并没有明确说明指令所表示的含义 xff0c 所以在百度了许多许多的相关文章和blog
  • spring 注解作用与解析过程

    64 PostConstruct 作用 xff1a 初始化方法之前执行 xff0c 作用于方法 xff0c 无方法上修饰符限制 解析过程 xff1a CommonAnnotationBeanPostProcessor xff08 BeanF
  • 关于Goland调试不可以使用

    今天在使用Goland时发现Goland断点调试无法使用 如下图所示 在找了半天之后在某论坛找到了原因 结果是360把Go的程序截拦导致无法断点调试 关闭360 重新打开文件即可使用
  • MySQL导入含有触发器的sql脚本报错解决方案

    报错码 ERROR 1419 HY000 You do not have the SUPER Privilege and Binary Logging is Enabled 解决方案 1 Linux下执行sql脚本 我们一般在linux服务
  • maven 本地仓库的配置以及如何修改默认.m2仓库位置

    本人转载于http blog csdn net qq 27093465 article details 52957253 以下为转载内容 xff1a 本地仓库是远程仓库的一个缓冲和子集 xff0c 当你构建Maven项目的时候 xff0c
  • onNewIntent 作用

    当Activity启动模式为singleTask时 如果在栈中已经有该Activity的实例 xff0c 就重用该实例 会调用实例的onNewIntent 不会调用onCreate方法 重用时 xff0c 会让该实例回到栈顶 xff0c 因
  • xml与txt文件格式互换

    当前遇到一个问题 xff0c 需要将txt格式的文件转换为xml格式的文件 xff0c 网上找了挺多的方法 xff0c 也成功了 但用时比较麻烦 xff0c 考虑到后期程序的需要 xff0c 决定开发一个小程序 耗时两个半天 xff0c 终

随机推荐

  • Spring中自定义注解的解析过程-学习

    Spring中自定义注解的解析过程 学习 在学习spring源码的过程中 xff0c 最好奇的一件事就是Sprint的注解是怎么被读取到的 xff0c 又是怎么进行解析的 然后又是怎么将注解的内容注入到spring容器中的 带着这个好奇心
  • [RK3399][Android7.1] 调试笔记 --- 移除/删除Settings的Preference的三种方法小结

    Platform RK3399 MID OS Android 7 1 2 Kernel v4 4 83 需求 xff1a 整理一下移除 删除Settings的Preference三种方法 xff1b 方法一 xff1a 对于 Prefere
  • windows server 2008 R2服务器系统密码破密

    问题 xff1a 管理员administrator密码忘记 前提 xff1a 服务器型号Dell S130 2 系统2008R2 3 系统带有阵列驱动 准备工具 xff1a 1 2008R2系统光盘 xff0c 2016 R2系统光盘 2
  • Java 经典例题:生产者/消费者问题

    Java 经典例题 xff1a 生产者 消费者问题 1 问题2 分析3 demo 1 问题 生产者 Productor 将产品交给店员 Clerk xff0c 而消费者 Customer 从店员处取走产品 xff0c 店员一次只能持有固定数
  • angular2如何识别字符串中的html标签,并按照html来显示视图

    这个源于一个需求 xff1a 从后台拿到用户评论的内容 xff0c 该内容是字符串的 xff0c 但是里面包含了html代码 要求显示的时候按照html来显示 xff0c 不是按照字符串来显示 并且要求任意的段文字添加样式 xff1b 思路
  • 使用虚拟机安装kali Linux遇到的运行问题

    最近在虚拟机上安装Linux xff0c 谁知道在运行安装的时候 xff0c 竟然报这个错误 xff0c 唯恐以后学习中再次遇到同样的问题 xff0c 以至于手忙脚乱 xff0c 所以在此做下收录 出现此类问题是因为360安全防护中心的In
  • 安装kali2.0之后,如何从Windows中通过SecureCRT工具远程到kali中呢?

    xfeff xfeff 1 在kali的终端输入 etc init d ssh status 回车 xff0c 用来查看kali中SSH服务状态 xff1b 由上图可知 xff0c kali Linux 默认情况下SSH服务是inactiv
  • 虚拟机权限不足,无法访问文件

    今天在使用虚拟机的时候 xff0c 出现了一个报错 xff0c 一下子懵逼了 xff0c 找度娘百度了一下 xff0c 各种答案五花八门 xff0c 但是根本木有卵用 xff0c 问题如下图 xff1a 解决方案是 xff1a 现在关掉虚拟
  • 如何使用英文界面的JMETER

    如何使用英文界面的JMETER JMETER启动时会自动判断操作系统的 locale 并选择合适的语言启动 xff0c 所以 xff0c 我们启动JMETER 后 xff0c 会出现一个倍感亲切的中文界面 但由于JMETER 本身的汉化工作
  • 在CMD命令行模式下运行.py文件,提示:无法初始化设备PRN

    在CMD命令行模式下运行 py文件 xff0c 提示 xff1a 无法初始化设备PRN 问题的重现步骤 xff1a 首次学习python xff0c 不知道 py文件是如何创建的 xff0c 故新建了一个txt文件 xff0c 添加完内容之
  • office 2010 Word,Excel的功能区突然消失了

    office 2010 Word Excel的功能区突然消失了 xff0c 点击展开功能区无效 在网上搜了很久没有找到解决办法 Office都卸载重装过还是无法解决 在网上找到一个方法 xff1a 将com加载项的ntkofficecont
  • IndentationError:expected an indented block

    xfeff xfeff 在用python写判断语句时 xff0c 报错 错误语句写法如下 xff1a 报错信息如下 xff1a 解决方案如下 xff1a 在print前面加上Tab 问题迎刃而解
  • kindeditor使用可能遇到的问题

    1 音视频上传不能播放问题 xff08 使用自定义video标签 xff09 更改kindeditor all min js中的 mediaImg方法 function mediaImg blankPath attrs if attrs s
  • manjaro21折腾笔记

    1 换源以及更新 1 1 配置镜像源 span class token function sudo span pacman mirrors i c China m rank 输入后会出现源列表选项 xff0c 全选即可 1 2 设置源 打开
  • 最简nvim配置

    1 安装nvim span class token function sudo span span class token function apt get span span class token function install sp
  • 竟然可以在Windows下用Nvim写代码?2.nvim基础插件配置

    在windows下用nvim写代码 使用wsl和terminal简直不要太方便 保姆级教学 一篇就够了 一 下载plug 可以用指令安装 curl fLo config nvim autoload plug vim create dirs
  • vscode国内源下载

    https az764295 vo msecnd net stable ea3859d4ba2f3e577a159bc91e3074c5d85c0523 VSCodeUserSetup x64 1 52 1 exe 将官方下载地址的域名更换
  • linux下搜狗拼音隐藏悬浮状态栏

    打开配置文件 vim config sogoupinyin conf env ini 找到以下内容 并修改为0 StatusAppearance 61 0 重启fcitx状态栏就消失了 killall fcitx fcitx
  • JavaScript笔记(2)

    7 对象 xff1a 对象的三种声明与调用方法 span class token comment 第一种声明方法 span span class token keyword let span ObjectName span class to
  • C++类与对象笔记

    C 43 43 类与对象笔记 本章主要讲了面向对象三大特性 xff1a 封装 xff0c 继承 xff0c 多态 C 43 43 认为万事万物都皆为对象 xff0c 对象上有其属性和行为 例如 xff1a 人可以作为对象 xff0c 属性有