C++ 之 【类与对象】从入门到精通一条龙服务 入门篇

不要觉的自己很没用,其实你还可以给家人带来温暖,比如爸妈看到你就来火

目录:

一、面向过程和面向对象初步认识

二、类的引入

三、类的定义

四、类的访问限定符及封装

1.访问限定符

2.封装

五、类的作用域

六、类的实例化

七、类的对象大小的计算

1.类对象的存储方式猜测

2.结构体内存对齐规则

八、类成员函数的this指针

1.this指针的作用

2.this指针的特性

3.面试题练习

九、完结撒❀

前言:

对于类和对象的讲解一共划分为3篇,这是第1篇入门篇学习,更适合小白宝宝的体质

–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀-正文开始-❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–❀–

一、面向过程和面向对象初步认识

C 语言是 面向过程 的, 关注 的是 过程 ,分析出求解问题的步骤,通过函数调用逐步解决问题。
比如我们可以拿洗衣服为例:

C++ 基于面向对象 的, 关注 的是 对象 ,将一件事情拆分成不同的对象,靠对象之间的交互完
成。

二、类的引入

C 语言结构体中只能定义变量,在 C++ 中,结构体内不仅可以定义变量,也可以定义函数。 比如:
之前在数据结构初阶中,用 C 语言方式实现的栈,结构体中只能定义变量 ;现在以 C++ 方式实现,
会发现 struct 中也可以定义函数。
举例代码如下:
typedef int DataType;
struct Stack
{
   void Init(size_t capacity)
   {
      _array = (DataType*)malloc(sizeof(DataType) * capacity);
      if (nullptr == _array)
      {
         perror("malloc申请空间失败");
         return;
      }

      _capacity = capacity;
      _size = 0;
   }

   void Push(const DataType& data)
   {
      // 扩容判断 此处省略
      _array[_size] = data;
      ++_size;
   }

   DataType Top()
   {
      return _array[_size - 1];
   }
   void Destroy()
   {
      if (_array)
      {
         free(_array);
         _array = nullptr;
         _capacity = 0;
         _size = 0;
      }
   }

   DataType* _array;
   size_t _capacity;
   size_t _size;
};

int main()
{
   Stack s;
   s.Init(10);
   s.Push(1);
   s.Push(2);
   s.Push(3);
   cout << s.Top() << endl;
   s.Destroy();
   return 0;
}
 

可以看到在上面代码中,结构体stack里面定义了变量:

DataType * _array ;
size_t _capacity ;
size_t _size ;
还定义了函数:
void Init ( size_t capacity )
void Push ( const DataType & data )
DataType Top ()
void Destroy ()
所以在使用这些函数时,直接在创建的结构体变量中调用即可完成。
上面结 构体的定义, C++ 中更喜欢用 class 来代替,也就是struct换成class。

三、类的定义

类的定义如下:
 

class className
{
      // 类体:由成员函数和成员变量组成
};  // 一定要注意后面的分号
class 定义类的 关键字, ClassName 为类的名字, {} 中为类的主体,注意 类定义结束时后面 号不能省略
类体中内容称为 类的成员: 类中的 变量 称为 类的属性 成员变量 ; 类中的 函数 称为 类的方法 或者
成员函数

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

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

在后序工作中一般使用第二种定义方式

在上面演示图片中的代码,细心的同学可能已经注意到了,我们定义人的结构体变量名前面都加上了一个_,其实这是为了防止变量名冲突混淆含义而定义的

举例如下:
 

class Data
{
public:
	//我们看这个函数会感觉很僵硬
	void Init(int year, int month, int day)
	{
		//这里的year、month、day到底是成员变量还是函数形参
		year = year;
		month = month;
		day = day;
	}

private:
	int year;
	int month;
	int day;
};

上面代码无法区分Init函数中谁是形参谁是变量

所以我们在实际中一般这样写:
 

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

private:
	int _year;
	int _month;
	int _day;
};

其他命名方式都可,这主要看公司要求,一般都是加一个前缀加一个后缀标识区分就行。

上面定义结构体中我们使用了public和private,这是类的访问限定符,下面我们对其进行间接。

四、类的访问限定符及封装

1.访问限定符

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

