深入计算机语言之C++:类与对象(上)

news2024/10/22 19:28:12

 🔑🔑博客主页:阿客不是客

🍓🍓系列专栏:从C语言到C++语言的渐深学习

欢迎来到泊舟小课堂

😘博客制作不易欢迎各位👍点赞+⭐收藏+➕关注

前面我们学习了关于c++语言的一些基础知识,今天我们来正式进入c++语言的学习

一、类的定义

1.1 类的定义

C++是一门面向对象的语言,理解c++,首先要理解类和对象。

C++中的类可以看成c语言中的结构体的升级版,结构体是一种构造类型,可以包含若干个成员变量,成员变量的类型可以不同。而由类声明定义的变量,我们称为对象

C++中struct也可以定义类,C++兼容C中struct的⽤法,同时struct升级成了类,明显的变化是 struct中可以定义函数,⼀般情况下我们还是推荐⽤class定义类。

在类里面定义的成员函数默认为内联函数(inline)

1.2 类的语法规格式

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

class Stack 
{
public:

    void Init(int n = 4) 
    {
        array = (int*)malloc(sizeof(int) * n);
        if (nullptr == array)
        {
            perror("malloc申请空间失败");
            return; 
        }
        capacity = n;
        top = 0; 
    }

    int* array;
    size_t capacity;
    size_t top;
};//分号不能省略

int main()
{
    Stack st;
    st.Init();

    return 0;
}

1.3 成员变量的命名

虽然C++标准并没有规定成员变量的命名规则,但是大家约定俗成地在定义变量时会有一套特定的规则,目的就是解决可能存在的命名冲突的问题,比如说下面这段代码:

class Date
{
	void Init(int year, int month, int day)
	{
		//命名冲突
		year = year;
		month = month;
		day = day;
	}
	int year;
	int month;
	int day;
};

这时为了解决问题这类问题,我们在定义成员变量时会对其进行特定地修饰。比如说 _变量名 ,m_变量名 和变量名_ 等等不同的修饰

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

二、限定访问符

在C++类中有三种访问限定符:**public,private,protected。**他们每一个都有自己独特的作用:

  • public:公有属性,修饰的成员在类内外都可以直接被访问。
  • protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
    • private:私有属性
    • protected:保护属性
  • 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。如果后面没有访问限定符,作用域就到 } 即类结束。

那在C++中struct 和class有什么区别呢?

struct :内部默认是公有权限,结构体外部可以访问其内部成员

class:内部默认是私有权限,类的外部不能直接访问内部成员;可以手动声明为共有权限;

三、类域

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

#include<iostream>
using namespace std;

class Stack
{
public:

    void Init(int n = 4);

    int* array;
    size_t capacity;
    size_t top;
};

void Stack::Init(int n) {
    array = (int*)malloc(sizeof(int) * n);
    if (nullptr == array)
    {
        perror("malloc申请空间失败");
        return;
    }

    capacity = n;
    top = 0;
}

int main()
{
    Stack st;
    st.Init();

    return 0;
}

四、类对象模型

4.1 类对象的实例化

⽤类类型在物理内存中创建对象的过程,称为类实例化出对象。

在类中的成员变量实际是一种声明,相当于一个设计图纸。而我们利用类名定义的对象就是类对象的实例化,相当于通过设计图纸实际创建出来。单独的类是并不占据实际空间的大小。

⼀个类可以实例化出多个对象,实例化出的对象 占⽤实际的物理空间,存储类成员变量。打个比⽅:类实例化出对象就像现实中使⽤建筑设计图建造出房⼦,类就像是设计图,设计图规划了有多少个房间,房间⼤⼩功能等,但是并没有实体的建筑存在,也不能住⼈,⽤设计图修建出房⼦,房⼦才能住⼈。同样类就像设计图⼀样,不能存储数据,实例化出的对象分配物理内存存储数据。

4.2 类对象的存储

我们知道了类对象的创建,那么具体类中的成员变量与成员函数又是如何存储的呢?

