首页 > 编程语言 >C++——类和对象(上)

C++——类和对象(上)

时间:2024-11-22 12:43:34浏览次数:3  
标签:函数 对象 C++ 限定符 指针 属性

19178bd4cd074ff9836f734e413da6f9.png

前言

C语言大家都不陌生,它的最大特点是面向过程

而C++是C语言的升级版,它由原来的面向过程转变为面向对象

两者有什么区别呢?

本次文章带你处认识C++中的面向对象

面向对象和面向过程

C语言面向过程

  • 面向过程就是关心各个步骤的交互,步骤的顺序影响结果

C++面向对象

  • 面向对象就是关心各个对象之间的交互,对象之间的如何交互影响结果

简单的定义,无法理解二者的区别,谁优谁劣

举个例子——洗衣服

如果是面向过程,我们将会注重过程,步骤的顺序

则洗衣服变成:

c46f40ca85ac4a8c9b69a650ee8a01fe.jpeg

面向过程就是步骤之间交互,一个步骤接着一个步骤,一个步骤对另一个步骤产生影响

如果是面向对象,我们就会注重对象之间如何合作,关注对象做什么

则洗衣服变成:

3e84f297710c4f708ff660613d8a5aac.jpeg

面向对象就是对象之间交互,一个对象对另一个对象做事

这样一看,区别就出来了

  • 面向对象,比面向过程简单太多了

面向对象的本质也是面向过程,只是面向对象将面向过程中的步骤隐藏进了对象中,将具体步骤隐藏,不暴露出来

步骤实际并未减少,但减少了办事人的工作量

  • 如果是面向过程:我们需要“洗”、“换”、“搓”、“放”
  • 如果是面向过程:我们只需要“放”

C++面向对象的特性因为类得以体现

类是C++相较于C语言一种新的形式

class ClassName//class+类名
{

  
 //具体内容


};//分号一定要加!

一个类在投入使用前,有三个阶段

  1. 类的声明:表示有这个类
  2. 类的定义:表示这个类中有什么
  3. 类的实例化:创建一个类对象

类的定义

我们通常将类的声明和定义放在一起,其中也有一些特殊情况,需要在定义前先声明

声明形式

class ClassName;//直接class+类名,注意分号

我们重点看类的定义

类的定义

  • 对类进行充实,添加成员,如函数和变量

其中

  • 类的函数,我们称之为成员函数或者类的方法
  • 类的变量,我们称之为成员变量或者类的属性
class ClassName
{
  //函数
  //方法
};

C++是C语言的升级,C++的类不仅可以有属性,还可以有函数,而结构体只能有属性。

类的两种定义方法

  1. 声明和定义全部放在类体中,注意:成员函数如果在类中被定义,有可能被编译器当成内联函数
  2. 声明放在类体中,定义放在类外,定义在类外时,成员函数前添加——类名::
  • 如:我们一般将类放在.hpp中进行声明,类的成员函数和属性也在类中声明,但成员函数的定义放在.cpp中进行定义

62e7b4b9f32241329505eae6cc5d3dad.jpeg

我们一般建议采用第二种定义方法,这就和手机商卖手机一样

  • 卖是靠手机专卖店卖
  • 造是靠手机工厂造

你永远无法看到一个手机是如何生产的,交到你手上就是一个完整的手机 

一定程度上增加了保密性,更加安全

我们实际采用第二种方法,不仅更加安全,也能让代码不冗余

类的实例化

类的声明和定义完成后,就可以直接使用了吗?

试一下

c1b7d6df510b42a2a2e28212a83e77d2.png

报错了,为什么?

因为没有实例化!

类没有实例化之前,都是虚的。

  • 就像函数没有调用之前,充其量只是一传存储在文件中的文本信息,没有任何作用

就像小说中说的

传说中的某某宝物,我曾经旨在一本记载上古宝物的书籍中见过,据说有XX功效

48d9aa505dae41d4b73d09161918fbe5.jpeg

相当于,类只有声明和定义,没有实例化

没有想到,今天居然在这里见到了

c1b5b1bbdef84015b395cb994cc9ad2a.jpeg

类被实例化了

类没有被实例化之前,几乎没有用,形如虚设

注意关键字“几乎”

  1. 类的方法不一定不能用
  2. 类的属性一定不能用

