C++-类与对象(上)

news2024/12/24 2:47:36

一、

auto关键字

1.自动识别数据类型

2.auto的初始化

3.auto简化for循环

nullptr的使用

二、类与对象

1.c++中类的定义

2.c语言与c++的比较

3.类的访问限定符以及封装

3.1访问限定符

3.2封装

3.3类的作用域

3.4类的声明与定义分离


🗡CSDN主页:d1ff1cult.🗡

🗡代码云仓库:d1ff1cult.🗡

🗡文章栏目:数据结构专栏🗡

一、

auto关键字

auto的意义:类型名字较长时使用auto来定义比较方便

1.自动识别数据类型

auto关键字可以自动识别数据的类型,我们可以是typeid()name.()函数来查看一个数据的类型

int main()
{
	int a = 0;
	int b = a;
	auto c = a;
	auto d = &a;
	auto* e = &a;
	int& f = a;
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;
	cout << typeid(e).name() << endl;
	cout << typeid(f).name() << endl;
	return 0;
}

下面是运行结果

typeid().name()函数可以输出一个数据的类型,我们auto c=a;a是int类型的,那么auto出来的c也是int类型的,auto d=&a,那么这个d的数据类型就是int *。

上面只是auto用法的一个小小小小小的用法。

2.auto的初始化

auto初始化时必须在右边给个值进行初始化,不然auto无法识别数据的类型

auto=x; //对auoto错误的初始化

auto x=1.0;
auto x=1.22;

需要注意的是auto不能作为函数的参数,也不能作为一个函数的返回值,与此同时auto也不能用来声明数组

3.auto简化for循环

int main()
{
int array[] = { 1,2,3,4,5 };
	for (int i = 0; i < sizeof(array) / sizeof(array[0]); i++)
	{
		array[i] *= 2;
	}
	for (int* p = array; p < array + sizeof(array) / sizeof(array[0]); ++p)
	{
		cout << *p << endl;
	}
	for (auto e : array)
	{
		cout << e << "";
	}
	cout << endl;
	return 0;
}

auto在这里的作用:依次取数组中的数字赋值给e,并且自动判断结束,自动++往后走。

auto简化for循环时 auto e中的e只是数组内容的一份临时拷贝,对e进行操作不会修改数组中的值,如下

int main()
{
for (auto e : array)
	{
		e++;
		cout << e << "";
	}
	cout << endl;
	for (auto e : array)
	{
		cout << e << "";

	}
	cout << endl;
	return 0;
}

如果想要通过修改e来对数组内容进行修改,可以使用 引用

int main()
{
for (auto &e : array)
	{
		e++;
		cout << e << "";
	}
	cout << endl;
	for (auto e : array)
	{
		cout << e << "";

	}
	cout << endl;
	return 0;
}

eg:c语言为了效率,数组是不能够传参的,一般是使用数组的首元素的地址进行传参的。

nullptr的使用

c语言中的NULL本质上是一个宏定义,#define NULL 0

在c++中 为了弥补这一缺陷,使用了nullptr来替换NULL

二、类与对象

1.c++中类的定义

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

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

类体中内容称为类的成员类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。

类的两种定义方式:

1.声明和定义全部放在类体中,需注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理

//定义一个人
class People
{
public:
	void show()
	{
		cout << _name << "-" << _sex << "-" << _age << endl;
	}
public:
	char* _name; //姓名
	char* _sex;  //性别
	int _age;    //年龄
};

2,类声明放在 .h 文件中,成员函数定义放在 .cpp 文件中,注意:成员函数名前需要加类名::    以此来进入对应的域中

People.h
 
//人
class People
{
public:
	void show();
public:
	char* _name; //姓名
	char* _sex;  //性别
	int _age;    //年龄
};
 
People.cpp
 

void Person::show()
{
	cout << _name << "-" << _sex << "-" << _age << endl;
}

2.c语言与c++的比较

c++向下兼容所有c语言struct所有的用法

struct同时升级成了类

1、类名就是类型,Stack就是类型,不需要加struct

2、函数的定义都放在了类中

下面这一段是c语言对栈进行初始化

//C语言
struct Stack
{
 int* a;
 int top;
 int capacity;
};