类实例化出的每个对象,都有独⽴的数据空间,所以对象中肯定包含 成员变量,那么成员函数是否包含呢?

  1. 每次创建对象时,都开辟一个空间存储类成员变量与成员函数。
  2. 每次创建对象时,都开辟一个空间存储类成员变量与成员函数的地址。
  3. 每次创建对象时,都开辟一个空间存储类成员变量。而成员函数提前单独存储一个区域
  • ⾸先函数被编译后是⼀段指令,对象中没办法存储,这些指令存储在⼀个单独的区域(代码段),而且每次对象的实例化都会开辟函数的空间。而每个函数的功能都是一样的,这就造成了空间的浪费。那么对象中⾮要存储的话,只能是成员函数的指针。
  • 再分析⼀下,对象中是否有存储指针的必要呢,Date实例化d1和d2两个对象,d1和d2都有各⾃独⽴的成员变量_year/_month/_day存储各⾃的数据,但是d1和d2的成员函数Init/Print指针却是⼀样的,存储在对象中就浪费了,这⾥也就没有必要其。
  • 函数指针是⼀个地址,调⽤函数被编译成汇编指令[call 地址], 其实编译器在编译链接时,就要找到函数的地址,不是在运⾏时找。

除此之外我们还可以通过计算类的大小来判断是以哪种形式存在的

4.3 类对象的大小

4.3.1 一般类的计算

类型对象的大小我们可以借助运算符sizeof计算,并且类的大小也遵循结构体内存对齐规则,这部分的内容已经在结构体的部分谈过了,就不再赘述,详情见:深入C语言:探索结构体的奥秘 的第五点

#include<iostream>
using namespace std;
class Date
{
//可以被直接访问
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
//不能被直接访问
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d;
	cout << sizeof(d) << endl;
	return 0;
}

根据内存对齐规则,我们知道成员变量的大小就是12,所以证明成员函数是存在于内存的其他位置。所以说存储三正确。一般这个存储成员函数的区域我们称之为公共代码段。

4.3.2 空类的计算

当类中只有成员函数,或者什么都没有时。类的大小又为多少呢?

// 类中仅有成员函数
class A1
{
public:
	void func2() {}
};
// 类中什么都没有---空类
class A2
{
};
int main()
{
	A1 d1;
	A2 d2;
	cout << sizeof(d1) << endl;
	cout << sizeof(d2) << endl;
	return 0;
}

为什么空类的大小为1,而不是0呢?其实并不能难像,因为在我们进行空类的实例化时必须要有空间存储对象的大小。这是编译器就会默认给一个字节大小来标记这个类的对象,实际操作中实用性也很少。

五、this指针

我们先来看一段代码:

#include<iostream>
using namespace std;
class Date
{
public:
	//初始化
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year; // 年
	int _month; // 月
	int _day; // 日
};
int main()
{
	Date d1, d2;
	d1.Init(2022, 1, 11);
	d2.Init(2022, 1, 12);
	d1.Print();
	d2.Print();
	return 0;
}

对于上述类,有这样的一个问题:

Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?

那么这⾥就要看到C++给了⼀个隐含的this指针解决这⾥的问题编译器编译后,类的成员函数默认都会在形参第⼀个位置,增加⼀个隐藏的当前类类型的指针,叫做this指针,只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。。

void Init(Date* const this, int year, int month, int day)
{
	this->_year = year;
	this->_month = month;
	this->_day = day;
}
d1.Init(&d1,2022, 1, 11);//实际传参

但是注意:我们并不能将隐式传参书写出来,因为这是编译器默认添加的

虽然我们不能在传参的时候书写this指针,但我们在成员函数内部可以使用this指针,使用this指针的时候需要注意一些问题:

  • this指针的类型:类型为const,即成员函数中,不能给this指针赋值。

  • 只能在“成员函数”的内部使用。

  • this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给this形参。所以对象中不存储this指针。

  • this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传递,不需要用户传递。

问题:

问题1:

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class Betty
{
public:
	void Print()
	{
		cout << "Print()" << endl;
	}
private:
	int _a;
};
int main()
{
	Betty* p = nullptr;
	p->Print();
	(*p).Print();
	return 0;
}

为什么程序会正常运行,对空指针解引用不是会发生运行崩溃吗?首先我们得明白成员函数并不存放在类对象中,而是存放在公共代码段。虽然我们表面看上去解引用,但实际上编译器不需要通过解引用去找对应函数,只需要去公共代码区执行对应函数即可。