类,只是一个类型,它需要一个载体来实现它的功能

就像《凡人修仙传》中的没有躯体的修士灵魂

几乎无法做任何事情,但他仍有思想,有记忆,能思考,自己知道能做什么,要做什么

但只有等夺舍,重新拥有躯体,才能真正做事

14e6c0352e4446f98aa2c5e09fd1db52.jpeg

如果强行使用未实例化的类中的成员,则会引发报错。

实例化后,就可以使用类

实例化类,相当于创建一个变量,我们习惯将类的变量称之为对象

通过对象,来使用类中的成员变量和成员函数

#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
class A
{
public:
	void Print()
	{
		std::cout << "a: " << a <<" " << "b: " << b << std::endl;
	}
	int a;
	int b;
};
int main()
{
	A tmp;//实例化一个类A对象tmp
	tmp.a = 10;//使用属性
	tmp.b = 20;//使用属性
	tmp.Print();//使用方法
	return 0;
}

运行结果

b127b8333b5d4fefb21d087c9cf891ce.png

 类的大小

类中有属性有方法,那么类的大小是多少呢?

验证一下

class A
{
public:
    void Print()
	{
		std::cout << "a: " << a << " " << "b: " << b << " " << "c: " << std::endl;
    }
private:
	int a;
	int b;
	int c;
};
int main()
{
	A tmp;
	std::cout << sizeof(A) << std::endl;
	std::cout << sizeof(tmp) << std::endl;
	return 0;
}

结果

a329071199f44861a29166f69a8ccafa.png

为什么会这样? 

类的大小只和类的属性有关,与类的方法无关

当你使用一个类创建多个对象的时候,每个类对象的属性的值会有所不同,但每个类对象使用的方法执行的功能都是一样的。

我们有必要为了一个一样的函数单独开辟空间吗?

没有必要

类就像小区中的一种户型设计图,这种户型只有一个

2d98e021a07f4236b8fd66d3b203b70c.png

但小区根据户型建造的每一套房子就像由类实例化的对象,可以有很多个

它们有着相同的布局,就像类对象有相同的方法和属性

类的属性就像每套房子中的厨房客厅卧室,也是独立的,可以自己设计装修风格

而类的方法,就像是小区的公共场所,如篮球场、公园

大家用这些公共场所的目的是一样的,完全没有必要每一个人一个篮球场,每个人一个公园

类被实例化后

  • 它的变量会根据初始化方式不同,存储在不同区域
  • 类的方法,则会统一存放在一个公共代码区,等待调用

7c6ba90c5be6410993ea634af5dfc6a4.jpeg


this指针

当类对象使用类方法,类方法中涉及对类的属性相关操作的时候,是不是会出现歧义

什么歧义?

当用一个类创建两个对象A和B

该类具备属性,并且有一个类方法Print打印类的属性的值

当对象A和对象B同时调用Print方法的时候

打印出的属性,是对象A的属性,还是对象B的属性?

实际上,我们知道

  • 对象A调用,就打印对象A的属性的值
  • 对象B调用,就打印对象B的属性的值

但为什么?

为什么不同对象使用相同类方法的结果不一样?

因为每一个类的方法的参数中,会有一个指针this

这个this指针,指向当前类的一个对象,类型为——类名*

当方法被定义的时候

  • 我们定义的是:返回值类型 方法名(参数1 , 参数2,......)
  • 编译器看到的是:返回值类型 方法名(this指针,参数1,参数2,......)

当方法中,涉及对类的属性操作

  • 我们看到的是:属性
  • 编译器看到的是:this->属性

当方法被类对象调用的时候,类对象就会把自己的地址,传递给这个指针。

类方法,就可以通过指针的值,来找到对应的类对象

这样,同样的类方法,因为this指针的值不同,就可以访问不同的类对象

不懂的,可以看下面这个例子

你在学校是一个学生类对象,你们学校会有很多学生对象

学生都会有一张自己的校园卡,校园卡上有学生自己的属性,如余额

当你们在学校用餐的时候,是用机器刷卡扣钱的

机器,相当于一个类方法,大家都可以使用

当你用机器刷卡的时候

刷自己的卡,会扣别人的钱吗?

并不会,只会扣自己的钱,因为你使用校园卡进行刷卡的时候