【访问限定符说明】
1. public 修饰的成员在类外可以直接被访问
2. protected private 修饰的成员在类外不能直接被访问 ( 此处 protected private 是类似的 )
3. 访问权限 作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
4. 如果后面没有访问限定符,作用域就到 } 即类结束。
5. class的默认访问权限为privatestructpublic(因为struct要兼容 C)
注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别
我们还拿上面代码举例讲解:
class Data
{
public:
	void Init(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
	}

private:
	int _year;
	int _month;
	int _day;
};

上面代码,类中共有域为public到private的范围,私有域为private到类结束为止

那么我们在主函数中创建类变量即可访问到函数Init,但是访问不到类的成员变量,因为成员变量范围在私有域内,所以只能在类里面才能被访问

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

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Data da1;

	da1.Init(2024, 4, 7);//直接访问
	da1.Init(_day);//直接报错

	return 0;
}

之前看到的一道【面试题】:

问题: C++ struct class 的区别是什么?
解答: C++ 需要兼容 C 语言,所以 C++ struct 可以当成结构体使用。另外 C++ struct 还可以用来
定义类。和 class 定义类是一样的,区别是 struct 定义的类默认访问权限是 public class 定义的类
默认访问权限是 private
注意:在继承和模板参数列表位置, struct class 也有区别,这里对于才学习了本章节知识的同学们不太方便进行说明,之后在我下面的博客会继续进行讲解

2.封装

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来
和对象进行交互。
封装本质上是一种管理,让用户更方便使用类
比如: 对于电脑这样一个复杂的设备,提供给用 户的就只有开关机键、通过键盘输入,显示器, USB 插孔等,让用户和计算机进行交互,完成日 常事务。但实际上电脑真正工作的却是 CPU 、显卡、内存等一些硬件元件。

对于计算机使用者而言,不用关心内部核心部件,比如主板上线路是如何布局的, CPU 内部是如
何设计的等,用户只需要知道,怎么开机、怎么通过键盘和鼠标与计算机进行交互即可。因此
算机厂商在出厂时,在外部套上壳子,将内部实现细节隐藏起来,仅仅对外提供开关机、鼠标以
及键盘插孔等,让用户可以与计算机进行交互即可
C++ 语言中实现封装,可以 通过类将数据以及操作数据的方法进行有机结合,通过访问权限来
隐藏对象内部实现细节,控制哪些方法可以在类外部直接被使用

五、类的作用域

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

比如下面代码:
 

class Person
{
public:
    void PrintPersonInfo();
private:
    char _name[20];
    char _gender[3];
    int  _age;
};

// 这里需要指定PrintPersonInfo是属于Person这个类域
void Person::PrintPersonInfo()
{
    cout << _name << " "<< _gender << " " << _age << endl;
}

六、类的实例化

用类类型创建对象的过程,称为类的实例化
1. 类是对对象进行描述的 ,是一个 模型 一样的东西,限定了类有哪些成员,定义出一个类 并没
有分配实际的内存空间 来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个
类,来描述具体学生信息
2. 一个类可以实例化出多个对象, 实例化出的对象 占用实际的物理空间,存储类成员变量

还拿上面代码举例:
 

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

private:
	int _year;
	int _month;
	int _day;
};

int main()
{
	Data da1;

	da1.Init(2024, 4, 7);//直接访问
	da1.Init(_day);//直接报错

	return 0;
}

类中的成员变量_year,_month,_day都是对其进行的声明,并没有开辟真正的空间,只有当定义出类变量da1时才会真正对类中的成员变量开辟空间,这就是类的实例化。

3. 做个比方。 类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图 ,只设
计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象
才能实际存储数据,占用物理空间

七、类的对象大小的计算

类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算
一个类的大小?
我们举例猜测下面代码的存储方式:
 
class Person
{
public:
   void PrintPersonInfo();
   void SetPersonInfo();

private:
   char _name[20];
   char _gender[3];
   int  _age;
};

1.类对象的存储方式猜测

··· 对象中包含类的各个成员

缺陷:每个对象中成员变量是不同的,但是调用同一份函数,如果按照此种方式存储,当一
个类创建多个对象时, 每个对象中都会保存一份代码,相同代码保存多次,浪费空间。那么
如何解决呢?