问题2:

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class Betty
{
public:
	void Print()
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	Betty* p = nullptr;
	p->Print();
	(*p).Print();
	return 0;
}

这里就引起程序崩溃,因为我们知道访问对应的成员变量,会传递对应对象的地址。cout 需要访问 _a,从而需要对p进行解引用,而这里 p 的地址为 nullptr ,导致了程序的崩溃

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Go语言gRPC快速入门

文章目录 前言gRPC是什么Go语言的gRPC技术栈准备工作接口定义代码生成服务端代码编写客户端代码编写效果演示完整代码链接最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;这篇博客想帮助初学者能够快速入门gRPC&#xff0c;希望能够为你节省宝贵的时间&#xff0c;让时间…

无线网络基础

文章目录 无线组网胖AP瘦AP胖瘦AP的区别组网方式连接方式CAPWAP概念 无线组网 WLAN&#xff1a;无线局域网 蜂窝网络&#xff1a;无线广域网 802.11&#xff0c;无线网络封装的报文头部 WLAN是一种基于IEEE 802.11标准的无线局域网技术 802.11标准聚焦在TCP/IP对等模型的下两层…

算力提升10倍,特斯拉Cybercab预示了半导体行业哪些方向?

北京时间10月11日上午&#xff0c;备受世界瞩目的“We&#xff0c;Robot”发布会成功举行。现场&#xff0c;特斯拉正式发布了被命名为Cybercab的特斯拉Robotaxi&#xff08;无人驾驶出租车&#xff09;&#xff0c;以及Robovan&#xff08;无人驾驶厢式货车&#xff09;。 这次…

Harmony OS原生端渲染RTMP流功能实现

前段时间公司收到鸿蒙的邀请&#xff0c;希望我们加入鸿蒙的生态应用。领导要求我们将原先安卓SDK实现的功能在鸿蒙生态上1&#xff1a;1还原。相信这也是当前很多公司在做的事情。 我们项目原先有获取硬件实时视频流展示的需求&#xff0c;这块功能也耗费了两周的时间才打通测…

springboot 整合 快手 移动应用 授权 发布视频 小黄车

前言&#xff1a; 因快手文档混乱&#xff0c;官方社区技术交流仍有很多未解之谜&#xff0c;下面3种文档的定义先区分。 代码中的JSON相关工具均用hutool工具包 1.快手 移动双端 原生SDK 文档https://mp.kuaishou.com/platformDocs/develop/mobile-app/ios.html 2.快手 Api 开…

每日OJ题_牛客_chika和蜜柑_TopK_C++_Java

目录 牛客_chika和蜜柑_TopK 题目解析 C代码 Java代码 牛客_chika和蜜柑_TopK chika和蜜柑 (nowcoder.com) 描述&#xff1a; chika很喜欢吃蜜柑。每个蜜柑有一定的酸度和甜度&#xff0c;chika喜欢吃甜的&#xff0c;但不喜欢吃酸的。 一共有n个蜜柑&am…

万物皆可浮雕,comfyui一键图片转浮雕

一键生成图片浮雕效果&#xff1a;ComfyUI工作流指南 在图像处理和艺术创作领域&#xff0c;生成浮雕效果的图片是一种既独特又吸引人的表现手法。使用ComfyUI工作流&#xff0c;可以一键生成灰度图、深度图和浮雕图&#xff0c;大大简化了复杂的图像处理过程。本文将详细介绍…

嵌入式C语言之结构体封装函数

嵌入式C语言之结构体封装函数 Chapter1 嵌入式C语言之结构体封装函数结构体封装函数的作用结构体封装函数的应用结构体封装函数的好处举例1举例2举例3 Chapter1 嵌入式C语言之结构体封装函数 原文链接&#xff1a;https://blog.csdn.net/qq_43416206/article/details/13140531…

spring:Springboot3使用模版引擎thymeleaf

文章目录 介绍语法1、文本替换2、属性替换3、条件判断4. 列表循环5. 表单处理 基本示例视图解析机制视图解析器的默认配置为什么用Controller可以&#xff0c;用RestController就只是返回字符串 介绍 Thymeleaf 是一个现代的服务器端 Java 模板引擎&#xff0c;用于在服务器端…

