【C++入门系列】——类和对象

news2024/12/30 3:07:50

作者主页

📚lovewold少个r博客主页

   ⚠️本文重点C++入门知识点以及类和对象的初步了解

😄每日一言:实践能力是自学能力最终转化为真正价值的根本。

目录

前言

auto关键字

auto关键字新用法

auto使用细节

auto与指针和引用结合起来使用

一行声明多个变量

auto不能推导情况

基于for范围的循环(C++11)

范围for的使用条件

指针空值

类和对象(重点)

什么是类和对象

类的定义

类的两种定义方式

类的限定访问符及封装

class和struct的区别

封装

类的作用域

类的实例化

类对象模型

如何计算类对象的大小

this指针

总结


前言

        本章主要讲述C++的类和对象特性,同时对auto关键字进行一个简要讲解,并简要完善前面章节未完成部分。在本章节,我们主要学习到auto关键字的合理用途,接触类和对象的面纱。能理解什么是面向过程,什么是面向对象,并且对类进行一个初步了解,了解在规则上的特点和用处。

auto关键字

        auto关键字是C++11加入的一个新特性,让编译器能够根据初始值的类型判断变量的类型。其主要的目的还是解决随着程序越来越复杂引起的各种类型复杂命名,特别是对于自定义类型的难以拼写和含义不明确容易出错。

看到上述代码,单从类型名的意义上来讲,可读性还是非常高的,但是这如此长的一串不是折磨人么。std::map::iterator 是一个类型,但是该类型太长了,特别容易写错。在C语言中,我们就会用typedef来重命名解决这个问题。

当然,这样也会引发新的问题:

当我们要把表达式的值赋值给变量的时候就得要求声明时候清楚的知道表达式的类型,但是很显然这样子是不容易通过typedef就能实现的,因此C++11提供了auto关键字,赋予了新的含义。

auto关键字新用法

auto和早期的C和C++中的auto修饰变量不同,C++11赋予了auto的全新含义:作为一个类型提示符来指示编译器,auto声明的变量由编译器在编译时期根据初始化值推导类型

int TestAuto()
{
	return 10;
}
int main()
{
	int a = 10;
	auto b = a;
	auto c = 'a';
	auto d = TestAuto();

	cout << typeid(b).name() << endl;//typeid用来确定变量类型
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;

	//auto e; 无法通过编译,使用auto定义变量时必须对其进行初始化
	return 0;
}

注意使用auto声明变量的时候,必须进行初始化,在编译期间编译器就会对初始化的表达值进行推导,来确定变量是什么类型。因此auto不是一种简单的类型声明,可以理解为类型声明占位符,提示编译器推导后将实际类型于auto位置替换。

auto使用细节

auto与指针和引用结合起来使用

        用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&。理解起来也很好理解,对于编译器类型推导过程中来讲,能推导右边是取地址还是一个变量,因此对于推导替换过程来讲,x推导为int类型和auto替换成int&;而auto*和auto也能根据右值为什么类型地址而清楚推导类型进行替换。

一行声明多个变量

void TestAuto()
{
	auto a = 1, b = 2;
	auto c = 3, d = 4.0; // 该行代码会编译失败,因为c和d的初始化表达式类型不同
}

以上代码是错误演示,实际上auto推导只推导一次,并根据推导结果去声明同行其它变量,因此要确保同行类型一致。

auto不能推导情况

  • auto不能作为函数的参数
  • auto不能用来声明数组

基于for范围的循环(C++11)

void TestFor()
{
	int array[] = { 1, 2, 3, 4, 5 };
	for (auto& e : array)
	{
		e *= 2;
		cout << e << " ";

	}
}

        上述代码实现了C语言部分我们经常使用的一个for循环遍历一个数组的同等操作,因为对于一个有范围的集合还说,确定范围是多余的,且在边界的范围确定中容易发生越界访问,发生错误。C++11引入了基于范围的for循环。for循环后的的括号由冒号:分为两个部分,一个是用于范围内用于迭代的变量,第二分表示被迭代的范围。

注意:与普通循环一样可以使用continue和break关键字对循环进行控制。

范围for的使用条件

for循环的迭代范围是确定的。

对于数组而言,就是数组的第一个元素和最后一个元素的范围;对于类而言,需要和for循环一致,提供begin和end的方法,用来确定迭代范围。

指针空值