··· 代码只保存一份,在对象中保存存放代码的地址

··· 只保存成员变量,成员函数存放在公共的代码段

问题:对于上述三种存储方式,那计算机到底是按照那种方式来存储的?

我们再通过对下面的不同对象分别获取大小来分析看下

class A1 {
public:
    void f1(){}
private:
    int _a;
};

// 类中仅有成员函数
class A2 {
public:
   void f2() {}
};

// 类中什么都没有---空类
class A3
{};

分别计算每个类的大小可以直到

sizeof(A1):4          sizeof(A2) : 1          sizeof(A3) : 1

A1中有一个成员函数和成员变量构成,总大小为4个字节

A2只有一个成员函数组成,总大小为1个字节

A3为空类,里面什么都没定义,总大小为1个字节

空类和只有一个成员函数的类大小相等都为1个字节,说明类的空间大小并没有计算成员函数的大小

那么我们就可以推测出

结论:一个类的大小,实际就是该类中 成员变量 之和,当然要注意内存对齐, 注意空类的大小,空类比较特殊,编译器给了空类一个字节来唯一标识这个类的对象。

2.结构体内存对齐规则

下面我们再回顾学习一下结构体的内存对齐规则

1. 第一个成员在与结构体偏移量为0的地址处。
2. 其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
注意:对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。
VS 中默认的对齐数为 8
3. 结构体总大小为:最大对齐数(所有变量类型最大者与默认对齐参数取最小)的整数倍。
4. 如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。

八、类成员函数的this指针

1.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(2022, 1, 12);
    d1.Print();
    d2.Print();
    return 0;
}
对于上述类,有这样的一个问题:
Date 类中有 Init Print 两个成员函数,函数体中没有关于不同对象的区分,那当 d1 调用 Init
数时,该函数是如何知道应该设置 d1 对象,而不是设置 d2 对象呢?
C++ 中通过引入 this 指针解决该问题,即: C++ 编译器给每个 非静态的成员函数 增加了一个隐藏
的指针参数,让该指针指向当前对象 ( 函数运行时调用该函数的对象 ) ,在函数体中所有 成员变量
的操作,都是通过该指针去访问。只不过所有的操作对用户是透明的,即用户不需要来传递,编
译器自动完成
因为this是编译器自动完成的,不需要用户自己完成,所以 上面代码实际运行实现如下
class Date
{
public:
    void Init(int year, int month, int day)
    {
        _year = year;
        _month = month;
        _day = day;
    }

    //void Print()
    void Print(Data* const this)
    {
        //cout << _year << "-" << _month << "-" << _day << endl;
        cout << this->_year << "-" << this->_month << "-" << this->_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;
}

上面代码中this指针所在位置就是编译器自己进行处理的操作,因为是隐含的this指针,形参和实参的位置不能显示写,编译器会自行处理,但是this指针是可以在类里面显示着进行使用的

我们需要知道的是函数体是进行对象区分是通过this指针自动将成员变量的地址传递了过去,当作函数的形参进行了使用。

2.this指针的特性

1. this 指针的类型:类类型 * const ,即成员函数中,不能给 this 指针赋值。
2. 只能在 成员函数 的内部使用
3. this 指针本质上是 成员函数 的形参 ,当对象调用成员函数时,将对象地址作为实参传递给
this 形参。所以 对象中不存储 this 指针
4. this 指针是 成员函数 第一个隐含的指针形参,一般情况由编译器通过 ecx 寄存器自动传
递,不需要用户传递

3.面试题练习

下面我们来看两道【面试题】

问:this 指针存在哪里?
答:一般情况下this指针作为形参会存放于栈区当中,有时根据编译器的不同会存放在寄存器ecx当中
根据下面代码选择ABC中一个选项:
// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
    void Print()
    {
       cout << "Print()" << endl;
    }
private:
    int _a;
};

int main()
{
    A* p = nullptr;
    p->Print();
    return 0;
}

答案:C、正常运行

题解:定义出的类指针变量赋值为空指针,之后访问Print成员函数,这里我们就要清楚程序是如何进行Print函数的访问的——通过this指针,而我们只是向Print函数传了一个空指针作为形参而已,并且我们并没有对空指针进行访问,所以不会出现报错,所以程序最终进入Print函数打印出了Printf()字符串。

