C++类和对象详解(一)

目录

  • 面向过程和面向对象初步认识
  • 类的引入
  • 类的定义
    • 类的两种定义方式
      • 声明和定义全部放在类体中
    • 声名定义分离
  • 类的作用域
    • 成员变量命名规则建议
    • 访问限定符
  • 类的封装
  • 类的实例化
  • 类对象模型
    • 类的对象大小的计算
      • 扩展
    • 结构体内存对齐规则

感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接
🐒🐒🐒 个人主页
🥸🥸🥸 C语言
🐿️🐿️🐿️ C语言例题
🐣🐣🐣 python
🐓🐓🐓 数据结构C语言
🐔🐔🐔 C++
🐿️🐿️🐿️ 文章链接目录

面向过程和面向对象初步认识

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

我们以洗衣服例:
C语言洗衣服关注的是过程:放洗衣粉 搓衣服 换水 搓衣服 拧干 晾衣服

C++洗衣服关注的是对象: 人 衣服 洗衣粉 ,因为整个过程是由这三个对象共同完成的,不需要关注具体怎么洗衣服

类的引入

C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。
比如:之前在数据结构文章中,用C语言方式实现的栈,结构体中只能定义变量;现在以C++方式实现,会发现struct中也可以定义函数,在C++入门基础(三)中有演示过

struct test
{
	int a;
	int b;
	void Init()
	{
		cin >> a;
		cin >> b;
	}
	int Add()
	{
		return a+b;
	}
};
int main()
{
	struct test t1;
	test t2;
	cout << "输入t1中a和b的值" << endl;
	t1.Init();
	cout  <<"t1Add:" << t1.a << "+" << t1.b << "=" << t1.Add() << endl;
	cout << "输入t2中a和b的值" << endl;
	t2.Init();
	cout << "t2Add:" << t2.a << "+" << t2.b << "=" << t2.Add() << endl;
	return 0;
}

在这里插入图片描述
上面代码中struct test t1为C语言的用法,而 test t2是因为C++将结构体升级成了类,因为类名代表类型,test代表这个类的类型,所以struct可以省略掉
上面结构体的定义,在C++中更喜欢用class来代替
有了class之后一般就不像C语言中的结构体那样定义结构体了,比如class test t1一般写成test t1

类的定义

class className
{
 // 类体:由成员函数和成员变量组成
 
};  // 一定要注意后面的分号

class为定义类的关键字,ClassName为类的名字,{}中为类的主体(注意类定义结束时后面分号不能省略)

类体中内容称为类的成员:
类中的变量称为类的属性或成员变量(一般情况下类的成员变量都是私有的,因为不希望有人直接去修改成员变量,一般都是通过成员函数去修改,但是这个不是强制要求的)
类中的函数称为类的方法或者成员函数。

类的两种定义方式

声明和定义全部放在类体中

注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理

class Stack
{
private:
	int* a;
	int top;
	int capacity;
public:
	void Init(int n)
	{
		a = (int*)malloc(sizeof(int) * n);
		if (nullptr == a)
		{
			perror("malloc申请空间失败");
			return;
		}
		capacity = n;
		top = 0;
	}
	void Push(int x)
	{
		//...
		a[top++] = x;
	}
};

声名定义分离

声明放在.h文件中,成员函数定义放在.cpp文件中

//Stack.h
#include<iostream>
using namespace std;
class Stack
{
private:
	int* a;
	int top;
	int capacity;
public:
	void Init(int n = 4);
	void Push(int x);
};
//Stack.cpp
#include"Stack.h"
void Init(int n )
{
	a = (int*)malloc(sizeof(int) * n);
	if (nullptr == a)
	{
		perror("malloc申请空间失败");
		return;
	}
	capacity = n;
	top = 0;
}
void Push(int x)
{
	//...
	a[top++] = x;
}

当运行代码的时候,我们发现报错了
在这里插入图片描述