在C语言中,在养成过良好编程习惯后大概会对为指针进行初始化。int* p=NULL--NULL实际上是一个宏定义,在头文件“stddef.h”中,宏主要是替换作用,所以实际上NULL可能被定义为字面常量0或者被定义为无类型指针(void*)的常量。

这种方式首先是有歧义的,在使用过程中会和程序的设计初衷相悖。程序本意是想通过f(NULL)调用指针版本的f(int*)函数,但是由于NULL被定义成0,因此与程序的初衷相悖。除非在使用过程中对其强制类型转换,但是这种细节是很难去避免的。

C++中以nullptr表示指针空值且不需要包含头文件,因为是作为关键字引入。

C++11中。sizeof(nullptr)和sizeof((void*)0)所占字节数相同。

因此在后续C++程序中,更加常用nullptr来表示指针空值。

类和对象(重点)

         C++和C的本质区别主要不是语法的转变,而是思维逻辑的转变。在C语言中更强调的是面向程序过程而言。

        身体作为人的一部分,是由无数原子构成,C语言对于处理我们动动手指,可能有点像调用身体器官各个部分分别运转,从而达到动动手指这个操作。但是如果我们吧人看作一个整体,身体作为整体的一部分,我们只需要知道动动手指这个操作方式,我们就可以执行。这就是一种面向过程和面向对象的区别。

        C++通过类和对象的实现,极大的简化了对于程序编程而言的繁琐,极大的解放了思维提高了效率,这就是语言之间的本质区别。

什么是类和对象

        C语言结构体中只能定义变量,在C++中,不仅可以定义变量,还可以定义函数。类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员。函数在一个类被称为类的成员。

        看周围真实的世界,会发现身边有很多对象,车,狗,人等等。所有这些对象都有自己的状态和行为。拿一条狗来举例,它的状态有:名字、品种、颜色,行为有:叫、摇尾巴和跑。我们把这个对象的属性和能执行的操作集合为一个类组成一个对象。程序对象也有状态和行为。对象的状态就是属性,什么变量,行为通过方法体现。

类的定义

        Class为定义类的关键字,classname为类名,{}中为类的主体,注意类的定义结束的时候不能省略。类体中的内容称之为类的成员:类的变量称之为类的属性或者成员变量;类中的函数称之为类的方法和成员函数。

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

类的两种定义方式

声明和定义都放在类体中。

class person
{
public:
	void showInfo()
		{
			cout << _name << "-" << _sex << "-" << _age << endl;
		}
public:
	char* _name;
	char* _sex;
	int _age;
};

类声明放在.h头文件中,成员函数定义放在.cpp文件中,注意函数成员名前要加上类名::

类的限定访问符及封装

        首先我们要来理解类的作用域范围。对于一个全局变量而言,可以在全局变量所属文件的任何地方进行使用,而局部变量只能在所属的代码块中使用。

        对于类而言,其内部定义的成员名和成员函数作用域都为整个类,作用域为整个类的名称,在内部是已知的,在类外部是不可知的。我们也可以通过访问限定符来决定其成员的作用域。 

        在类成员的封装中,我们通关访问修饰符能定义其成员相对类外部为公有、私有还是保护。

        C++封装方式:用类将对象的属性和方法结合在一起,让对象更加完善,通过访问选择性的将接口提供给外部的用户使用。

 访问限定符:

  • public修饰的成员在类外部可以直接被访问。
  • protected和private修饰的成员在类的外部不可以直接访问。
  • 访问权限的作用域从该限定符起到下一次限定符出现位置。
  • 没有后续的访问限定符,作用域到“}”即类结束。
  • class的默认访问权限为private,当数据映射到内存以后,没有任何访问限定符的区别。

class和struct的区别

        C中的struct需要兼容C,因此C++中的struct可以当成结构体使用,另外还可以用来定义类。和class定义类啥一样的,不同的是struct定义的类默认访问权限为pblic,class定义的默认访问权限是private。

封装

        在类和对象阶段,主要是研究类的封装特性,那么什么是封装?封装其实就是将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅使用公开接口完成对对象的交互

        封装其实是一种底层管理,保证用户更加方便的使用类。我们使用计算机的过程本质就是这样子,我们插入鼠标就可以使用,插上耳机就能听歌,插上键盘就能实现输入。当实际上工作的是计算机的底层,但是我们就通过这样子的封装让使用更加简单。

        我们不用用c语言思维去关心内存零部件,比较主板线路布局是这样子的,比较cpu如何设计,都不需要。对于一台计算机他只需要厂商提供接口,外部套上壳子,用户就能完成和计算机的交互工作。

        在C++中,通过类的方式将数据和操作数据的方法进行有机结合,通过访问权限来隐藏对象的细节,控制哪些方法能在外部被直接使用。