掌握这几款在线音频剪辑工具,轻松成为音频处理达人!

在数字时代&#xff0c;音频剪辑已经成为一项必备技能。无论是制作短视频、播客&#xff0c;还是进行音乐创作&#xff0c;一款好用的音频剪辑工具都能助你事半功倍。今天&#xff0c;我们就来为大家推荐几款实用的在线音频剪辑工具&#xff0c;让你轻松成为音频处理达人&#…

救命!后悔没早点读,自学Python,这本书永远的神,经典又好懂!

这是一本对新手来说很友好的入门书&#xff0c;这本是今年才出的新版&#xff0c;之前的两个版本在某瓣都是9分以上了。专为初学者设计&#xff0c;同时也适合有编程经验的读者。该书由Eric Matthes编写&#xff0c;内容涵盖Python基础语法、编程概念以及丰富的实践项目。 全书…

【工具变量】文明城市评选DID(2000-2023年)

数据简介&#xff1a; 随着城市化的不断推进和全球城际竞争的日益激烈&#xff0c;城市品牌成为争夺优质资源、推动城市可持续发展的重要战略工具。通过关注城市品牌建设&#xff0c;不仅可以刺激本地企业家更多地进行创新活动&#xff0c;为企业家创新活动提供更好的营商环境…

自回溯天线:实现波束自动跟踪的智能天线系统

自回溯天线:实现波束自动跟踪的智能天线系统 1. 引言 自回溯天线是一种能够自动将接收到的信号发射回信号源方向的智能天线系统。它基于相位共轭原理,无需复杂的信号处理和控制系统,就能实现波束的自动跟踪。 自回溯天线技术依靠纯模拟方式实现&#xff0c;通过共轭模块对入射…

vue3中如何更改当前类的文件名称

首先&#xff0c;使用script指定文件名称 <template><div class"person"><h2>姓名&#xff1a;{{ name }}</h2><h2>年龄&#xff1a;{{ age }}</h2><button click"showTel">查看联系方式</button><bu…

【含文档】基于Springboot+Vue的招投标管理系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

如何恢复误删除的照片?能恢复多少?

最近在旅行时不小心删除了相机里之前拍摄的照片&#xff0c;我尝试在相机上恢复&#xff0c;但是没有找到恢复选项。我还能恢复这些照片吗&#xff1f;求助&#xff01; 一、照片恢复的可能性 照片恢复的可能性取决于多个因素&#xff0c;包括数据是否被覆盖、存储介质的类型、…

C语言笔记 10

求前n项之和 程序设计 f(n)1… 起点终点数字已知&#xff0c;用for循环最合适 #include <stdio.h>int main() {int n;int i;double sum 0.0;scanf("%d", &n);for ( i1; i<n; i ) {sum 1.0/i;}pritnf("f(%d)%f\n", n, sum);return 0; } i…

宿舍离人自动断电控制系统的功能要求是什么?

宿舍离人自动断电系统&#xff0c;由石家庄光大远通电气有限公司匠心打造&#xff0c;专为集体公寓、学生宿舍等密集型居住空间量身定制的智能用电管理解决方案&#xff0c;其卓越性能与广泛适应性&#xff0c;如同智慧之网&#xff0c;精准覆盖并优化每一份用电需求。该系统不…

八卦GPT-5的一切

这篇超长文章——既是评论&#xff0c;也是探索——关于GPT-5 对最受期待的下一代 AI 模型的深入分析 但它不仅仅是关于GPT-5。 • 它涉及我们对下一代AI模型的期望。 • 它关于即将出现的令人兴奋的新功能&#xff08;如推理和代理&#xff09;。它不仅讨论GPT-5技术本身&…

人工智能领域科学问题

科学问题 目前中国在人工智能领域亟待解决的问题包括但不限于以下几个方面&#xff1a; 数据隐私和安全&#xff1a;随着人工智能技术的发展&#xff0c;个人数据的收集和使用越来越广泛&#xff0c;如何保护个人隐私和数据安全成为一个重要问题。 伦理和道德问题&#xff1…