void StackInit(struct Stack* ps);
void StackPush(struct Stack* ps, int x);

 下面是c++的一段

class Stack
{
private:
	int* a;
	int top;
	int capacity;

public:
	void Init()
	{
		a = 0;
		top = 0;
		capacity = 0;
	}

	void Push(int x)
	{
		//...
	}

	bool Empty()
	{
		return top == 0;
	}
};

 同样都是对栈进行声明以及初始化,但其实c++是比较方便简单的,例如Push()函数,c语言是不支持重名函数的,但是在c++中不同的域中函数的作用不同,我们可以通过调用不同的域中的函数来实现不同的功能

3.类的访问限定符以及封装

3.1访问限定符

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

1.public修饰的成员在类外可以直接被访问
2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)

3.访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止

4.如果后面没有访问限定符,作用域就到 },即类结束
5.class的默认访问权限为private,struct为public(因为struct要兼容C)

这里有一道关于struct和class的面试题:

C++ 中 struct 和 class 的区别是什么?

C++ 需要兼容 C语言,所以C++中struct可以当成结构体使用;

另外C++中struct还可以用来定义类。和class定义类是一样的,区别是struct定义的类默认访问权限是public,class定义的 默认访问权限是private;

3.2封装

  • 封装可以隐藏实现细节,使得代码模块化,使代码和功能独立
  • 封装是把函数和数据包围起来,对数据的访问只能通过可信任的对象和类进行访问,对不可信的进行信息隐藏。
  • 封装本质上是一种管理,让用户更方便使用类。

3.3类的作用域

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

class Person
{
public:
	void PrintPersonInfo();
private:
	char _name[20];
	char _gender[3];
	int  _age;
};
// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
	cout << _name << " " << _gender << " " << _age << endl;
}

 访问时如果不加作用域操作符号,编译器就不知道应该调用哪一个域内的函数。

c++中花括号定义的都是域

3.4类的声明与定义分离

 类中成员函数可以在类中直接进行声明与定义同时也可以将声明和定义分开,例如下面

在类中定义时,由于我们已经在对应的域中,所以我们不需要使用::访问,若我们将成员函数的声明与定义分离之后,定义的时候就需要加上这样使用:void Stack::Init(),因为我们不知道这个Init函数究竟是哪一个类中的成员,所以我们需要使用::来限制它的域

//Stack.h文件
class Stack
{
private:
	int* a;
	int top;
	int capacity;
public:
	void Init();
	void Push(int x);
	bool Empty();
};
//Stack.cpp文件
void Stack::Init()
{
	a = 0;
	top = 0;
	capacity = 0;
}
void Stack::Push(int x)
{
	//....
}

在类中定义的函数默认就是inline,正确的定义方法应该是,长的函数的定义和声明分离,短小的可以直接在类里面定义

 3.5成员变量命名规则

class Date
{
public:
	void Init(int year)
	{
		year = year;
	}
private:
	string year;
};
 
int main()
{
	return 0;
}

看到这个函数我们不免发出疑问,调用Init的这个函数中 两个year,哪一个是成员变量,哪一个是函数的形参,这样的写法使得阅读代码的人一个头两个大。所以我们可以在成员变量前加上一个下划线来区分形参和成员变量

class Date
{
public:
	void Init(int year)
	{
		_year = year;
	}
private:
	int _year;
};

 3.6内存对齐规则

1,第一个成员在与结构体偏移量为 0 的地址处。

2,其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。

     注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。

     VS中默认的对齐数为8

3,结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍

4,如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体    的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

 3.7类中对象的存储方式

存储方式:保留成员变量,成员函数存放在公共的代码段

 类的大小,根据内存对齐规则可以求得

需要注意的是:一个类的大小就是通过内存对齐规则后求得的大小,特殊的是我们要注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。

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

//private:
	// 声明
	int _year;
	int _month;
	int _day;
};

class A
{
private:
	char _ch;
	int _a;
};

class B
{};