注意这个报错不是因为private的原因,因为如果是private的原因报错会明确说出无法访问,并告诉你是private的原因

根据上面的报错,未定义标识符说明这些变量都没有定义,而未定义是因为找不到这些变量的出处,也就是不知道在哪定义的
编译器搜索默认都是在局部域和全局域中搜索,所以因为在Stack.cpp中没有定义这些变量,所以才会报错,所以需要让编译器去搜索Stack.h里的某个域

类的作用域

类定义了一个新的作用域,类的所有成员都在类的作用域中。在类体外定义成员时,需要使用 ::
作用域操作符指明成员属于哪个类域。

除了全局域,其他的域都是用花括号括起来的

域的存在就可以解决函数名重复的问题

class Stack
{
private:
	int* a;
	int top;
	int capacity;
public:
	void Init(int n = 4);
	void Push(int x);
};
class Queue
{
public:
	void Init(int n);
	void Push(int x);
};

有了域就可以使两个类中有相同名称的函数

所以上面代码中的报错是将Stack.cpp文件的函数当成了全局函数

域作用限定符是加载函数类型的右边

void Stack::Init(int n )
{
	a = (int*)malloc(sizeof(int) * n);
	if (nullptr == a)
	{
		perror("malloc申请空间失败");
		return;
	}
	capacity = n;
	top = 0;
}
void Stack::Push(int x)
{
	//...
	a[top++] = x;
}

在这里插入图片描述

成员变量命名规则建议

class Date
{
	void Init(int year,int month,int day)
	{
		year = year;
		month = month;
		day = day;
	}
	int year;
	int month;
	int day;
};

上面的year month day很容易让人产生误会,为了很好的区分,推荐下面的这种写法

class Date
{
	void Init(int year,int month,int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	int _year;
	int _month;
	int _day;
};

当运行代码的时候,却发现报错了,显示的是不可访问
在这里插入图片描述
而当我们把class换成struct后却又可以正常运行了,说明class中有什么东西限制了访问
在这里插入图片描述

访问限定符

C++实现封装的方式:用类将对象的属性与方法结合在一块,让对象更加完善,通过访问权限选择性的将其接口提供给外部的用户使用。
在这里插入图片描述

  1. public修饰的成员在类外可以直接被访问
  2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
  3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
  4. 如果后面没有访问限定符,作用域就到 } 即类结束。
  5. class的默认访问权限为private,struct为public(因为struct要兼容C)
    所以在上面的代码中我们只需要加一个public就可以解决问题了
    在这里插入图片描述

注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

有道面试问题上这样的:C++中struct和class的区别是什么

C++需要兼容C语言,所以C++中struct可以当成结构体使用。另外C++中struct还可以用来
定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的类
默认访问权限是private,并且在继承和模板参数列表位置,struct和class也是有区别的

类的封装

面向对象的三大特性:封装、继承、多态。

封装:将数据和函数都放到类里面,然后通过访问限定符对类的成员进行限制

封装本质上是一种管理,让用户更方便使用类。比如:对于电脑这样一个复杂的设备,提供给用
户的就只有开关机键、通过键盘输入,显示器,USB插孔等,让用户和计算机进行交互,完成日
常事务。但实际上电脑真正工作的却是CPU、显卡、内存等一些硬件元件。

对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的,CPU内部是如
何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此计
算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以
及键盘插孔等,让用户可以与计算机进行交互即可。

在C++语言中实现封装,可以通过类将数据以及操作数据的方法进行有机结合,通过访问权限来
隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用。

类的实例化

用类类型创建对象的过程,称为类的实例化

  1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没
    有分配实际的内存空间来存储它
class Stack
{
public:
	int* a;
	int top;
	int capacity;
};
int main()
{
	Stack s1;
	Stack::top++;
	s1.top++;
}

在这里插入图片描述