类的作用域

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

class person
{
public:
	void PrintPersonInfo();
private:
	char _name[20];
	char _gender[3];
	int _age[];
};
//定义函数方法先指明此函数是属于哪一个类的
void person::PrintPersonInfo()
{
	cout << _name << " " << _gender << " " << _age << endl;
}

类的实例化

用类型创建类的过程叫做类的实例化

        类是对对象进行表述的,是一个模型的东西,限定了类有哪些成员,定义出一个类并没有实际分配内存空间来进行存储。好比一张设计图纸,图纸上面限定了设计的方方面面,各方面细节。但是图纸始终是图纸,没有建造出实例化的对象就不占空间。

        一个类可以实例化多个对象,实例化的对象占用实际的物理空间,存储类成员变量。即需要先利用这张设计图设计出来的房子才具备住人等基本功能,人不能住进设计图内。

类对象模型

如何计算类对象的大小

class A
{
public:
	void PrintA()
	{
		cout << _a << endl;
	}
private:
	char _a;
};

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

首先要分析类的存储方式

通过以下一段代码获取大小对存储方式进行分析。

class A1//既有成员变量又有成员函数
{
public:
    void f1() {};
private:
    int _a;
};
class A2//仅有成员函数
{
public:
    void f2() {};
};
class A3//类中什么都没有
{};

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

成员函数实际在一个公共代码区域,因此计算类的大小和空类一致,编译器给空类一个字节来标识这个类的对象。

this指针

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 a;
};

int main()
{
	Date d1, d2;
	d1.Init(2022, 1, 11);
	d2.Init(2023, 12, 10);
	d1.print();
	d2.print();
}

        对于上述的一个Date类,有两个成员函数,函数体没有关于对象的区分,那为何d1和d2调用init函数的时候,设置对象却进行了区分呢。

        C++通过引用this指针解决该问题,即:C++编译器给每一个非静态成员函数增加了一个隐藏的指针,让该指针去指向当前对象(函数运行时调用该函数的对象),在函数体中所有成员变量的操作都是通过该隐式指针去访问的。不过所有的操作对用户是透明的,即用户不需要去传递,编译器自动完成。因此,哪有什么岁月静好,只是编译器在为你负重前行。

this指针的特性

  • 每个对象都有一个 "this" 指针:在C++中,每个类的对象都有一个 "this" 指针,它是一个指向对象自身的指针。

  • "this" 指针的隐含性:无需显式声明或初始化 "this" 指针。它是隐含的,C++编译器自动创建并使用它。

  • 成员函数内使用 "this" 指针:在类的非静态成员函数内,可以使用 "this" 指针来访问对象的成员变量和调用其他成员函数。例如,如果有一个成员变量 x,可以使用 this->x 来引用它。

  • 避免命名冲突:使用 "this" 指针有助于避免命名冲突。如果一个成员函数的参数或局部变量与成员变量同名,你可以使用 "this" 指针来明确指定你要访问的是成员变量,而不是局部变量。

  • const 成员函数中的 "this" 指针:当你有一个 const 成员函数时,"this" 指针的类型变为 const ClassName*,这意味着在该函数内不能修改对象的成员变量。


总结

        本章节主要涵盖了C++中的类和对象特性,以及介绍了C++11中引入的 "auto" 关键字。下面是一些重要的概念和内容的总结:

"auto" 关键字:

  • "auto" 关键字是C++11引入的一个特性,允许编译器根据初始化值的类型推导变量的类型,从而减少类型复杂性和提高代码可读性。

  • "auto" 关键字可以用于自定义类型、基本类型和表达式的类型推导。

  • "auto" 也可以结合指针和引用使用,根据右值类型进行类型推导。

类和对象:

  • 类是C++中的一个重要概念,它允许将数据和操作数据的方法有机地结合在一起,形成一个独立的数据类型。

  • 类定义了对象的形式,包含了数据成员(属性)和成员函数(方法)。对象是类的实例。

  • 成员变量是类的属性,成员函数是类的方法,它们用于访问和操作对象的状态。

  • 封装是类的一个关键特性,它隐藏了对象的内部细节,只允许通过公有接口来访问和操作对象。

  • 访问权限关键字(public、protected、private)用于控制成员的可访问性,限定了哪些成员可以被外部访问。

  • 类和对象的定义,成员函数的定义需要使用作用域操作符 :: 来标明属于哪个类。

