【C++】类和对象详解(类的使用,this指针)

文章目录

  • 前言
  • 面向过程和面向对象的初步认识
  • 类的引入
  • 类的定义
  • 类的访问限定符和封装性
    • 访问限定符
    • 封装性
  • 类的作用域
  • 类的实例化
  • 类对象模型
    • 如何计算类对象的大小
    • 类对象的存储方式猜测
    • 结构体内存对齐规则
  • this指针
    • this指针的引出
    • this指针的特性
  • 总结


前言

提示:这里可以添加本文要记录的大概内容:

在计算机编程领域,程序设计的方法论不断演化,从最初的面向过程到如今更为强大而灵活的面向对象。本文将深入探讨C++中关于类和对象的概念,为读者提供对面向对象编程的深刻理解。

提示:以下是本篇文章正文内容,下面案例可供参考

面向过程和面向对象的初步认识

在计算机编程的世界中,面向过程和面向对象是两种不同的编程范式,它们反映了程序设计的不同思想和方式。以下是对这两种范式的初步认识:

面向过程:

面向过程编程是一种以过程为中心的编程思想。在这种范式中,程序被看作一系列的函数或过程的集合,这些函数按照一定的次序依次执行,完成特定的任务。程序的执行流程主要由函数的调用关系来控制。

主要特点包括:

  • 程序的控制流程是线性的,从上到下逐行执行。
  • 重点在于解决问题的步骤和流程,以完成特定的任务。
  • 数据和函数分离,强调过程的执行。

面向对象:

面向对象编程是一种以对象为中心的编程思想。在这种范式中,程序被组织成一组对象,每个对象包含数据和相关的操作,通过这些对象之间的交互来完成任务。

主要特点包括:

  • 程序的控制流程不再是线性的,而是由对象之间的消息传递和方法调用构成。
  • 重点在于组织和管理对象,强调数据的封装和对象的行为。
  • 对象可以被看作是现实世界中的实体,有着状态和行为。

对比和选择:

面向过程和面向对象各有优缺点,选择合适的范式取决于问题的性质和解决方案的需求。面向过程适用于简单的、线性的问题,而面向对象更适用于复杂的、模块化的系统设计。

在实际开发中,很多编程语言提供了同时支持面向过程和面向对象的特性,如C++、Java等,使得程序员可以根据具体情况选择合适的编程方式。这也说明了在面向对象编程的潮流中,面向过程并没有被淘汰,而是与面向对象共同存在,相互补充,为编程提供了更灵活的选择。

类的引入

在c语言中,结构体内只能定义变量,在c++中,结构体内不仅可以定义变量,还可以定义函数

#include <iostream>
#include <cstring>  // 添加头文件以使用字符串库函数
using namespace std;struct stu
{void getName(){cout << name << endl;}int age;int num;char name[20];
};int main()
{struct stu s1;strcpy(s1.name, "dzj");  // 使用strcpy将字符串赋值给字符数组s1.getName();return 0;
}

但是在C++中,上述结构体的定义,更喜欢用class来代替

注意:C语言结构体中不能定义成员函数,C++兼容C的语法,并进行拓展,可以定义成员函数

类的定义

类名:由成员函数和成员变量组成,同时注意分号

class className
{//类名:由成员函数和成员变量组成
}

class是定义类的关键字,className是类的名称,{}中类的主体同时注意类定义结束时后面的分号。类中的元素是类的成员:类中的数据称为类的属性或者成员变量;类中的函数称为类的方法或者成员函数
类的两种定义方式:

  • 声明和定义全部放在类体中,需要注意:成员函数如果在类中定义,编译器可能会将其当成内联函数处理。
class person
{
public:void print(){cout << _age << _name << _weight << endl;}
private:int _age;char _name[10];int _weight;
};
  • 声明放在.h中,类的定义放在.cpp中