这里的top无法使用就是因为top只是类中的一个声明,没有实例化,所以top没有占用空间,当用top++的时候就会报错
在这里插入图片描述
当把Stack::top++屏蔽掉后,只是告诉我们没有初始化局部变量,说明Stack.s1是已经有空间了,我们只需要对类里面的成员变量初始化就可以正常运行了

一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量

int main()
{
 Person._age = 100;   
 return 0;
}

Person类是没有空间的,只有Person类实例化出的对象才有具体的年龄。

类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象才能实际存储数据,占用物理空间
在这里插入图片描述

类对象模型

类的对象大小的计算

类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算
一个类的大小?

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date test;
	cout << sizeof(test) << endl;
	return 0;
}

在这里插入图片描述

在之前结构体中有了解过结构体的计算方式,C++的类的计算方式也非常相似,都遵循内存对齐原则

在上图可以知道这个类的大小为12个字节,而类中的成员即有函数,又有3个整形变量,而这3个整形的大小就是12个字节,那这么说函数是不占内存的吗?
显然是不可能的,所以猜测函数可能单独存在一块空间,而那块空间不会被计算到类的大小中去,那函数的空间会不会被共用呢?

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date test;
	Date test2;
	test._year;
	test2._year;
	test.Init(1,2,3);
	test2.Init(3,4,5);
	cout << sizeof(test) << endl;
	return 0;
}

通过汇编可以看出,两个相同的类可以共用同一个函数的空间,
在这里插入图片描述
综上可以得知,函数的内存不是和成员变量存在一起的,因为如果每次创建一个类,都需要开辟一看成员函数的空间,而成员函数的内容都是一样的,这样就太浪费空间了
在这里插入图片描述
所以存储方式是这样的,成员函数存在一块公共的区域,每次调用这个函数的时候就直接去公共区域里用就行了,这个公共的区域被叫做代码段/代码区
在这里插入图片描述

结论:一个类的大小,实际就是该类中”成员变量”之和,当然要注意内存对齐

由于类域的存在,所以可能会存在不同的类用同一个函数名,为了区分,会在调用函数的时候加上类的类名

class Date
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	int _year;
	int _month;
	int _day;
};
class Queue
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	int _year;
	int _month;
	int _day;
};

在调用class Date和class Queue中的Init函数会将类名Date和Queue也加入进去,这样就不会调错函数了

如果类里面全是函数没有成员变量或者什么都没有的话,他的内存大小是多少呢

 class Date
{
public:
	void Init()
	{
	}
};
int main()
{
	Date test;
	cout << sizeof(test) << endl;
	return 0;
}

在这里插入图片描述
按照之前的说法没有成员变量结果应该是0才对,其实是C++的规定,没有成员变量的大小为1字节(这个1字节是用来表示定义的对象存在,如果他的内存大小为0就表示他没有存在,取他的地址也为空,这不是我们想要的结果)

所以没有成员变量的类对象大小为1字节,这个1字节是用来占位标识对象实例化时定义出来存在过的

扩展

class Date
{
public:
	void Init()
	{
		cout << "Date Init" << endl;
	}
};
int main()
{
	Date test;
	Date* p1 = &test;
	p1->Init();
	return 0;
}

这个代码是通过一个指针p1指向test的地址,然后用箭头访问的方式取访问类的成员函数
在这里插入图片描述
再来看看下面的这个代码

class Date
{
public:
	void Init()
	{
		cout << "Date Init" << endl;
	}
};
int main()
{
	Date test;
	Date* p2 = nullptr;
	p2->Init();
	return 0;
}

Date*p2为空指针,但是却可以用p2访问类的成员函数,这是因为用箭头去访问不一定是解引用,这个取决于后面的值在不在指针指向的空间里,因为Init不在p2指向的空间里,所以不存在解引用,在编译的时候会直接调用函数Init,也就是说在编译的时候就确定Init存在哪里了,而不是在运行的时候再去找
在这里插入图片描述

在这里插入图片描述

