IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C++类和对象(上) -> 正文阅读

[C++知识库]C++类和对象(上)

目录

C++ struct的升级

类的定义

?访问限定符

类域

类的声明和定义分离

C++类的一些约定

封装

类对象模型

隐含的this指针

?this指针两道经典面试题


上一篇博客我向大家介绍了面向过程和面向对象的一些区别,并捎带着引入了一点点类和对象的概念,今天我们正式来看一下类和对象。

https://blog.csdn.net/SAKURAjinx/article/details/126990400

C++ struct的升级

为了引入类,C++先拿C语言的struct开刀了。

首先C++的struct还是兼容C的用法,但同时也将其升级成了类。也就是说struct里面不仅可以放以前那一套(属性),还可以放入方法(函数)了。

struct stu
{
	int name;
	int age;
	char ID[19];
	//...
	void StuReturnSch(stu* ps)
	{

	}
	void StuRegisterSch(stu* ps)
	{

	}
};

struct teacher
{
	int name;
	int age;
	char ID[19];
	//...
	void TeaReturnTea(teacher* pt)
	{
		
	}
	void TeaRegisterTea(teacher* pt)
	{

	}
};

并且因为struct升级成了类,所以stu ,teacher 是类名,结构体实参命名可以不加struct,直接用类名。

struct teacher p1;
teacher p2;

类的定义

?一开始C++还只是升级了struct,但后来研发者感觉这种方式不太好,就用class取代了struct。

当然,struct还是可以用,并且功能和class大同小异,但是后来程序员一般还是使用class,这成为一种通用标准了,Java里面类也是用的class。

类里面的变量和函数不需要按 变量在上,函数在下的方式书写,可以穿插,也可以倒过来。

但是一般都不会胡乱穿插书写,最好还是变量放一起,函数放一起,方便阅读。

C语言里面变量要放上面,函数要放下面,是因为C语言编译器是向上查找,不会向下。C的变量和函数没有必然的关联性。

C++变量和函数都在一个域里面,有必然的联系,因此可以上函数下变量。

?访问限定符

?C++有封装、继承、多态,为了更好地控制封装,C++定义了访问限定符。

1、protected 和 private 都是私有,但是有区别,前期我们先不讲它们的区别。

2、public修饰的成员类外面也可以访问,protected 和 private 修饰的成员类外面不能访问。

3、不管是public还是protected 和 private 修饰,类里面都可以访问该成员。

4、class里没用访问限定符修饰的成员,默认私有; struct正相反,默认公有。

类域

class里面的域叫类域。

之前C++命名空间域也是一个域。

stu::age = 20;

问大家一个问题,类里面可以这样像命名空间一样访问吗?

不可以。因为class 里面是声明,没有空间,自然也没有age的空间,不能访问。

要访问age,如下所示:

class stu
{
public:
	char name[20];
	int age;
	char ID[19];
	//...
	void StuReturnSch(stu* ps)
	{

	}
	void StuRegisterSch(stu* ps)
	{

	}
};

class teacher
{
public:
	char name[20];
	int age;
	char ID[19];
	//...
	void TeaReturnTea(teacher* pt)
	{
		
	}
	void TeaRegisterTea(teacher* pt)
	{

	}
};

int main()
{
	stu p1;
	teacher p2;
	p1.age = 20;
	return 0;
}

如果是静态的,可以用上面那种方式访问,后面再讲。

类的声明和定义分离

声明和定义的原因:

1、增强可读性。比如公司里需要你加入一个项目,你要迅速了解项目的基本内容,可以查看项目程序的声明及注释。? 如果声明和定义在一起,阅读、查找起来就很吃力。

2、增强代码安全性,防止源代码泄漏。

先来看一种声明和定义分离的情况:

project.h

#include<iostream>

class stu
{
public:
	char name[20];
	int age;
	char ID[19];
	void ReturnSch(stu* ps);
	void RegisterSch(stu* ps);
};

class teacher
{
public:
	char name[20];
	int age;
	char ID[19];
	void ReturnSch(teacher* pt);
	void RegisterSch(teacher* pt);
};

project.cpp

#include"project.h"

void ReturnSch(stu* ps)
{

}
void RegisterSch(stu* ps)
{

}

void ReturnSch(teacher* pt)
{

}
void RegisterSch(teacher* pt)
{

}

test.c

#include"project.h"

int main()
{
	stu p1;
	teacher p2;

	return 0;
}

我们发现一个问题,project.cpp里面,函数定义时,分不清哪个是stu的哪个是teacher的。

因此,此时要加上类的限定。

void stu::ReturnSch(stu* ps)
{

}
void stu::RegisterSch(stu* ps)
{

}

void teacher::ReturnSch(teacher* pt)
{

}
void teacher::RegisterSch(teacher* pt)
{

}

另外,如果在类里面定义函数,那么编译器会默认函数是内联的。

C++类的一些约定

我们在类里定义变量时,通常会在前面或后面加_? 以示区分。

如:int _year;???? int year_;

还有:int? m_year;??? int mYear

具体以公司惯例为主。

封装