根据下面代码选择ABC中一个选项:

// 1.下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{ 
public:
    void PrintA() 
   {
        cout<<_a<<endl;
   }
private:
 int _a;
};

int main()
{
    A* p = nullptr;
    p->PrintA();
    return 0;
}

答案:B

题解:上面代码中PrintA函数里cout<<_a<<endl;在编译运行时真正的运行的代码为:cout<<this->_a<<endl;而这里的this指针为空指针,对空指针访问成员变量最后程序就会运行崩溃。

九、完结撒❀

如果以上内容对你有帮助不妨点赞支持一下,以后还会分享更多编程知识,我们一起进步。
最后我想讲的是,据说点赞的都能找到漂亮女朋友❤

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

亚马逊云配置深度学习环境

开发环境 对于MacOS来说没无法cuda&#xff0c;所以用的是mps后端计算&#xff0c;所以也无法打印GPU数量和型号。 torch.backends.mps.is_available()如果使用PopOS的话&#xff0c;可以选择自带英伟达驱动的镜像&#xff0c;这样就可以免去复杂的驱动安装流程。 EC2 (自己…

RabbitMQ的交换机与队列

一、流程 首先先介绍一个简单的一个消息推送到接收的流程&#xff0c;提供一个简单的图 黄色的圈圈就是我们的消息推送服务&#xff0c;将消息推送到 中间方框里面也就是 rabbitMq的服务器&#xff0c;然后经过服务器里面的交换机、队列等各种关系&#xff08;后面会详细讲&am…

计算机毕业设计PHP+vue+mysql外卖订餐配送系统

本系统的设计与实现共包含17个表:分别是关于我们信息表&#xff0c;菜品分类信息表&#xff0c;菜品信息信息表&#xff0c;配置文件信息表&#xff0c;订单信息信息表&#xff0c;菜品信息评论表信息 表&#xff0c;留言反馈信息表&#xff0c;美食资讯信息表&#xff0c;配送…

白色磨砂质感html5页源码

白色磨砂质感html5页源码&#xff0c;简约的基础上加上了团队成员&#xff0c;自动打字特效音乐播放器存活时间 源码下载 https://www.qqmu.com/2980.html

牛客NC93 设计LRU缓存结构【hard 链表,Map Java】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/5dfded165916435d9defb053c63f1e84 思路 双向链表map最新的数据放头结点&#xff0c;尾节点放最老的数据&#xff0c;没次移除尾巴节点本地考察链表的新增&#xff0c;删除&#xff0c;移动节点参考答案Java im…

K8s学习四(资源调度_1)

资源调度 发现对Pod操作不方便&#xff0c;不能直接操作&#xff0c;而且不能直接编辑&#xff0c;需要对原来的配置文件进行操作&#xff0c;而且需要删除之后再创建Pod&#xff0c;不方便&#xff0c;更多是通过控制器来操作。 Label和Selector 通过设置标签和选择器来确定…

python 06实验

实验目的 &#xff08;1&#xff09;掌握Python流程控制语句&#xff0c;合理使用循环进行程序设计 &#xff08;2&#xff09;掌握Python数据结构&#xff0c;能熟练运用进行程序设计 &#xff08;3&#xff09;掌握Python的文件读写&#xff0c;能编写读取数据集的程序 1…

java理论小作业(2)--类

第一题 1.题目&#xff1a; 2.解析&#xff1a; 首先&#xff0c;我们来分析Hello1类的结构和给定代码的执行流程&#xff1a; Hello1类中有两个成员变量&#xff0c;一个静态的a和一个非静态的b。静态变量a属于类本身&#xff0c;而非静态变量b属于类的每一个实例&#xff…

c++20协程详解(四)

前言 到这就是协程的最后一节了。希望能帮到大家 代码 到这里我们整合下之前二、三节的代码 #include <coroutine> #include <functional> #include <chrono> #include <iostream> #include <thread> #include <mutex> #include <me…

24上教资面试报名时间汇总⏰报名流程✅