结构体内存对齐规则

  1. 第一个成员在与结构体偏移量为0的地址处。
  2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
    注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
    VS中默认的对齐数为8
  3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
  4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
    体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/605663.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Linux系统一步一脚印式学习

Linux操作系统具有许多特点和优势。首先&#xff0c;它是开放源代码的&#xff0c;也就意味着任何人都可以对源代码进行查看和修改。其次&#xff0c;可以同时支持多个用户且可以同时执行多个任务&#xff0c;此外&#xff0c;Linux操作系统也非常稳定和安全。相对于其他操作系…

MyBatis认识

一、定义 MyBatis是一款优秀的持久层框架&#xff0c;它支持自定义 SQL、存储过程以及高级映射。MyBatis 免除了几乎所有的 JDBC 代码以及设置参数和获取结果集的工作。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java POJO&#xff08;Plain Old Java O…

关于zabbix简介及zabbix服务端的部署

文章目录 一、zabbix概念1、zabbix简介2、zabbix主要特点3、zabbix运行机制4、zabbix应用场景5、zabbix监控原理6、zabbix的子程序7、zabbix监控的架构模式7.1 server-client架构7.2 server-proxy-client架构7.3 master-node-client 二、部署zabbix1、服务器配置2、服务器环境3…

ruoyi-nbcio 基于flowable规则的多重并发网关的任意跳转

更多ruoyi-nbcio功能请看演示系统 gitee源代码地址 前后端代码&#xff1a; https://gitee.com/nbacheng/ruoyi-nbcio 演示地址&#xff1a;RuoYi-Nbcio后台管理系统 http://218.75.87.38:9666/ 更多nbcio-boot功能请看演示系统 gitee源代码地址 后端代码&#xff1a; h…

认识下MapReduce

&#x1f50d; 什么是MapReduce&#xff1f; MapReduce是一种分布式计算模型&#xff0c;最初由Google提出&#xff0c;用于处理大规模数据集的并行计算。它将数据处理任务分解成独立的Map和Reduce两个阶段&#xff0c;以实现分布式计算和并行化处理。Map阶段负责将输入数据映…

自然语言处理(NLP)技术有哪些运用?

目录 一、自然语言处理&#xff08;NLP&#xff09;技术有哪些运用&#xff1f; 二、Python进行文本的情感分析 1、NLTK库: 2、TextBlob库: 三、错误排除 一、自然语言处理&#xff08;NLP&#xff09;技术有哪些运用&#xff1f; 自然语言处理&#xff08;NLP&#xff09…

DAY 3

1. #include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent) {this->resize(540,415);this->setFixedSize(540,415);//窗口标题this->setWindowTitle("盗版QQ");//窗口图标this->setWindowIcon(QIcon("E:\\qq\\pictrue\\pi…

520情人节送什么礼物?五款好物分享,情侣必看!

在浪漫的520情人节&#xff0c;为心爱的人挑选一份特别的礼物是每对情侣表达爱意的重要方式。市场上琳琅满目的选择让人眼花缭乱&#xff0c;究竟什么样的礼物能触动TA的心弦&#xff1f;本篇分享将为您精选五款既实用又充满情意的好物&#xff0c;无论是甜蜜的开始还是长久的陪…

linux上go项目打包与部署

1.第一步把项目打包 1.确保本地goland的操作系统为linux go env找到GOOS如果为window就修改为Linux 修改命令为 go env -w GOOSlinux2.打包 在项目根目录下输入 go build main.go然后项目根目录下会出现一个mian的二进制文件 3.上传包 将 main 程序包放到服务的目录下&…

图像质量评价方法简介与Python实现

图像质量评价方法简介与Python实现 在图像处理和计算机视觉领域&#xff0c;评价图像质量的准确性是一项重要任务。评价图像质量的方法可以分为主观评价和客观评价两种。主观评价是通过人类观察者进行评价&#xff0c;而客观评价则是通过计算机算法来评价。本文将介绍图像质量…

