C++类与对象(上)

目录

    • 类的定义
    • 类的访问限定符
    • 类的实例化
    • 类对象大小和储存方式
    • this指针

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。
C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完
成。

C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。
C++兼容c语言,结构用法可以继续使用
同时struct也升级成了类,struct中可以定义函数了

类的定义

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

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

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

class Stack
{
public:// 成员函数void Init(){a = nullptr;top = capacity = 0;}void Push(int x){if (top == capacity){size_t newcapacity = capacity == 0 ? 4 : capacity * 2;a = (int*)realloc(a, sizeof(int) * newcapacity);capacity = newcapacity;}a[top++] = x;}int Top(){return a[top - 1];}private:// 成员变量int* a;int top;int capacity;
};

类的声明和定义可以分开

Func.h中
class Stack
{
public:// void Init();void Push(int x);int Top();private:// int* a;int top;int capacity;
};

在以前学习时说编译器只会向上查找,那么Init在用a的时候向上是找不到a的,因为类不是只会向上找,是在类域里面找

Func.cpp中
//得有作用域运算符::来告诉编译器Init是栈的成员函数
//编译器默认只在当前域、全局域找,不会到空间域、类域里去找
类定义了一个新的作用域,类的所有成员都在类的作用域中。
在类体外定义成员时,需要使用 :: 作用域操作符指明成员属于哪个类域。
void Stack::Init()
{a = nullptr;top = capacity = 0;
}void Stack::Push(int x)
{if (top == capacity){size_t newcapacity = capacity == 0 ? 4 : capacity * 2;a = (int*)realloc(a, sizeof(int) * newcapacity);capacity = newcapacity;}a[top++] = x;
}int Stack::Top()
{return a[top - 1];
}

成员变量命名风格的建议:

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

域搜索:

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

两个year,一个是局部域的year,一个是类域的year,局部优先,先在局部搜索,所以就是自己赋值给自己了,所以成员变量可以加个_方便区分,前加后加都可以,前面加m的也有,member表示成员。

类的访问限定符

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

别人如果随便的就能访问成员变量,那么可能会出错,比如下面错误的代码,应该是要top-1的地方
C++封装体现在想给访问就公有,不想给访问的就放成私有,杜绝随意访问数据出错的可能性。

cout << st.a[st.top] << endl;

让使用者不接触成员变量,用成员函数去实现对应功能

cout << st.Top() << endl;

在这里插入图片描述

【访问限定符说明】

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

类里面不受访问限定符的限制,平时用class更好一些,因为这样就必须给访问限定符

类的实例化

class Date
{
public:void Init(int year, int month, int day){_year = year;_month = month;_day = day;}
//private:int _year;   // 声明int _month;int _day;
};int main()
{Date._year;return 0;
}

类里面这些看似是定义,其实只是声明,Date._year;报错,外面访问不了成员是因为没有空间,变量定义特点是开空间。Date d;这样才是定义,对象的定义也叫对象的实例化,就会开空间,那么成员变量也开空间了

类在内存中不占空间,可以认为它存在文件系统

用类类型创建对象的过程,称为类的实例化
类是对对象进行描述的
类的本质像设计图,类实例化出对象就像用设计图建造出房子
类不存数据,类实例化的对象才能存数据

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;d1.Init(2023, 7, 19);d1.Print();d1._year;Date d2;d2.Init(2023, 7, 19);d2.Print();d2._year;cout << sizeof(Date) << endl;cout << sizeof(d1) << endl;return 0;
}

类对象大小和储存方式

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

只保存成员变量,成员函数存放在公共的代码段
不是到对象里找函数,是到公共代码区找

class A1 {
public:void f1() {}
private:char _ch;int _a;
};// 类中仅有成员函数
class A2 {
public:void f2() {}
};// 类中什么都没有---空类
class A3
{};int main()
{cout << sizeof(A1) << endl;// 分配1byte,不存储数据,只是占位,表示对象存在过cout << sizeof(A2) << endl;cout << sizeof(A3) << endl;A2 aa2;A2 aaa2;cout << &aa2 << endl;cout << &aaa2 << endl;return 0;
}

sizeof(A1) = 8
sizeof(A2) = 1
sizeof(A3) = 1

对于空类或仅有成员函数分配1字节是为了能区分开不同对象的区别,如果不分配空间那取地址该怎么办?零字节怎么表示这个对象存在?可以开多个字节但是没必要,只是为了表示对象存在从最小单位去考虑,那么一个字节就可以了
那一个字节存什么不重要,因为空类我们也很难去访问

结构体内存对齐规则

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

this指针

Date类中有 Init 成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?
在这里插入图片描述

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

绿色的字体就是编译器增加的指针参数,准确来说是Date* const this,从this不能++可以看出
在这里插入图片描述