机器会找到你的信息,然后从你的余额上扣钱

校园卡刷卡的过程,相当于传递地址

告诉机器“你应该去找哪个类对象”,“你应该扣谁的钱!”

两个this指针问题

  • 问题一:this指针可以为空吗?
  • 问题二:this指针存在哪里?

解决这两个问题前,首先得认清this指针的本质,靠本质去解决问题

this指针的本质:不过是一个函数的一个形参罢了

8c7801cd2d9047338fb6734bd319b7f4.jpeg

this指针可以为空吗?

this指针是一个函数的形参

这个形参的类型是指针,指针当然可以为空!

所以,this指针可以为空,并且函数依然可以正常被调用

验证一下

class A
{
public:
	void Test()
	{
		std::cout << "测试一下" << std::endl;
	}
};
int main()
{
	A*tmp=nullptr;
	tmp->Test();
	return 0;
}

运行结果 

5d2cfffed2734ca38ae6e9acb59ac002.png

this指针存在哪里?

铭记this指针的本质——一个函数的一个形参罢了

当一个函数执行前,它所需要的空间大小,已经在栈帧中开辟好了

函数存于栈帧之中,其中的形参也是

所以,this指针存在于函数栈帧之中


封装 

我们在之前就说过,面向对象本质上就是面向过程,但面向对象将过程中的步骤隐藏进了对象中

这种隐藏的方法,我们称之为“封装

  • 封装在于将复杂的步骤进行隐藏,只放在内部,外部是无法看见的,只提供给外部一个接口

当外部使用接口的时候,步骤就会开始!

封装是C++的三大特性之一,它的存在,让C++显得更加简单,易用。

怎么说呢,举个例子

我们平常使用的电脑,它工作的时候,内部硬件会进行十分复杂的交互。

计算机厂商在电脑出厂的时候,在外部套上一个壳子,将内部实现细节全部隐藏起来,仅仅对外提供开关机、鼠标以及键盘插孔等。

13f68e7c86a74386866b0ae8fb8b760c.png

我们看到的,只有关机键、鼠标、键盘等,我们也只需要使用这些,就可以享受电脑的全部功能,我们需要了解内部硬件是怎么交互的吗?

如CPU怎么工作、硬盘怎么存储数据

cfd4122bdafc4b5082ceaeb5a8bbe584.png

显然不用,因为我们有封装,不需要了解内部硬件怎么工作,互相怎么合作

我们只需要提供给我们的简单接口——鼠标、键盘等就可以了

访问限定符

我们用封装,对过程进行隐藏

我们不希望把复杂的东西暴露在外面,另外一些隐私的东西,或者容易引发错误的东西,我们也不想暴露,被他人随意访问,如:类的属性

因此,我们用三个访问限定符来对类的成员进行选择性隐藏和公开

三个访问限定符

  • protected
  • private
  • public

访问限定符说明

  1. public修饰的成员在类外可以被直接访问
  2. protected和private修饰的成员在类外不能被直接访问
  3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
  4. 如果后面没有访问限定符,作用域到类结束

因为我们的诉求,是对一些成员进行选择性隐藏和开放,增强保密性

所以需要我们主动去设置访问限定符,但我们也有忘记的时候

这时候,编译器就会将没有主动被限定的部分,用默认访问限定符进行限定

C++类的默认访问限定符是private

C++中的结构体和类

C++是在原来C语言的基础上进行升级,它不仅有更多的新玩法,也保留了一些旧的东西

如C语言的结构体

C++中的结构体,不仅保留了原来的可以声明变量,甚至向类看齐,能在结构体中声明和定义函数

C++中结构体和类的共同点

  • 能声明和定义函数
  • 能声明变量

当一个类没有主动设置访问限定符的时候,C++会默认它的所有成员的访问限定符是private

当一个结构体没有主动设置昂文限定符的时候,C++会默认它的所有成员的访问限定符是public

C++中结构体和类的不同点

  • C++的类的默认访问限定符是private
  • C++的结构体默认访问限定符是public

总结

本文章相当于C++的正式入门,我们真正认识到了什么是面向对象,以及它的好处,在C++中是怎么体现的,后续的文章中,我们将继续介绍类,将类吃透

有问题,欢迎在评论区讨论