面向对象有三大特性:封装、继承、多态。当然还有一些其他特性(如反射等),但这三个是最主要的。

我们现在所学的类就是封装的一大体现。其本质就是把一系列相关的东西都封到一个地方。

类里面有公有和私有,想给外面使用的就设为公有(如函数),不想给外面使用的就设为私有(如变量)。

以数据结构的栈为例C语言实现的时候相对自由一些,它的数据和方法(变量和函数)不是在一起的,是分离的。 而C++则是将数据和方法都封装在了一个类下。

?左边C语言因为相对自由,没有封装的约束,也就可以通过访问变量随意修改成员。比如访问栈顶数据,本来需要调用StackTop函数,但是因为这个函数实现就两行太过简单,很多人直接就访问成员变量,这样会出现问题(因为不知道top初始设计是-1还是0)。

C++就不存在上述问题,因为封装在一起,数据是私有的,无法从外部访问,必须调用方法(函数),这样就增加了安全性,能更好地管理。

类对象模型

如何计算对象的大小

?计算类的大小时,和之前讲的结构体内存对齐那一块一样,都涉及到内存对齐相关原则,不清楚的老铁可以看一下我的博客:自定义类型————结构体、位段、枚举类型、联合体_SAKURAjinx的博客-CSDN博客

?

?先说结论,这里类A的大小不是8,而是1.? 很多老铁会把函数也算进大小里面,其实大佬在设计的时候没有将函数算进去,只计算对象的大小

这里大佬在设计存储方式的时候有三种想法:

?第一种:将对象和方法都存进去。

这种显然不好,太浪费空间了。pass

?第二种:存对象及函数的地址。

毫无疑问,对象肯定都要存的,将函数放到一起,用一个指针指向它,保存这个地址就可以访问所有函数了。

?第三种是大佬选择的方法,只存对象,将函数放到一块公共代码区,每个对象想访问就可以访问到。

方法二比方法三多存了一个地址,其实是没必要的,函数都在公共代码区了,对象都能轻易调用,没有必要特地保存一个地址取找这些函数。

既然函数不算进类的大小,那如果类里面没有对象呢?


#include<iostream>
using namespace std;
class A1
{};
class A2
{
public:
	void func() { }
};
int main()
{
	cout << sizeof(A1) << endl;
	cout << sizeof(A2) << endl;

	return 0;
}

?不论是类里面只有函数没有变量,还是什么都没有,编译器默认给的大小是1,不是0

也就是说编译器会给1个字节占位,它不存储有效数据,仅标识类存在

因为如果需要取类的地址,连空间都没有就不行了。

?

隐含的this指针

class Date
{
public:
	void Init(int year = 1,int month = 1,int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << " " << _month << " " << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2;
	d1.Init(2022,1,1);
	d2.Init(2022,1,2);
	d1.Print();
	d2.Print();
	return 0;
}

this指针是关键字,只能叫this,不能用that...代替。

我们用日期类来引出隐含的this指针,看上面代码,结果如下图:

上面已经讲过了,对象是去类里面找,但是函数不是去类里面找的,是去公共代码区找的,不同的对象调用的是同一个,那为什么结果会不同呢?

这就印证了this指针的存在。其实类里面有一个隐含的this指针,它指向调用函数的对象。

	void Print(Date* this)
	{
		cout << this->_year << " " << this->_month << " " << this->_day << endl;
	}

?d1调用,传给this指针的就是d1 的地址;?d2调用,传给this指针的就是d2 的地址。

因此,结果才会不同。

this指针是隐含的、默认的,不需要我们自己加上。在函数参数里加会报错。

虽然定义和传递都不能加this,但是我们可以用,像在函数体里面用 this->就没问题。

正因如此,在类外部不能直接用类访问里面的函数:

?因为类里的函数要传d1 \ d2的地址给this指针,但是这里没有定义d1 \ d2,只有类名,编译器不知道传什么给this,就报错了。

?

其实this指针接收实参传过来的地址时,会加个const修饰:

?这里const修饰的是this指针本身,而非它指向的值(解引用访问)。

也就是说 this 指针是不能修改的,this = nullptr(X)

?this指针两道经典面试题

一、this指针存在哪里?

两种经典错误解答:1、在常量取区(代码段)

????????????????????????????????? 2、在对象里

答案是存在栈帧中。因为this指针是形参。

二、

?乍看之下,好像两道题是一样的,但其实有坑在里面。

很多人以为p是空指针,空指针解引用访问肯定会崩溃,所以都选了B。

这里就要结合我们上面讲的,p是空指针不假,但是注意:print函数的地址是在公共代码区的(代码段),而非在对象里,编译器去找print函数不会去对象里找,而是直接去代码段,所以这里不发生解引用。p是A的指针,直接传给print函数的this指针,指针可以为空,不会报错,因此正常运行,第一题选C

第二题传指针之前都是一样的,当p指针传给this后,this是nullptr,还原编译器的写法就是:

cout << this->_a << endl;

空指针this解引用访问_a就会崩溃,所以第二题选B

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-09-24 20:38:18  更:2022-09-24 20:40:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 9:42:49-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码