Init里面有this,print里面也有一个this指针,那他们会不会混?他们俩是不一样的,可以从&year打印结果看出来,不同域中可以定义同名变量,两个year不一样,是两个不同的形参。

Date d1;d1.Init(2023, 7, 20);d1.Print(2023);

在这里插入图片描述

class Date
{
public:// this在实参和形参位置不能显示写// 但是在类里面可以显示的用void Init(int year, int month, int day){cout << this << endl;//this->_year = year;//this->_month = month;//this->_day = day;_year = year;_month = month;_day = day;}void Print(){cout << this << endl;cout << _year << "/" << _month << "/" << _day << endl;}private:int _year;   // 声明int _month;int _day;
};int main()
{Date d1;d1.Init(2023, 7, 20);d1.Print();Date d2;d2.Init(2023, 7, 21);d2.Print();return 0;
}

在这里插入图片描述

this指针的特性

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

this指针可以为空吗?

下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行


class A
{
public:void Print(){//cout << _a << endl;cout << "Print()" << endl;}
private:int _a;
};int main()
{A* p = nullptr;p->Print();//p->_a;return 0;
}

正常运行

p->不代表就是解引用因为函数没有存在对象中。
成员函数不需要在p指针指向的对象里去找,是在公共代码区找,编译器会把p传给this指针,vs下是通过寄存器传递,不是push压栈进去(挺多传参是压栈进去的),因为认为this指针会被经常访问。虽然在函数中有this这个空指针,但是没有解引用

在这里插入图片描述

在vs下p->_a;这样写没有报错是因为编译器进行了优化,编译器认为p指向了a但是也没有进行赋值等操作,就没有生成指令,在一些老的编译器上面可能就出错了。p->_a=1;进行解引用就空指针报错了

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

在这里插入图片描述

这样依旧能正常运行,因为函数没有存在对象中。看起来解引用了,其实没有解引用,编译器会转换为汇编指令,传递this指针

在这里插入图片描述

this指针存在哪里?

在这里插入图片描述

C语言和C++实现Stack的对比

在这里插入图片描述

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

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

相关文章

WSL2安装CentOS7和CentOS8

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、下载ZIP包&#xff1f;二、安装1.打开Windows子系统支持2.安装到指定位置3.管理虚拟机4.配置虚拟机1.配置国内源2.安装软件3.安装第三方源 5.配置用户1.创建…

【ASP.NET MVC】数据到客户端(7)

前文ViewBag数据在服务端动态生成页面&#xff0c;也可以传到客户端浏览器供JS使用。 一、数据从控制器到客户端 前文介绍&#xff0c;动态生成页面时&#xff0c;控制器的数据 并没有传递到 客户端&#xff0c;而是给自己来用&#xff0c;生成View 再利用http传递到客户端浏…

神经概率语言模型

本文主要参考《A Neural Probabilistic Language Model》这是一篇很重要的语言模型论文,发表于2003年。主要贡献如下: 提出了一种基于神经网络的语言模型&#xff0c;是较早将神经网络应用于语言模型领域的工作之一&#xff0c;具有里程碑意义。采用神经网络模型预测下一个单词…

Linux环境下VS code的python与C++调试环境的安装

Linux环境下VS code的python与C调试环境的安装 文章目录 Linux环境下VS code的python与C调试环境的安装前言一、云服务器的环境二、VS code相关信息三、python 开发环境配置四、C开发环境配置1.测试main.cpp2.进行debug3.进行debug程序4.运行main.cpp程序步骤 前言 最近写的 C&…

Meta AI研究团队新AI模型: Llama 2 大语言模型

Llama是Facebook Research团队开发的基础语言模型集&#xff0c;旨在提供广泛的语言理解能力。它基于转换器架构&#xff0c;参数范围从7B到65B。通过使用Llama模型&#xff0c;研究人员和开发人员可以构建更先进的自然语言处理系统。您可以在GitHub上找到相关的代码和资源&…

【BASH】回顾与知识点梳理(二)

【BASH】回顾与知识点梳理 二 二. Shell 的变量功能2.1 什么是变量&#xff1f;2.2 变量的取用与设定: echo, 变量设定规则: set/unset2.3 环境变量的功能用 set 观察所有变量 (含环境变量与自定义变量)export&#xff1a; 自定义变量转成环境变量那如何将环境变量转成自定义变…

【Spring Cloud 五】OpenFeign负载均衡

这里写目录标题 系列文章目录背景一、OpenFeign是什么Feign是什么Feign的局限性 OpenFeign是什么 二、为什么要有OpenFeign三、如何使用OpenFeign服务提供者order-servicepom文件yml配置文件启动类实体ParamController 服务消费者user-servicepom文件yml配置文件启动类接口类Us…

怎么维护自己的电脑?

方向一&#xff1a;我的电脑介绍 我使用的是一台来自知名品牌的笔记本电脑。它具有高性能的核心配置&#xff0c;如快速处理器、大容量内存和高性能显卡&#xff0c;以及宽敞的存储空间。我选择这台电脑主要是因为它的出色性能和可靠性&#xff0c;能够满足我在学习和工作中的…

Bean的实例化方法

目录 1.工厂模式通常有三种形态&#xff1a; 2.简单工厂 2.1 静态工厂 2.1通过factory-bean实例化 2.3通过FactoryBean接口实例化 3.测试 关于容器的使用 3.1获得spring文件方式 3.2getBean方式 4.关闭容器 1.工厂模式通常有三种&#xff1a; 第一种&#xff1a;简单工…

(杭电多校)2023“钉耙编程”中国大学生算法设计超级联赛(5)

1001 Typhoon 计算几何 对于每一个避难点,计算其到所有线段的距离,取min即可 AC代码&#xff1a; #include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<deque> #include<cmath> #include<cstdio&…

【Linux命令200例】whereis用于搜索以及定位二进制文件

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;本文已收录于专栏&#xff1a;Linux命令大全。 &#x1f3c6;本专栏我们会通过具体的系统的命令讲解加上鲜…

nexus迁移

数据和配置迁移 打包两个目录&#xff0c;配置nexus-2.13.0-01和数据sonatype-work 数据量大可以split分割之后迁移再合并 大概看下文件目录 [roottest nexus]# tree -L 3 . ├── nexus-2.13.0-01 │ ├── bin │ │ ├── jsw │ │ ├── nexus │ │ …

selenium 遇到更新chorme驱动

打开浏览器,在地址栏输入chrome://version/便可以查看到谷歌当前的版本号 谷歌浏览器驱动的下载网址 http://chromedriver.storage.googleapis.com/index.htmlhttp://chromedriver.storage.googleapis.com/index.html 解压后把chromedriver.exe 放到python安装的目录下&am…

谈一谈缓存穿透,击穿,雪崩

缓存穿透 缓存穿透是指在使用缓存系统时&#xff0c;频繁查询一个不存在于缓存中的数据&#xff0c;导致这个查询每次都要通过缓存层去查询数据源&#xff0c;无法从缓存中获得结果。这种情况下&#xff0c;大量的请求会直接穿透缓存层&#xff0c;直接访问数据源&#xff0c;…

电动自行车上架eBay的UL2849、16CFR1512测试标准

在奥运经济的带动下&#xff0c;今年以来运动自行车消费有较大幅度增长&#xff0c;其中高端消费者对进口自行车需求扩张&#xff0c;上半年竞赛型自行车进口量同比增长49.5%。另外&#xff0c;电助力自行车在国际市场也倍受追捧&#xff0c;国际自行车贸易总额的60%来自中国&a…

嵌入式入门教学——C51

一、前期准备 1、硬件设备 2、软件设备 二、预备知识 1、什么是单片机&#xff1f; 在一片集成电路芯片上集成微处理器、存储器、IO接口电路&#xff0c;从而构成了单芯片微型计算机&#xff0c;及单片机。STC89C52单片机&#xff1a; STC&#xff1a;公司89&#xff1a;所属…

【计算机网络】应用层协议 -- DNS协议

文章目录 1. DNS背景2. 域名简介3. 域名解析过程4. 使用dig查看DNS过程 1. DNS背景 DNS&#xff08;Domain Name System&#xff0c;域名系统&#xff09;协议&#xff0c;是一个用来将域名转化为IP地址的应用层协议。 TCP/IP当中通过IP地址和端口号的方式&#xff0c;来确定…

调试正在运行的程序(Keil)

大家好&#xff0c;我是惊觉。接上一篇调试正在运行的程序(STM32CubeIDE)&#xff0c;今天Keil的实现方法。调试正在运行的程序&#xff0c;属于附着调试&#xff0c;在启动调试器时不会重置单片机的运行状态&#xff0c;从而可以定位死机等问题。没看过上一篇的同学&#xff0…

SystemC的调度器

文章目录 前言调度器初始化evaluatewait updatenotify delta notificationtime notification仿真结束 前言 SystemC是基于C的库&#xff0c;主要用来对 IC 进行功能建模和性能建模。有时也被用来当做 RTL (register transfer level) 级的升级版 HLS(High Level synthesis) 直接…

力扣 416. 分割等和子集

题目来源&#xff1a;https://leetcode.cn/problems/partition-equal-subset-sum/description/ C题解&#xff08;思路来源代码随想录&#xff09; &#xff1a; 背包问题有多种背包方式&#xff0c;常见的有&#xff1a;01背包、完全背包、多重背包、分组背包和混合背包等等。…