C++初阶篇----类与对象上卷

2024-03-02 13:36
文章标签 c++ 对象 初阶 上卷

本文主要是介绍C++初阶篇----类与对象上卷,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 引言
  • 1.面向过程和面向对象初步认识
  • 2.类的引入
  • 3.类的定义
    • 3.1声明与定义全部放在类体中
    • 3.2声明与定义分离
  • 4.类的访问限定符及封装
    • 4.1访问限定符
    • 4.2封装
  • 5.类的作用域
  • 6.类的实例化
    • 类是对对象进行描述
    • 一个类(一个类型变量)可以实例化出多个对象
  • 7.类对象模型
    • 7.1类对象的大小
    • 7.2类对象的存储方式
    • 7.3结构体内存对齐规则
  • 8.`this` 指针
    • 8.1 this指针的引出
    • 8.2 this指针的特性
  • 总结:

引言

在面向对象编程(OOP)中,类(Class)和**对象(Object)**是两个核心概念。
简单来说,**类定义了对象的模板,而对象是根据类创建的具体实体**。例如,假设有一个类叫做Car,描述了汽车的属性(如颜色、品牌、型号)和行为(如加速、减速、转向)。那么根据这个类,我们可以创建多个具体的汽车对象,每个对象都有自己的属性和行为,但都基于相同的类模板。

在面向对象编程中,程序主要由对象组成,每个对象都是一个实例,具有特定的属性(成员变量)和行为(成员函数)。类则用来定义对象的模板,描述了一类对象共同的属性和行为。

1.面向过程和面向对象初步认识

面向对象编程(OOP)是一种以对象为中心的编程范式,它将数据和操作数据的方法封装在对象中,使得对象可以通过方法与其他对象进行交互。在面向对象编程中,程序的设计和实现是围绕着对象的概念展开的,强调对象之间的交互和继承关系,以及多态性的特性。

面向过程编程(POP)是一种以过程为中心的编程范式,它将问题分解为一系列的步骤或过程,然后按照顺序执行这些步骤来解决问题。在面向过程编程中,数据和操作数据的方法是分开的,程序的设计和实现是围绕着函数或过程的概念展开的,强调按照步骤执行任务。

C语言是面向过程的,关注的是过程,分析求解问题
而C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成

2.类的引入

相较于C语言,结构体中只能定义变量,而在C++中,结构体内不仅可以定义变量,还可以定义函数并在内部嵌套调用
如,C语言栈的实现

#include<iostream>using namespace std;
typedef int DataType;
struct Stack
{//初始化函数void Init(size_t capacity=5){_array = (int*)malloc(sizeof(int) * capacity);_capacity = capacity;_size = 0;}void Push(const DataType& data){_array[_size] = data;_size++;}DataType Top(){return _array[_size - 1];}void Destory(){if (_array){free(_array);_array = nullptr;_capacity = 0;_size = 0;}}//成员变量DataType* _array;size_t _capacity;size_t _size;
};int main()
{Stack s;s.Init();s.Push(1);s.Push(3);s.Push(2);cout << s.Top() << endl;s.Destory();return 0;
}

在这里插入图片描述
而在C++中,结构体的定义,更习惯用 class 关键字来替代

3.类的定义

class name
{//成员函数//成员变量};

class 为定义类的关键字,name为类的名字
类的定义方式有俩种

3.1声明与定义全部放在类体中

若成员函数在类中定义,那么编译器可能会当作 内联函数来处理
在这里插入图片描述

3.2声明与定义分离

类声明放
在这里插入图片描述

4.类的访问限定符及封装

4.1访问限定符

C++实现封装的方式:类与对象的属性与方法结合在一起,设置访问权限的选择性将其接口提供外部使用
在这里插入图片描述

  1. public修饰的成员在类外可以直接被访问
  2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)
  3. 访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止
  4. 如果后面没有访问限定符,作用域就到 } 即类结束。
  5. class的默认访问权限为private,struct为public(因为struct要兼容C)

4.2封装

在面向对象的三大特性中(封装、继承、多态),主要研究类的封装特性,在类和对象阶段
封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来
和对象进行交互。
封装本质上是一种管理,让用户更方便使用类。

5.类的作用域

在C中,结构体的定义等价于一个变量的定义,而在C++中类的定义形成了一个新的作用域

C中有全局和局部,static静态
而C++中则形成了一个新的作用域,就好比之前,一块土地有公工区域(公共管理),和非公共区域(无人管理),然后类的定义,开始出现,私人住宅(别人允许你访问,那么便可以做客参观)

在类体外定义成员时,需要标识符 ::作用域操作符指明

void name::fun() 
{//…………
}

6.类的实例化

用类类型创建对象的过程,称为类的实例化

类是对对象进行描述

定义一个类,并没有分配实际的内存空间来存储它

注:类当中的成员函数也没有空间? 类成员函数在定义后,就有了固定的存放位置,当创建类的实例化,并不会重复开辟成员函数的空间

一个类(一个类型变量)可以实例化出多个对象

多个类,分别占用实际的物理空间,储存类成员变量
类比,实例化出对象就像在现实中使用建筑设计图建造出房子,类就是设计图,房子就是实例化
在这里插入图片描述

7.类对象模型

7.1类对象的大小

类对象的大小取决于其成员变量成员函数