在这里插入图片描述
一般情况下,一般采用第二种定义和声明分离的方式,但是为了方便,在平时的练习时,可以采用第一种方式(声明和定义全部放在类体中)

补充:声明和定义的区别是什么?
声明是一种承诺,承诺要干什么,但是还没做,定义就是把这个事情执行了或者落实了

类的访问限定符和封装性

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

访问限定符

  1. public(公有)
  2. protected(保护)
  3. private(私有)

【访问限定符说明】

  • public修饰的成员在类外可以直接被访问
  • protected修饰的成员类的内部和派生类的成员可以访问,但在类的外部无法直接访问.
  • private修饰的成员只能在本类中访问,在类外不能直接访问
  • 访问权限的作用域从该访问限定符出现的位置直到下一个访问限定符出现为止
  • class的默认访问权限是private,但是struct是public(因为struct要兼容c语言)

注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

C++中struct和class的区别是什么?
C++需要兼容C语言,所以C++中struct可以当成结构体去使用。另外C++中struct还可以用来定义类。
和class是定义类是一样的,区别是struct的成员默认访问方式是public,class的成员默认访问方式是private。

封装性

面向对象的三大特性:封装、继承、多态。
在类和对象阶段,我们只研究类的封装特性,那什么是封装呢?
封装是面向对象编程(OOP)中的一个重要概念,它指的是将数据(变量)和操作数据的方法(函数)捆绑在一起的一种机制。封装有助于隐藏对象的内部实现细节,同时提供一组公共接口供外部使用。这样,对象的内部状态和行为对外部来说是不可见的,只有通过公共接口才能与对象进行交互。

封装的主要目的有以下几点:

  1. 数据隐藏: 将对象的实现细节隐藏起来,防止外部直接访问对象的内部数据,从而提高数据的安全性。

  2. 实现细节隔离: 允许对象实现者修改对象的内部实现细节而不影响外部使用者的代码。外部代码只需要关心对象的接口,而不必关心其具体实现。

  3. 代码组织: 将数据和操作数据的方法封装在一个单元中,使得代码更加模块化、可维护性更强。

在面向对象的语言中,封装通过类来实现。类封装了数据成员和成员函数,成员函数提供了访问和操作数据的接口。访问控制修饰符(如public、private、protected)用于控制成员的可见性和访问权限,实现封装的关键。

示例:

#include <iostream>class Car {
private:// 私有数据成员int speed;public:// 公有成员函数void setSpeed(int s) {if (s >= 0) {speed = s;}}int getSpeed() const {return speed;}
};int main() {Car myCar;// 使用公有接口设置速度myCar.setSpeed(60);// 使用公有接口获取速度std::cout << "Current Speed: " << myCar.getSpeed() << " km/h" << std::endl;return 0;
}

在这个例子中,Car 类封装了一个私有的速度成员,并提供了公有的 setSpeedgetSpeed 方法来设置和获取速度。外部代码通过这些公有接口与 Car 对象进行交互,而不需要了解具体的实现细节。这就体现了封装的思想。

类的作用域

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

class person
{
public:void print();
private:int _age;char _name[10];int _weight;
};
void person::print()
{cout << _age << _name<<_weight << endl;
}

类的实例化

类的实例化指的是创建类的对象。在面向对象编程中,类定义了一种数据类型,而实例化则是根据这个数据类型创建具体的对象。对象是类的一个实例,具有类定义的属性和行为。

下面是一个简单的C++示例,演示了如何定义一个类并实例化对象:

#include <iostream>
#include <string>// 定义一个简单的Person类
class Person {
public:// 公有成员函数,用于设置和获取姓名void setName(const std::string& n) {name = n;}std::string getName() const {return name;}private:// 私有数据成员,姓名std::string name;
};int main() {// 实例化Person类的对象Person person1;// 使用公有接口设置姓名person1.setName("Alice");// 使用公有接口获取姓名std::cout << "Person's Name: " << person1.getName() << std::endl;// 实例化另一个Person类的对象Person person2;// 使用公有接口设置姓名person2.setName("Bob");// 使用公有接口获取姓名std::cout << "Person's Name: " << person2.getName() << std::endl;return 0;
}