class C
{
public:
	void f()
	{};
};
int main()
{
	Date d1;
	Date d2;
	Date d3;

	cout << sizeof(d1) << endl;
	cout << sizeof(A) << endl;

	B b1;
	B b2;

	cout << sizeof(B) << endl;
	cout << sizeof(C) << endl;

	// 无成员变量的类,对象大小开一个字节,这个字节不存储有效数据
	// 标识定义的对象存在过

	return 0;
}

 

类B与类C的大小都是1。

3.8 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 main()
{
	Date d1, d2;
	d1.Init(2022, 1, 11);
	d2.Init(2023, 1, 12);
	d1.Print();
	d2.Print();
	return 0;
}

 

d1.Print()没有传参数,为什么还能打印出d1的内容呢,这一切都要归功于this指针

C++ 编译器给每个“非静态的成员函数“增加了一个隐藏的指针参数,让该指针指向当前对象(函数运行时调用该函数的对象),在函数体中所有“成员变量” 的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

 3.9this指针的一些性质

1.this指针的类型是const *类型,不能写this相关的实参和形参,不能给this指针赋值

2.只能在成员函数内部使用

3.this指针能在类中显示调用

4.this指针是个形参,存储在栈帧上,不是存储在对象中的


总结

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

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

相关文章

转变命运!揭秘反转链表的神奇算法!

目录 使用虚拟头节点来辅助实现链表反转直接操作链表实现反转使用递归来实现链表反转 链表是计算机科学中常用的数据结构之一&#xff0c;它由一系列节点构成&#xff0c;每个节点包含一个值和指向下一个节点的指针。链表的灵活性使其在许多场景下被广泛应用&#xff0c;但其中…

S32K144芯片焊接完成后使用S32DS初次下载无法下载解决方法

一、问题现象如下&#xff0c;S32DS Debug下报错 二、原因&#xff0c;原厂芯片出厂时的FLASH Memory的安全机制是激活的&#xff0c;仿真器是可以连上&#xff0c;但是没法读取Flash Memory的内容 三、解决方法 参考图示&#xff0c;解锁后即可正常Debug

2023mathorcup大数据竞赛选题建议及思路

大家好呀&#xff0c;昨天6点2023年第四届MathorCup高校数学建模挑战赛——大数据竞赛开赛&#xff0c;在这里给大家带来初步的选题建议及思路。 注意&#xff0c;本文章只是比较简略的图文讲解&#xff0c;更加详细完整的视频讲解请移步&#xff1a; 2023mathorcup大数据数学…

【Opencv4快速入门】轮廓检测findContours

7.2 轮廓检测findContours 7.2.1 轮廓查找findContours7.2.2 轮廓绘制drawContours图像轮廓是指图像中对象的边界,是图像目标的外部特征,这个特征对于图像分析、目标识别和理解更深层次的含义具有重要的作用。 7.2.1 轮廓查找findContours 图像的轮廓补单能够提供物体的边缘,…

Crypto(6)攻防世界-babyrsa

参考文章&#xff1a; [攻防世界adworld] Crypto - babyrsa - 知乎 (zhihu.com) 涉及到的RSA知识点&#xff1a;

systrace/perfetto如何看surfaceflinger的vsync信号方法-android framework实战车载手机系统开发

背景&#xff1a; hi&#xff0c;粉丝朋友们&#xff1a; 大家好&#xff01;近期分享了surfaceflinger相关的一些blog&#xff0c;有同学就对相关的一些内容产生了一些疑问。 比如&#xff1a;vsync查看问题&#xff0c;即怎么才可以说是vsync到来了。 比如perfetto中surfac…

保姆级教学安装Linux操作系统,以及Linux的语法入门

&#x1f3c5;我是默&#xff0c;一个在CSDN分享笔记的博主。&#x1f4da;&#x1f4da; &#x1f31f;在这里&#xff0c;我要推荐给大家我的专栏《Linux》。&#x1f3af;&#x1f3af; &#x1f680;无论你是编程小白&#xff0c;还是有一定基础的程序员&#xff0c;这个专…

【性能测试】初识 Jmeter 中的 BeanShell

初识 Jmeter 中的 BeanShell 1.简介1.1 应用场景1.2 BeanShell 类型 2.常用内置变量2.1 log 日志模块2.2 vars 模块2.3 props 模块2.4 prev 模块 3.常见应用场景3.1 Java 文件处理3.2 导入外部 jar 包 BeanShell 是一个小型嵌入式 Java 源代码解释器&#xff0c;完全兼容 Java …