觉得有所帮助,麻烦点个赞,关注一下

e934d3d56cce46f49b8408149bcff218.png

标签:函数,对象,C++,限定符,指针,属性
From: https://blog.csdn.net/2402_85267481/article/details/143815047

相关文章

  • C++四级抽测题目(答案+题目)
    今天我给大家出一套C++四级考题限时1小时,大家加油!!!题目1:改变二维数组题目描述输入一个n行m列的二维数组,把它的奇数和偶数行互换后输出。(如果n为奇数,最后的一行无需调换位置)n,m为不超过20的正整数。数组内的数据为不大于200的正整数。输入格式共n+1行......
  • C++三级抽测题目(答案+题目)
    今天我给大家出一套C++三级考题限时1.5小时,大家加油!!!题目1:回文数回文数题目描述若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。例如:给定一个十进制数56,将56加65(即把56从右向左读),得到121是一个回文数。又如:数87:STEP1:87+78=165S......
  • C++:模拟实现unordered_map和unordered_set
    目录一.unordered_set和unordered_set二.哈希表的改造三.整体代码1.MyUnorderedMap.h2.MyUnorderedSet.h3.HashTable.h4.Hash.cpp一.unordered_set和unordered_setunordered_set和unordered_map的实现通过调用哈希表即可#pragmaonce#include"HashTable.h"using......
  • C++AVL平衡树
    1.AVL平衡树节点定义每一个节点都配左右孩子和父节点,以及平衡因子和其所对应的值。template<classK,classV>structAVLTreeNode{ //需要parent指针,后续更新平衡因子可以看到 pair<K,V>_kv; AVLTreeNode<K,V>*_left; AVLTreeNode<K,V>*_right; AVLTreeNode<K......
  • QT 线程 QThread QT5.12.3环境 C++实现
    一、线程  QT主线程称为GUI线程,负责初始化界面并监听事件循环,并根据事件处理做出界面上的反馈。如果把一些比较复杂或者费时的操作放在主线程中,界面就会出现卡顿或者无响应的现象。一般主线程负责影响界面上的操作,子线程负责负责费时的数据处理。二、使用多线程有什么好......
  • QT基础 编码问题 定时器 事件 绘图事件 QT5.12.3环境 C++实现
    一、编码问题        在计算机编程中,流(Stream)是一种抽象的概念,用于表示数据的输入或输出。根据处理数据的不同方式,流可以分为字节流(ByteStream)和字符流(CharacterStream)两大类。1.字节流(ByteStream)        字节流是处理数据的基本单位是字节(8位二进制数......
  • QT基础 窗体 对话框 文件 QT5.12.3环境 C++实现
    一、堆栈窗体1.概念是一种界面设计思路,多个窗体重叠在一起,通过点击对应的按钮,显示对应的界面。2.相关方法PublicFunctions  QStackedWidget(QWidget*parent=0)  //stack如果单纯指定父窗口,但是没有指定大小,那么是不显示的  intaddWidget(QWidget*......
  • 深度克隆对象的方法有哪些,并把你认为最好的写出来
    在前端开发中,深度克隆对象的方法主要有以下几种:JSON.parse(JSON.stringify(obj)):这是最简单和常用的方法,它利用JSON序列化和反序列化来实现深度克隆。然而,这种方法有一些局限性:无法处理循环引用:如果对象中存在循环引用,则会抛出错误。无法克隆函数、Date、RegExp等......
  • 【C++】右值引用与移动语义详解:如何利用万能引用实现完美转发
    C++语法相关知识点可以通过点击以下链接进行学习一起加油!命名空间缺省参数与函数重载C++相关特性类和对象-上篇类和对象-中篇类和对象-下篇日期类C/C++内存管理模板初阶String使用String模拟实现Vector使用及其模拟实现List使用及其模拟实现容器适配器Stack与QueuePriority......
  • 【JAVA】Java基础—面向对象编程:常用API与数据结构—常用工具类(Collections、Arrays等
    在Java开发中,常用工具类如Collections和Arrays为我们提供了处理数据结构和算法的便捷方法。1.Collections框架背景介绍:Java的Collections框架提供了一套用于存储和操作数据的接口和类。它包括List、Set、Map等常用数据结构,帮助开发者高效地管理数据。重要性:在实际应用中,C......