类的实例化和对象模型:

  • 类定义了对象的模型,但类本身并不占用实际内存空间。对象的实例化是用类创建对象的过程,实际分配了内存空间来存储对象的成员变量。

  • 对象的大小取决于其成员变量的大小,不同的类对象可能占用不同大小的内存空间。

"this" 指针:

  • "this" 指针是一个隐含的指针,指向当前对象的地址。它允许在成员函数中访问对象的成员变量和其他成员函数。

  • "this" 指针在成员函数内部自动可用,无需显式声明或初始化。

  • "this" 指针是用来区分不同对象调用同一个成员函数的情况,从而正确地访问各自的成员变量。

      本章介绍了C++中的类和对象概念,封装特性,访问权限,以及 "auto" 关键字的使用。这些概念和特性是C++中面向对象编程的核心,用于创建更加模块化和可维护的代码。


    作者水平有限,文章难免出现错误,如有错误,欢迎指正!


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

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

相关文章

VisualStudio(VS)设置程序的版本信息(C-C++)

一、前言 在软件开发过程中&#xff0c;通常需要为生成的程序添加一些重要的元数据&#xff0c;如版本号、公司名称和版权信息。这些信息不仅可以提供对程序的更详细描述&#xff0c;还可以帮助用户了解程序的来源和使用限制。在 Visual Studio (以2017为例)中&#xff0c;可以…

大数据请把这个分离软件推给所有后期~

相信每个后期都要这样一个烦恼&#xff0c;怎样单独提取人声台词&#xff1f;怎么样提取背景音乐&#xff0c;今天就给大家推荐一款超实用的人声分离软件&#xff0c;可以在线提取人声或背景音乐&#xff0c;对于做后期的小伙伴们来说简直就是神器&#xff0c;再也不用到处找音…

C语言指针精简版(三)

目录 字符指针变量 剑指offer中经典题&#xff1a; 数组指针变量 ⼆维数组传参的本质 函数指针变量 typedef关键字 函数指针数组 什么是函数指针数组&#xff1f; 为什么要使用函数指针数组&#xff1f; 转移表 计算器的⼀般实现&#xff1a; 使用函数指针实现&…

MyBatisPlus(二十二)代码生成器

使用场景 使用代码生成器&#xff0c;根据数据库表&#xff0c;自动生成对应的 Entity&#xff0c;Mapper&#xff0c;Service&#xff0c;Controller 。 代码 依赖 两个依赖&#xff1a; 生成器依赖模板依赖 <dependency><groupId>com.baomidou</groupId&…

思维导图Xmind2023安装教程分享

wx供重浩&#xff1a;创享日记 对话框发送&#xff1a;xmind 获取 1、解压压缩包得到以下文件。 2、如果“winmm.dll”被系统删除不见&#xff0c;打开屏幕右下角处“windows安全中心”&#xff0c;在历史记录里将已删除的还原即可。 3、以管理员身份打开“Setup”。 4、…

Win10如何彻底关闭wsappx进程?

Win10如何彻底关闭wsappx进程&#xff1f;在Win10电脑中&#xff0c;用户看到了wsappx进程占用了大量的系统资源&#xff0c;所以想结束wsappx进程&#xff0c;提升电脑的运行速度。但是&#xff0c;用户们不知道彻底关闭掉wsappx进程的方法&#xff0c;那么接下来小编就给大家…

windows编译zlmediakit

开发环境搭建 使用visual studio 2022 打开360软件管家 &#xff0c;选择宝库&#xff0c;输入2022 点击安装 选择下图中的选择项目进行安装&#xff0c;安装路径可以修改为d盘 等待安装完成 打开源码进行编译 双击打开 选择打开文件夹 选择代码文件夹 配置如下&#xff…

视频播放音画同步处理

一、视频播放流程 播放一个视频&#xff0c;一般分一下几步完成 解复用&#xff08;Demux&#xff09;&#xff1a;在媒体文件中将音频数据、视频数据、字母数据分离出来。 二、播放参数说明 视频帧率&#xff1a;一秒钟需要显示的画面&#xff0c;比如25FPS&#xff0c;意思就…

sql注入的其他注入