24上教资面试报名公告已经发布&#xff01; &#x1f4a1;报名地址&#xff1a;中小学教师资格考试网 &#x1f550;报名时间&#xff1a;4月12日开始 广东&#xff1a;4月12日10:00-15日17:00 河北&#xff1a;4月12日10:00至4月15日17:00 广西&#xff1a;4月12日10:00至15日…

深入理解Vue 3.0中的watch属性immediate和deep的用法

摘要&#xff1a; 在 Vue 3.0 中&#xff0c;watch 是一个用于观察和响应组件中数据变化的强大工具。它允许我们监听组件中的属性、对象或数组的变化&#xff0c;并执行相应的回调函数。除了基本的用法外&#xff0c;watch 还提供了两个扩展选项&#xff1a;immediate 和 deep…

【JavaScript】原型链/作用域/this指针/闭包

1.原型链 参考资料&#xff1a;Annotated ES5 ECMAScript起初并不支持如C、Smalltalk 或 Java 中“类”的形式创建对象&#xff0c;而是通过字面量表示法或者构造函数创建对象。每个构造函数都是一个具有名为“prototype”的属性的函数&#xff0c;该属性用于实现基于原型的继…

【氮化镓】在轨实验研究辐射对GaN器件的影响

【Pioneering evaluation of GaN transistors in geostationary satellites】 摘要&#xff1a; 这篇论文介绍了一项为期6年的空间实验结果&#xff0c;该实验研究了在地球静止轨道上辐射对氮化镓&#xff08;GaN&#xff09;电子元件的影响。实验使用了四个GaN晶体管&#xf…

H3C防火墙RBM对接交换机M-LAG典型配置

FW配置&#xff1a;FW1与FW2采用RBM组网&#xff0c;M-LAG Border的跨设备二层聚合口与RBM FW设备的设备内三层聚合口对接。FW主设备的设备内三层聚合口编号应与备设备的设备内三层聚合口编号保持一致。防火墙省略安全域和安全策略配置。 Border设备配置&#xff1a;采用M-LAG组…

嵌入式学习49-单片机2

指令周期 1M 机器周期 12M &#xff08;晶体震荡器产生&#xff09; 中断两种方式 …

创建型模式--1.单例模式【巴基速递】

1. 巴基的订单 在海贼世界中&#xff0c;巴基速递是巴基依靠手下强大的越狱犯兵力&#xff0c;组建的集团海贼派遣公司&#xff0c;它的主要业务是向世界有需要的地方输送雇佣兵&#xff08;其实是不干好事儿&#xff09;。 自从从特拉法尔加罗和路飞同盟击败了堂吉诃德家族 &…

怎么把学浪的视频保存到手机

越来越多的人在学浪app里面购买了课程并且想要下载下来&#xff0c;但是苦于没有方法或者工具&#xff0c;所以本文将教大家如何把学浪的视频保存到手机随时随地的观看&#xff0c;再也不用担心课程过期的问题。 本文将介绍工具来下载&#xff0c;因为下载方法太复杂&#xff…

Yolov5改进算法之添加Res2Net模块

目录 1. Res2Net介绍 1.1 Res2Net的背景和动机 1.2 Res2Net的基本概念 2. YOLOV5添加Res2Net模块 Res2Net&#xff08;Residual Resolution Network&#xff09;是一种用于图像处理和计算机视觉任务的深度卷积神经网络架构。它旨在解决传统的ResNet&#xff08;Residual Ne…

【JVM性能调优】- 阿里在线排除工具 - Arthas

阿里在线排除工具 - Arthas Arthas&#xff08;阿尔萨斯&#xff09;是阿里开源的一款Java在线诊断工具&#xff0c;官网原话&#xff1a;当你遇到以下类似问题而束手无策时&#xff0c;Arthas可以帮助你解决&#xff1a; 这个类从哪个 jar 包加载的&#xff1f;为什么会报各种…

千视携 NDI 6 轻量化媒体方案亮相北京CCBN展会

展会简介 第30届中国国际广播电视网络技术展览会&#xff08;CCBN&#xff09;将于4月24至26日在北京首钢会展中心举行。此次展会将汇集全球各大数字媒体、广播电视单位以及IT、通信技术厂商。展会重点关注数字化转型、智能媒体、融媒体等主题&#xff0c;并展示最新的5G、4K/8…