1.成员变量的大小:类中的每个成员变量都占用内存空间。基本数据类型(如int、float等)通常占用固定大小的内存空间,而对象、指针或其他用户自定义类型的大小取决于其内部包含的成员变量。
2.对齐规则:在内存中,数据通常按照特定的对齐规则存储,以提高访问速度。对齐规则可以导致成员变量之间存在一些额外的空隙,以保证每个成员变量从正确的内存地址开始。对齐规则通常由编译器和目标平台决定。
3.继承和虚函数:如果类继承自其他类,或者包含虚函数,那么额外的内存空间可能会用于存储指向虚函数表的指针(对于包含虚函数的类)或基类的成员变量(对于派生类)。

如:

//前面所创建的Stack的类与Stack1比较
class Stack1
{int x;int y;int z;
};int main()
{cout << sizeof(Stack) << endl<<sizeof(Stack1)<<endl;
}

在这里插入图片描述

7.2类对象的存储方式

类对象包含类的各个成员
在这里插入图片描述
每个对象中成员变量是不同的,但是调用同一份函数,如果按照此种方式存储,当一个类创建多个对象时,每个对象中都会保存一份代码,相同代码保存多次,浪费空间。

代码只保存一份,在对象中保存成员函数的地址
只保存成员变量,成员函数存放在公共的代码段

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

7.3结构体内存对齐规则

对齐规则和C语言中的结构体对齐规则是一样

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

8.this 指针

8.1 this指针的引出

问题:当俩个同类型的类实例化,调用同一个成员函数,编译器是怎么分辨出,是哪一个面向对象调用函数?

如:

//引用之前所定义的Stack 的类
int main()
{Stack d1;Stack d2;d1.Init();d2.Init();//~~~~return 0;
}
这里调用Init初始化,怎么分辨出是d1,还是d2调用?
这就是this指针的作用了> 在C++中,this指针是一个特殊的指针,它指向当前对象的地址。它是每个非静态成员函数的隐式参数。当你在一个**成员函数内部引用类的成员变量或者调用其他成员函数**时,编译器会自动地插入this指针。

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

8.2 this指针的特性

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

在这里插入图片描述

总结:

C++中通过类可以将数据 以及 操作数据的方法进行完美结合,通过访问权限可以控制那些方法在类外可以被调用,即封装,在使用时就像使用自己的成员一样,更符合人类对一件事物的认知。

这篇关于C++初阶篇----类与对象上卷的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/766298

相关文章

C++ move 的作用详解及陷阱最佳实践

《C++move的作用详解及陷阱最佳实践》文章详细介绍了C++中的`std::move`函数的作用,包括为什么需要它、它的本质、典型使用场景、以及一些常见陷阱和最佳实践,感兴趣的朋友跟随小编一起看... 目录C++ move 的作用详解一、一句话总结二、为什么需要 move?C++98/03 的痛点⚡C++

详解C++ 存储二进制数据容器的几种方法

《详解C++存储二进制数据容器的几种方法》本文主要介绍了详解C++存储二进制数据容器,包括std::vector、std::array、std::string、std::bitset和std::ve... 目录1.std::vector<uint8_t>(最常用)特点:适用场景:示例:2.std::arra

C++构造函数中explicit详解

《C++构造函数中explicit详解》explicit关键字用于修饰单参数构造函数或可以看作单参数的构造函数,阻止编译器进行隐式类型转换或拷贝初始化,本文就来介绍explicit的使用,感兴趣的可以... 目录1. 什么是explicit2. 隐式转换的问题3.explicit的使用示例基本用法多参数构造

C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解

《C++,C#,Rust,Go,Java,Python,JavaScript的性能对比全面讲解》:本文主要介绍C++,C#,Rust,Go,Java,Python,JavaScript性能对比全面... 目录编程语言性能对比、核心优势与最佳使用场景性能对比表格C++C#RustGoJavapythonjav

C++打印 vector的几种方法小结

《C++打印vector的几种方法小结》本文介绍了C++中遍历vector的几种方法,包括使用迭代器、auto关键字、typedef、计数器以及C++11引入的范围基础循环,具有一定的参考价值,感兴... 目录1. 使用迭代器2. 使用 auto (C++11) / typedef / type alias

C++ scoped_ptr 和 unique_ptr对比分析

《C++scoped_ptr和unique_ptr对比分析》本文介绍了C++中的`scoped_ptr`和`unique_ptr`,详细比较了它们的特性、使用场景以及现代C++推荐的使用`uni... 目录1. scoped_ptr基本特性主要特点2. unique_ptr基本用法3. 主要区别对比4. u

C++11中的包装器实战案例

《C++11中的包装器实战案例》本文给大家介绍C++11中的包装器实战案例,本文结合实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录引言1.std::function1.1.什么是std::function1.2.核心用法1.2.1.包装普通函数1.2.

C++多线程开发环境配置方法

《C++多线程开发环境配置方法》文章详细介绍了如何在Windows上安装MinGW-w64和VSCode,并配置环境变量和编译任务,使用VSCode创建一个C++多线程测试项目,并通过配置tasks.... 目录下载安装 MinGW-w64下载安装VS code创建测试项目配置编译任务创建 tasks.js

C++ 多态性实战之何时使用 virtual 和 override的问题解析

《C++多态性实战之何时使用virtual和override的问题解析》在面向对象编程中,多态是一个核心概念,很多开发者在遇到override编译错误时,不清楚是否需要将基类函数声明为virt... 目录C++ 多态性实战:何时使用 virtual 和 override?引言问题场景判断是否需要多态的三个关

C++简单日志系统实现代码示例

《C++简单日志系统实现代码示例》日志系统是成熟软件中的一个重要组成部分,其记录软件的使用和运行行为,方便事后进行故障分析、数据统计等,:本文主要介绍C++简单日志系统实现的相关资料,文中通过代码... 目录前言Util.hppLevel.hppLogMsg.hppFormat.hppSink.hppBuf