PMP课程知识点很多,无法入手,该如何学习?

回顾整个学习过程&#xff0c;我花费了不少时间&#xff0c;但也学到了系统的项目管理知识&#xff0c;考试结果也让我感到满意。在学习过程中&#xff0c;我认为以下几点非常重要&#xff1a; 1、需要对课本进行整体阅读&#xff0c;以便对内容有一个整体印象&#xff1b; 2…

Git系列:git commit 被忽视的高级用法

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

增量同步笔记

2.2.2.增量同步 全量同步需要先做RDB&#xff0c;然后将RDB文件通过网络传输个slave&#xff0c;成本太高了。因此除了第一次做全量同步&#xff0c;其它大多数时候slave与master都是做增量同步。 什么是增量同步&#xff1f;就是只更新slave与master存在差异的部分数据。如图…

电脑文件x3daudio1 7.dll怎么修复?快速修复x3daudio1 7.dll的方法

你试过电脑文件x3daudio1 7.dll丢失么&#xff1f;如果你有遇到这种情况&#xff0c;那么可能你的某些程序就会启动不了&#xff0c;毕竟这个文件是用来处理音频功能的&#xff0c;那么我们要怎么去修复&#xff1f;下面我们一起来详细的了解电脑文件x3daudio1 7.dll这个文件吧…

(三)小程序样式和组件

视频链接&#xff1a;尚硅谷2024最新版微信小程序 文章目录 小程序的样式和组件介绍样式-尺寸单位 rpx样式-全局样式和局部样式组件-组件案例演示组件案例-轮播图区域绘制组件案例-轮播图图片添加组件案例-绘制公司信息区域组件案例-商品导航区域组件案例-跳转到商品列表组件案…

【DPU系列之】如何通过带外口登录到DPU上的ARM服务器?(Bluefield2举例)

文章目录 1. 背景说明2. 详细操作步骤2.1 目标拓扑结构2.2 连接DPU带外口网线&#xff0c;并获取IP地址2.3 ssh登录到DPU 3. 进一步看看系统的一些信息3.1 CPU信息&#xff1a;8核A723.2 内存信息 16GB3.3 查看ibdev设备 3.4 使用小工具pcie2netdev查看信息3.5 查看PCIe设备信息…

Vue-路由介绍

目录 一、思考引入 二、路由介绍 一、思考引入 单页面应用程序&#xff0c;之所以开发效率高&#xff0c;性能高&#xff0c;用户体验好&#xff0c;是因为页面按需更新。 而如果要按需更新&#xff0c;首先需要明确&#xff1a;访问路径和组件的对应关系。该关系通过路由来…

Python爬虫获取豆瓣电影Top100

大家好&#xff0c;我是秋意零。 今天分析一篇&#xff0c;Python爬虫获取豆瓣电影Top100。 在此之前&#xff0c;我没有学习过爬虫&#xff0c;只有一丢丢的Python基础。下面效果的实现源码几乎没经过我&#xff0c;而是AI百老师。我主要负责了对应的调试以及根据我想要的功…

敏感信息提取插件-CaA(三)

0x01 简介 CaA是一个基于BurpSuite Java插件API开发的流量收集和分析插件。它的主要作用就是收集HTTP协议报文中的参数、路径、文件、参数值等信息&#xff0c;并统计出现的频次&#xff0c;为使用者积累真正具有实战意义的Fuzzing字典。除此之外&#xff0c;CaA还提供了独立的…

Python 框架安全:Django SQL注入漏洞测试.(CVE-2021-35042)

什么是 Django 框架 Django 是一个用 Python 编写的 Web 应用程序框架。它提供了许多工具和库&#xff0c;使得开发 Web 应用程序变得更加容易和高效。Django 遵循了“MTV”&#xff08;模型-模板-视图&#xff09;的设计模式&#xff0c;将应用程序的不同组件分离开来&#x…
最新文章