在这个例子中,Person 类定义了一个私有数据成员 name 和公有的成员函数 setNamegetName。通过实例化两个 Person 对象 person1person2,分别设置和获取了它们的姓名。

实例化是面向对象编程中的重要概念,它允许我们根据类的定义创建多个对象,每个对象都拥有自己的状态和行为。

类对象模型

如何计算类对象的大小

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

问题:类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算一个类的大小?

答:对象中只存储成员变量,不存储成员函数

类对象的存储方式猜测

  • 对象中包含类中的各个成员(成员函数和成员变量)
    事实上,这样是不合理的,每个对象中成员变量是不同的,但是调用的却是同一个函数,如果按照这种方式存储,当一个类创建多个对象的时候,每个对象中都会保存一份代码,相同的代码保存了多次,浪费空间。
  • 只保存成员变量,成员函数保存在公共的代码段
    图解:
    在这里插入图片描述
    显然计算机采用的是第二种存储方式(类中对象仅仅存储成员变量)

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

结构体内存对齐规则

关于内存对齐可以看这篇博客

this指针

this指针的引出

#include <iostream>
using namespace std;
class Date
{
public:void setDate(int year,int month,int day){_year = year;_month = month;_day = day;}void getInfo(){cout << _year << endl;cout << _month << endl;cout << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;Date d2;d1.setDate(2024, 1, 6);d1.getInfo();return 0;
}

问题:在上述代码中,有两个成员函数setDate和getInfo,函数体中没有关于类的划分,那么程序是怎么知道d1.setDate(2024, 1, 6)设置的就是d1的空间,而不是d2的空间

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

图解
在这里插入图片描述
这里编译器偷偷帮我们做了处理,但是我们自己并不知道,即在成员函数第一个参数添加 类名*this,并在函数调用的时候传递了对象的地址。

#include <iostream>
using namespace std;
class Date
{
public:void setDate(int year,int month,int day)//隐含的this指针Date* this{this->_year = year;this->_month = month;this->_day = day;}void getInfo(){cout << _year << endl;cout << _month << endl;cout << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;Date d2;d1.setDate(2024, 1, 6);//隐含的传递对象地址 d1.setDate(&d1,2024, 1, 6)d1.getInfo();return 0;
}

this指针的特性

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

this指针存储在哪里?

上面说到this指针本质是成员函数的第一个形参,那么肯定存放在进程地址空间中的栈区,但是在vs2022下是存放在ecx寄存器中,不同编译器和环境下可能会有差异

this指针可以为空吗?

通过一段代码来说明

#include <iostream>
using namespace std;
class A
{
public:void PrintA(){cout << _a << endl;}void Show(){cout << "Show()" << endl;}
private:int _a;
};
int main()
{A* p = nullptr;//p->PrintA();p->Show();
}

上面代码中,p->PrintA()会发生程序崩溃,但是p->Show()可以正常运行。因为在PrintA()中发生了隐含的this指针的解引用操作(对空指针的解引用),但是在Show()并没有解引用所以程序没问题

总结

通过本文的学习,我们深入了解了C++中类和对象的方方面面,从面向过程的初步认识到类的引入和定义,再到类的作用域、实例化、访问限定符及封装,以及类对象大小的计算和类成员函数的this指针。这些概念和技术不仅为我们提供了更灵活的程序设计手段,也为构建更为可维护和可扩展的软件系统奠定了基础。在今后的编程学习和实践中,希望读者能够充分运用这些知识,编写出更高效、健壮的C++程序。面向对象编程不仅仅是一种技术,更是一种思想,期待读者通过不断实践,能够更深刻地理解和运用面向对象的优秀编程范式。

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

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

相关文章

计算机毕业设计选题分享-SSM律师事务所业务管理系统01664(赠送源码数据库)JAVA、PHP,node.js,C++、python,大屏数据可视化等

SSM律师事务所业务管理系统 摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技手段来提高自身的优势&#xff0c;律师事务所业务管理系统当然也不能排除在外。律师事务所业务管理系统是以实际运用为开发背景…

静态网页设计——电影推荐网(HTML+CSS+JavaScript)

前言 声明&#xff1a;该文章只是做技术分享&#xff0c;若侵权请联系我删除。&#xff01;&#xff01; 感谢大佬的视频&#xff1a; https://www.bilibili.com/video/BV1NK411x7oK/?vd_source5f425e0074a7f92921f53ab87712357b 使用技术&#xff1a;HTMLCSSJS&#xff08;…

【亚马逊云科技】使用Helm 3为Amazon EKS部署Prometheus+Grafana监控平台

文章目录 1. 创建Kubernetes命名空间2. 添加Prometheus社区helm chart3. 安装prometheus4. 检查Prometheus Pod运行状况5. 检查Prometheus Service部署情况6. 修改服务访问端口类型7. 访问Prometheus数据收集情况8. 访问Grafana9. 设置数据源10. 查看Kubernetes各类性能可视化参…

c/c++运算符优先级【一文搞懂】【大白讲解】

C运算符优先级教程 我们知道&#xff0c;在数学运算中&#xff0c;有 “先乘除后加减” 的运算规则&#xff0c;在我们程序语言中一样有运算符的优先级问题&#xff0c;来决定我们运算的顺序问题&#xff0c;这就是运算符的优先级。 即所谓运算符的优先级&#xff0c;指的是在…

【linux笔记】top、ps

【linux笔记】top命令 top&#xff08;Table of process&#xff09;是动态变化的。而ps是静态的。 PID — 进程id USER — 进程所有者 PR — 进程优先级 NI — nice值。负值表示高优先级&#xff0c;正值表示低优先级 VIRT — 进程使用的虚拟内存总量&#xff0c;单位kb。VI…

C语言实例_string.h库函数功能及其用法详解

一、前言 在计算机编程中&#xff0c;字符串处理是一项常见而重要的任务。C语言的string.h头文件提供了一系列函数和工具&#xff0c;用于对字符串进行操作和处理。这些函数包括字符串复制、连接、比较、查找等功能&#xff0c;为开发人员提供了强大的字符串处理能力。本文将对…

计算机中的数据运算

放上计算机中的数据的表示方法 计算机中的数据表示方法-CSDN博客 补码的运算&#xff1a; 连同符号位一起相加&#xff0c;符号位产生的进位自然丢掉&#xff0c;这里要特别注意机器数的位数&#xff0c;计算数的位数决定了可以存放的数据的大小&#xff0c;加减产生的数据的…

ATTCK视角下的信息收集:主机发现

目录 1、利用协议主动探测主机存活 利用ICMP发现主机 利用ARP发现主机 利用NetBIOS协议发现主机 利用TCP/UDP发现主机 利用DNS协议发现主机 利用PRC协议发现主机程序 2、被动主机存活检测 利用Browser主机探测存活主机 利用ip段探测主机存活 利用net命令探测主机存活…

【软件测试】学习笔记-测试覆盖率

测试覆盖率通常被用来衡量测试的充分性和完整性&#xff0c;从广义的角度来讲&#xff0c;测试覆盖率主要分为两大类&#xff0c;一类是面向项目的需求覆盖率&#xff0c;另一类是更偏向技术的代码覆盖率。 需求覆盖率 需求覆盖率是指测试对需求的覆盖程度&#xff0c;通常的做…

UAV | 多算法在多场景下的无人机路径规划(Matlab)

近年来&#xff0c;无人机(unmanned aerial vehicle&#xff0c;UAV)由于其灵活度高、机动性强、安全风险系数小、成本低等特点&#xff0c;被广泛应用于搜索巡逻、侦察监视、抢险救灾、物流配送、电力巡检、农业灌溉等军用或民用任务。路径规划是无人机执行任务的关键&#xf…

第34期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大型语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以…

数据结构之绪论

一个著名公式&#xff1a; 程序数据结构算法 非数值计算&#xff1a;无法用数学的公式或方程来描述 描述非数值计算问题的数据模型不是数学方程&#xff0c;而是诸如表&#xff0c;树和图之类的具有逻辑关系的数据 数据结构&#xff1a;是一门研究非数值计算的程序设计中计算机…

pyqt6 + pycharm 搭建+使用入门

首先安装PyQt6和PyQt6-tools。使用如下命令&#xff1a; pip install PyQt6 PyQt6-tools 但是运行后会报如下错误&#xff1a; 这个时候按照提示执行命令升级pip即可 python.exe -m pip install --upgrade pip 配置pycharm&#xff1a; 打开pycharm&#xff0c;进入setting&am…

大事务提交优化

经常性的报死锁异常&#xff0c;经常性的主从延迟......通过报错信息按图索骥&#xff0c;发现代码是这样的。 这是一段商品发布的逻辑&#xff0c;我们可以看到参数校验、查询、最终的insert以及update全部揉在一个事务中。遇到批量发布商品的时候就经常出现问题了&#xff0c…

css实现一个斑马条纹动画,实现一个理发店门口的小转转,进度条动画同理!

css实现一个斑马条纹动画&#xff0c;实现一个理发店门口的小转转 前置基础知识 css背景background的重复渐变属性repeating-linear-gradient() 该属性类似于linear-gradient(),但他会在整个方向上重复渐变以覆盖整个容器 一、先写一个普通渐变例子linear-gradient() &…

【JAVA】volatile 关键字的作用

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a; JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 volatile 的作用&#xff1a; 结语 我的其他博客 前言 在多线程编程中&#xff0c;保障数据的一致性和线程之间的可见性是…

复旦MBA科创青干营(二期):探索合肥科创企业的创新之路

11月18日-19日&#xff0c;复旦MBA科创青干营二期学生开启了整合实践活动的第三次企业参访&#xff0c;前往位于合肥的蔚来第二先进制造基地、安徽万邦医药科技股份有限公司和合肥国轩高科动力能源有限公司&#xff0c;在学术导师和科创企业家“双导师”的指导下&#xff0c;深…

【C++】STL 算法 ④ ( 函数对象与谓词 | 一元函数对象 | “ 谓词 “ 概念 | 一元谓词 | find_if 查找算法 | 一元谓词示例 )

文章目录 一、函数对象与谓词1、一元函数对象2、" 谓词 " 概念3、find_if 查找算法 二、一元谓词示例1、代码示例 - 一元谓词示例2、执行结果 一、函数对象与谓词 1、一元函数对象 " 函数对象 " 是通过 重载 函数调用操作符 () 实现的 operator() , 函数对…

【数值分析】非线性方程求根,牛顿法,牛顿下山法,matlab实现

4. 牛顿法 收敛时牛顿法的收敛速度是二阶的&#xff0c;不低于二阶。如果函数有重根&#xff0c;牛顿法一般不是二阶收敛的。 x k 1 x k − f ( x k ) f ′ ( x k ) x_{k1}x_k- \frac{f(x_k)}{f(x_k)} xk1​xk​−f′(xk​)f(xk​)​ matlab实现 %% 牛顿迭代例子 f (x) x…

创建Qt项目

项目工程名称一般不要有特殊符号&#xff0c;不要有中文 项目工程保存路径可修改的&#xff0c;但路径不要带中文 构建系统&#xff0c;有3种&#xff0c;这里使用qmake qmake和cmake区别 构建过程不同&#xff0c;项目管理不同。 1、构建过程&#xff0c;qmake是Qt框架自带的…