1.宽字节注入 原因 绕过单双引号转义 ?id1 ?id1 1\ 服务器会把单引号转义&#xff0c;单引号由原来的定义字符串的特殊字符被转义为普通字符。 315c27 非常强烈的暗示 代码 单双引号转义 并且编码变成了gbk 上编码 表 这个是GBK编码表&#xff1a;https://…

可变参数模板+lambda

目录 可变参数模板 引入 介绍 展开参数包的方法 递归 逗号表达式 整体使用 emplace 介绍 ​编辑 使用 模拟实现 代码 示例 lambda 引入 介绍 格式 使用 传参 捕捉 原理 可变参数模板 引入 还记得c语言中的printf吗,可以传入任意数量的变量来打印,非常…

pytorch,tf维度理解RNN

input_t input_t.squeeze(1) 这行代码用于从 input_t 中去除尺寸为1的维度。在深度学习中&#xff0c;经常会出现具有额外尺寸为1的维度&#xff0c;这些维度通常是为了匹配模型的期望输入维度而添加的。 在这里&#xff0c;input_t可能具有形状 (batch_size, 1, feature_dim…

青否数字人SaaS系统5.0发布,支持真人接管实时驱动!

青否数字人SaaS系统5.0正式发布&#xff0c;提供口播视频批量制作7*24小时直播全套解决方案。同时直播间支持真人开麦/输入文字选择音色接管&#xff0c;实时驱动直播间数字人回复。 7*24小时直播 青否数字人客户端选择克隆好的数字人主播&#xff0c;克隆好的声音&#xff0…

实现vue项目和springboot项目前后端数据交互

1、安装node.js 太高版本的win7不支持 这里安装node-v12.16.2-x64.msi&#xff0c;指定安装位置后直接按下一步就可以。npm是node内置的工具 这里配置npm的镜像cnpm&#xff08;提高下载速度&#xff0c;以后用到npm的命令都可以用cnpm命令替换&#xff09;不指定cnpm版本使用…

Tuxera2023最新版本新功能特性

当您获得一台新 Mac 时&#xff0c;它只能读取 Windows NTFS 格式的 USB 驱动器。要将文件添加、保存或写入您的 Mac&#xff0c;您需要一个附加的 NTFS 驱动程序。Tuxera 的 Microsoft NTFS for Mac 是一款易于使用的软件&#xff0c;可以在 Mac 上打开、编辑、复制、移动或删…

【论文阅读笔记】 Curated Pacific Northwest AI-ready Seismic Dataset

Curated Pacific Northwest AI-ready Seismic Dataset 太平洋西北部人工智能地震数据集 摘要 描述了一个AI就绪地震数据集包括各种地震事件参数 仪器元数据 地震波行描述地震目录和事件属性&#xff08;事件震级类型&#xff0c;信道类型&#xff0c;波形极性&#xff0c;信…

【框架源码篇 02】Spring源码-手写DI

Spring源码手写篇-手写DI 简单回顾前面的手写IoC的内容。 一、DI介绍 DI(Dependency injection)依赖注入。对象之间的依赖由容器在运行期决定&#xff0c;即容器动态的将某个依赖注入到对象之中。说的直白点就是给Bean对象的成员变量赋值。 在这里我们就需要明白几个问题。 1.…

【进阶C语言】C语言文件操作

1. 为什么使用文件 2. 什么是文件 3. 文件的打开和关闭 4. 文件的顺序读写 5. 文件的随机读写 6. 文本文件和二进制文件 7. 文件读取结束的判定 8. 文件缓冲区 一、文件与文件的意义 1.文件的意义 文件的意义&#xff0c;无非就是为什么要使用文件&#xff1f; &#xff08;1&…

当中国走进全球化的“深水区”,亚马逊云科技解码云时代的中国式跃升

中国跨境贸易中支付金融与服务领域的综合创新型企业连连国际的联席CEO沈恩光发现&#xff0c;眼下&#xff0c;很多跨境电商的出海方式已发生了变化。几年前&#xff0c;它们还主要借助第三方电商平台&#xff0c;而现在&#xff0c;更多公司开始选择通过自主渠道进入海外市场&…

线性代数-Python-01:向量的基本运算 - 手写Vector及numpy的基本用法

文章目录 一、代码仓库二、向量的基本运算2.1 加法2.2 数量乘法2.3 向量运算的基本性质2.4 零向量2.5 向量的长度2.6 单位向量2.7 点乘/内积&#xff1a;两个向量的乘法 --答案是一个标量 三、手写Vector代码3.1 在控制台测试__repr__和__str__方法3.2 创建实例测试代码3.3 完整…