大数据采集技术与预处理学习一:大数据概念、数据预处理、网络数据采集

目录 大数据概念&#xff1a; 1.数据采集过程中会采集哪些类型的数据&#xff1f; 2.非结构化数据采集的特点是什么&#xff1f; 3.请阐述传统的数据采集与大数据采集的区别&#xff1f; ​​​​​​​ ​​​​​​​4.大数据采集的数据源有哪些&#xff1f;针对不同的数…

二叉树的前序、中序和后序非递归

目录 一、前序 二、中序 三、后序 一、前序 力扣&#xff08;LeetCode&#xff09;官网 - 全球极客挚爱的技术成长平台 /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0)…

C++ 类和对象 (查漏补缺)

Inline 内联函数 内联函数是为了替代宏函数而出来的。 下面用宏实现一个ADD宏函数&#xff1a; 为什么这个ADD宏函数要这么写&#xff0c;首先我们来看&#xff0c;假设这样写&#xff1a; #define ADD(x,y)(xy) 会有什么问题呢&#xff1f; 宏函数是直接替换了&#xf…

FileInputStream文件字节输入流

一.概念 以内存为基准&#xff0c;把磁盘文件中的数据以字节形式读入内存中 二.构造器 public FileInputStream(File file) public FileInputStream(String pathname) 这两个都是创建字节输入流管道与源文件接通 三.方法 public int read() :每次读取一个字节返回&#xff0c;如…

设计模式:原型模式(C#、JAVA、JavaScript、C++、Python、Go、PHP)

上一篇《访问者模式》 下一篇《享元模式》 简介&#xff1a; 原型模式&#xff0c;它是一种创建型设计模式&#xff0c;它允许通过复制原型对象来创建新的对象&#xff0c;而无需知道创建的细节。其工作原…

安装Spring Tool Suite 4的一些问题

1、安装lombok.jar &#xff08;1&#xff09;把lombok.jar放到Spring Tool Suite 4的根目录下&#xff0c;java -jar lombok.jar&#xff0c;选择Spring Tool Suite 4&#xff0c;安装。然后SpringToolSuite4.ini里面会自动写入一行 sts4需要额外配置一行参数【-javaagent:lo…

springboot+mybatis-plus实现读写分离

shigen坚持日更的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。坚持记录和分享从业两年以来的技术积累和思考&#xff0c;不断沉淀和成长。 最近shigen加班也比较严重&#xff0c;很多天文章没有更新了&#xff0c;各位读者和伙伴见…

2023/10/28 JAVA学习

导入模块 找到模块路径后,复制到上面,注意导入的是这个 还需要注意,这样导入的话,可能模块不在同一个工程文件里,如果不小心删除这个模块,就不能使用了,所以建议,把原本模块先复制到工程文件中,然后再找模块路径,进行上面操作 还有一种方式新创一个模块,然后把想要导入的模块代…

不一样的网络协议-------KCP协议

1、kcp 的协议特点 1.1、RTO 不翻倍 RTO(Retransmission TimeOut)&#xff0c;重传超时时间。tcp x 2&#xff0c;kcp x 1.5&#xff0c;提高传输速度 1.2、选择重传 TCP丢包时会全部重传从该包开始以后的数据&#xff0c;而KCP选择性重传&#xff0c;只重传真正丢失的数据包…

『力扣刷题本』:移除链表元素

一、题目 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val val 的节点&#xff0c;并返回 新的头节点 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,6,3,4,5,6], val 6 输出&#xff1a;[1,2,3,4,5]示例 2&#xff1a; 输入&a…

时序预测 | Matlab实现ARIMA-LSTM差分自回归移动模型结合长短期记忆神经网络时间序列预测

时序预测 | Matlab实现ARIMA-LSTM差分自回归移动模型结合长短期记忆神经网络时间序列预测 目录 时序预测 | Matlab实现ARIMA-LSTM差分自回归移动模型结合长短期记忆神经网络时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 时序预测 | Matlab实现ARIMA-LSTM差…