当前位置: 首页 > news >正文

C++基础之类、对象一(类的定义,作用域、this指针)

目录

面向对象的编程

类的引入

简介

类的定义

简介

访问限定符

命名规则

封装

简介

类的作用域

类的大小及存储模型

this指针

简介

面向对象的编程

C++与C语言不同,C++是面向对象的编程,那么什么是面向对象的编程呢?

C语言编程,规定了编程的每一步指令,程序从上而下一步一步按照指令,最终达到想要的结果,而面向对象是另一种思路,将一件事情拆分成不同的对象,任务需要依靠对象之间的交互完成,也就是说关注模块和模块之间的关系。

类的引入

简介

类是C++中重要的概念,从C语言的结构体升级而来,C语言的结构体只能定义变量,C++中结构体不仅可以定义变量还能定义函数(成员变量/成员属性,成员函数/成员方法)

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;}

类的定义

C++中用class作为关键字定义类,其结构如下:

class classname
{//类体//成员变量(成员属性)//成员函数(成员方法)
}; 

访问限定符

C++中设置了访问限定符,其作用是设置类体的属性,访问限定符作用域从当前限定符开始直到下个访问限定符出现结束,如果没有访问限定符则直到类结束;

1、public 修饰的类体,可以直接被外部访问;

2、protected(保护)与private(私有)修饰的类体有同样的特征不允许被外部访问;

3、struct与class在默认的访问限定符不同,struct为了兼容c语言,默认的是public,class默认的是private。

命名规则

先看一下下面代码

class Date
{
private:int year;int month;int day;
public:void init(int year, int month, int day){year = year;month = month;day = day;}void print(){printf("%d-%d-%d\n", year, month, day);}
};
	void init(int year, int month, int day){year = year;month = month;day = day;}

这段代码阅读起来很不方便,形参与类中的成员变量无法区别,为了更好的阅读,在成员变量命名时可以加以区分;

class Date
{
private:int _year;int _month;int _day;
public:void init(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};

封装

简介

C++中存在多种特性,面向对象的最主要的是封装,继承,多态;

类和对象的阶段,主要是封装的特性,那么什么是封装呢?

简单的说,封装是一种管理行为,将程序的属性与方法结合在一起,隐藏对象的属性和细节,仅保留对外接口和对象进行交互,封装的特性在C++的类中体现的很明显;

class Date
{
private:int year;int month;int day;
public:void init(int year, int month, int day){year = year;month = month;day = day;}void print(){printf("%d-%d-%d\n", year, month, day);}
};int main()
{Date s;s.print();system("pause");return 0;
}

 上面的代码中,成员变量无法通过外部进行修改,只能通过init函数进行修改;

类的大小及存储模型

先看下面的代码:

class Date
{
public:int _year;int _month;int _day;void init(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};int main()
{Date s;printf("类的大小:%d\n", sizeof(s));system("pause");return 0;
}

上面这段代码的结果为12。为什么是12而不是20(包含两个函数的指针),这由类的存储模型决定的。

类的存储模型

 内存通常分为栈区,堆区,静态区,常量区等,(栈区的空间非常小)为了节省空间,编译器会将成员函数放在常量区(代码段)中,使用时寻找函数。

this指针

先看下面的代码及运行结果

class Date
{
private:int _year;int _month;int _day;
public:Date(int year=1, int month=1, int day=1){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};int main()
{Date d1(2023,5,7);Date d2(2024, 6, 8);d1.print();d2.print();system("pause");return 0;
}

 成员函数存储在常量区,那为什么d1和d2调用时会打印出不同的结果呢?

这是因为类中的函数有一个隐藏的参数this指针。

void thisprint(Date *this)//this指针隐藏在类的函数中,不能手写,编译器自动完成

那么this指针又是什么呢?

class Date
{
private:int _year;int _month;int _day;
public:Date(int year=1, int month=1, int day=1){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}void thisprint(){printf("this指针:%p\n", this);}
};int main()
{Date d1(2023,5,7);Date d2(2024, 6, 8);printf("d1的地址: %p\n", &d1);d1.thisprint();printf("d2的地址: %p\n", &d2);d2.thisprint();system("pause");return 0;
}

 

 通过上面代码的结果,this指针就是类的地址,那么可以由以下结论;

void print(){printf("%d-%d-%d\n", this->_year, this->_month, this->_day);}
//类能通过常量区的成员函数打印值,是通过指针调用完成的。

 为了保护this指针的值不被修改,this指针会用const修饰,写成const int * this(指针指向的值无法被修改   int * const this指针指向的变量不能被修改);

 this指针也是存在栈区中,其作用域与生命周期随着函数的调用而产生,随着函数的销毁而消失,VS下通常优化在寄存器ecx中;

this 指针可以为空吗?

//先看下这段代码
class A
{
public:void Print(){std::cout << "Print()" << std::endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->Print();system("pause");return 0;
}
//结构体的指针为nullptr,this指针为nullptr,在调用函数时Print函数从常量区中调用,与this指针无关,所以该程序可以正常运行;
//再看下面这段代码
class A
{
public:void PrintA(){std::cout << _a << std::endl;}
private:int _a;
};
int main()
{A* p = nullptr;p->PrintA();return 0;
}
//虽然PrintA函数被成功调用,但是因为p指向nullptr,所以_a是无法读取内存的,因此运行时程序会崩溃

类的作用域

类的作用域是{}中的部分,但是它只是虚拟的,这是因为类类似于图纸;

class Date
{
public:int _year;int _month;int _day;void init(int year, int month, int day){_year = year;_month = month;_day = day;}void print(){printf("%d-%d-%d\n", _year, _month, _day);}
};namespace date
{int _year = 2023;int _month = 5;int _day = 1;
}int main()
{Date s;/*s.print();*/printf("%d-%d-%d\n", date::_year, date::_month, date::_day);printf("%d-%d-%d\n", Date::_year, Date::_month, Date::_day);//该语句无法通过编译system("pause");return 0;
}

 上面的代码中,命名空间的变量可以通过作用域运算符::来找到对应的变量,但是类中定义的变量不能通过,其原因就是类没有被真实创建,类定义的只是图纸。

事实上不光是成员属性不能使用作用域运算符,成员方法也不行,这是因为this指针,虽然类中创建了成员函数,但是类没有被创建,没有this指针,所以运行崩溃。

成员函数的创建

定义成员函数时,如果将成员函数都放在类的内部,那么阅读起来会非常麻烦,通常只在类中声明,在外部定义;

class A
{
public:void PrintA();
private:int _a=10;
};void A:: PrintA()
{std::cout << _a << std::endl;
}int main()
{A _a;_a.PrintA();system("pause");return 0;
}

相关文章:

C++基础之类、对象一(类的定义,作用域、this指针)

目录 面向对象的编程 类的引入 简介 类的定义 简介 访问限定符 命名规则 封装 简介 类的作用域 类的大小及存储模型 this指针 简介 面向对象的编程 C与C语言不同&#xff0c;C是面向对象的编程&#xff0c;那么什么是面向对象的编程呢&#xff1f; C语言编程&#xff0c;规定…...

javaScript---设计模式-封装与对象

目录 1、封装对象时的设计模式 2、基本结构与应用示例 2.1 工厂模式 2.2 建造者模式 2.3 单例模式 封装的目的&#xff1a;①定义变量不会污染外部&#xff1b;②能作为一个模块调用&#xff1b;③遵循开闭原则。 好的封装&#xff08;不可见、留接口&#xff09;&#xff1a;①…...

【消息中间件】kafka高性能设计之内存池

文章目录 前言实现创建内存池分配内存释放内存 总结 前言 Kafka的内存池是一个用于管理内存分配的缓存区域。它通过在内存上保留一块固定大小的内存池&#xff0c;用于分配消息缓存、批处理缓存等对象&#xff0c;以减少频繁调用内存分配函数的开销。 Kafka内存池的实现利用了…...

创建型模式——单例(singleton)

1. 模式说明 单例模式保证类只有一个实例&#xff1b;创建一个对象&#xff0c;当你创建第二个对象的时候&#xff0c;此时你获取到的是已经创建过的对象&#xff0c;而不是一个新的对象&#xff1b; 1.1 使用场景 共享资源的访问权限&#xff1b;任务的管理类&#xff1b;数…...

算法:迷宫问题

描述 定义一个二维数组 N*M &#xff0c;如 5 5 数组下所示&#xff1a; int maze[5][5] { 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, }; 它表示一个迷宫&#xff0c;其中的1表示墙壁&#xff0c;0表示可以走的路&#xff0c;只能横着走或…...

聊聊并发编程的12种业务场景

前言 并发编程是一项非常重要的技术&#xff0c;无论在面试&#xff0c;还是工作中出现的频率非常高。 并发编程说白了就是多线程编程&#xff0c;但多线程一定比单线程效率更高&#xff1f; 答&#xff1a;不一定&#xff0c;要看具体业务场景。 毕竟如果使用了多线程&…...

MySQL执行顺序

MySQL执行顺序 MySQL语句的执行顺序也是在面试过程中经常问到的问题&#xff0c;并且熟悉执行顺序也有助于SQL语句的编写。 SELECT FROM JOIN ON WHERE GROUP BY HAVING ORDER BY LIMIT执行顺序如下&#xff1a; FROM ON JOIN WHERE GROUP BY # (开始使用别名) SUM # SUM等…...

引领真无线耳机未来趋势,NANK南卡OE骨传导真无线耳机惊艳亮相

传统的蓝牙耳机存在很多问题&#xff0c;例如续航时间短、长期佩戴耳朵会不舒服&#xff0c;甚至影响听力等等。为了解决这些问题&#xff0c;在骨传导领域深耕十多年的南卡品牌推出了这款真无线骨传导耳机——NANK南卡 OE。 NANK南卡OE即将正式上线&#xff0c;这一消息一经宣…...

5款写作神器,帮助你写出5w+爆款文案,好用到哭

我不允许还有文案小白、新手博主不知道这5款写作利器&#xff01; 每次一写文案就头秃的新媒体工作者&#xff0c;赶紧看过来吧&#xff01;这5款好用到爆的写作神器&#xff0c;喝一杯咖啡的时间就能完成写作。 我和同事都是用它们&#xff0c;出了很多的爆款&#xff0c;现…...

相交链表问题

给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 图示两个链表在节点 c1 开始相交&#xff1a; 题目数据 保证 整个链式结构中不存在环。 注意&#xff0c;函数返回结果后&…...

[ubuntu] ax200网卡虚接,导致系统根目录占满而无法进入系统的奇葩问题

20230508&#xff0c;我像往常一样,打开电脑发现根目录满了&#xff0c;报警了&#xff0c;所以按照网上的教程&#xff0c;清理了一下根目录的文件&#xff0c;没想到背后是网卡问题… 文章目录 1.进入终端模式2.查看占用情况3.清理系统log文件3.1 清理/var/log/syslog3.2 清…...

本地字体库的引入方法

本地字体库是指在计算机系统中存储的一组字体文件&#xff0c;通常包含多种字体格式&#xff0c;如TTF、OTF、WOFF等。引入本地字体库可以让用户在使用计算机时可以选择不同的字体&#xff0c;从而提高用户的使用体验。 本地字体库的引入方式有多种&#xff0c;其中比较常用的是…...

7种优秀的导航菜单设计总结

导航是应用程序界面中最常见的模块之一&#xff0c;在链接应用程序中起着每个页面的作用。 不同的设计需求和业务目标决定了导航的设计因品而异&#xff0c;移动设备的尺寸远小于计算机。因此&#xff0c;在设计移动终端导航时&#xff0c;应考虑更全面&#xff0c;以确保简单…...

Problem E. 矩阵游戏 (2023年ccpc河南省赛)

原题链接&#xff1a; https://codeforces.com/gym/104354 题意&#xff1a; 有一个n*m的矩阵&#xff0c;只有三种字符&#xff1a;0,1和?。从[1,1]走到[n,m],每次只能向下走或者向下走。当走到1的时候得一分&#xff0c;走到0的时候不得分&#xff0c;走到?的时候可以将他…...

数字孪生模型构建理论及应用

源自&#xff1a;计算机集成制造系统 作者&#xff1a;陶飞 张贺 戚庆林 徐 俊 孙铮 胡天亮 刘晓军 刘庭煜 关俊涛 陈畅宇 孟凡伟 张辰源 李志远 魏永利 朱铭浩 肖斌 摘 要 数字孪生作为实现数字化转型和促进智能化升级的重要使能途径&#xff0c;一直备受各…...

Vue面试题:30道含答案和代码示例的练习题

Vue中的双向数据绑定是怎么实现的&#xff1f; 双向数据绑定通过使用v-model指令实现。v-model指令会在表单元素上创建一个监听器&#xff0c;在用户输入时实时更新Vue实例的数据&#xff0c;并且在Vue实例数据变化时更新表单元素的值。 如何在Vue中定义一个方法&#xff1f;…...

2023-05-09 LeetCode每日一题(有效时间的数目)

2023-05-09每日一题 一、题目编号 2437. 有效时间的数目二、题目链接 点击跳转到题目位置 三、题目描述 给你一个长度为 5 的字符串 time &#xff0c;表示一个电子时钟当前的时间&#xff0c;格式为 “hh:mm” 。最早 可能的时间是 “00:00” &#xff0c;最晚 可能的时间…...

第三节课 Linux文件权限

目录 文件属性详解 权限修改 文件所有者与属组修改 文件默认权限修改 Linux是多人多任务的操作系统&#xff0c;因此可能常常会有多人使用一台机器&#xff0c; 为了考虑每个人的隐私、方便用户合作&#xff0c;每个文件都有三类用户&#xff0c;权限是基于这三类用户设定的…...

开发STC89C51系列单片机需要的单片机技术

端口操作&#xff1a;控制单片机的输入输出端口&#xff0c;与外界进行通信。中断优先级&#xff1a;当多个中断同时发生时&#xff0c;确定哪个中断优先级更高&#xff0c;优先响应。时钟模块&#xff1a;控制单片机的时钟&#xff0c;可以精确计时。PWM技术&#xff1a;实现模…...

分布式键值存储是什么?(分布式键值存储大值)

文章目录 什么是分布式键值存储&#xff1f;分布式键值存储“大值”指什么&#xff1f; 什么是分布式键值存储&#xff1f; 分布式键值存储是一种分布式数据存储系统&#xff0c;它将数据存储为键值对的形式&#xff0c;并将这些键值对分散在多个节点上。每个节点都可以独立地…...

多线程(线程同步和互斥+线程安全+条件变量)

线程互斥 线程互斥&#xff1a; 任何时刻&#xff0c;保证只有一个执行流进入临界区访问临界资源&#xff0c;通常对临界资源起到保护作用 相关概念 临界资源&#xff1a; 一次仅允许一个进程使用的共享资源临界区&#xff1a; 每个线程内部&#xff0c;访问临界资源的代码&am…...

Flutter学习——开发Flutter需要的技能

第二章 Flutter开发所需要掌握的知识 文章目录 第二章 Flutter开发所需要掌握的知识前言一、开发语言Dart语言Android/Ios知识 二、组件学习三、调试与性能优化总结 前言 上一章&#xff0c;介绍了Flutter的来源和平台支持及特点&#xff0c;这一章&#xff0c;来梳理一下学习…...

SPSS如何进行因子分析和主成分分析之案例实训?

文章目录 0.引言1.因子分析2.主成分分析 0.引言 因科研等多场景需要进行数据统计分析&#xff0c;笔者对SPSS进行了学习&#xff0c;本文通过《SPSS统计分析从入门到精通》及其配套素材结合网上相关资料进行学习笔记总结&#xff0c;本文对因子分析和主成分分析进行阐述。 1.因…...

图标字体与HTML转义字符:网页设计中的两个关键概念

在网页设计中&#xff0c;图标字体和HTML转义字符是两个重要的概念。图标字体用于显示网页的图标&#xff0c;可以让用户更加直观地理解网页的内容。而HTML转义字符则用于在网页中插入特殊的字符&#xff0c;以保证网页的安全性和可读性。 一、图标字体 在网页中显示图标&#…...

Elasticsearch详解

文章目录 概览使用与ES交互索引创建索引查询索引删除文档创建修改文档局部修改文档查询文档删除全查询 整合SpringBootpom依赖application.ymlElasticsearchAutoConfigurationElasticsearchPropertiesElasticsearchConstantPersonSearchPageHelperPersonServiceBaseElasticsear…...

学习笔记(13)网络基础

目录 1&#xff0c;get与post的区别2&#xff0c;JSON解析2.1&#xff0c;JSON.stringify2.2&#xff0c;JSON.parse 3&#xff0c;cookie3.1&#xff0c;set方法3.2&#xff0c;cookie方法用于设置响应头&#xff0c; 4&#xff0c;http模块4.1&#xff0c;请求报文和响应报文…...

LeertCode 134 加油站

题目&#xff1a; 在一条环路上有 n 个加油站&#xff0c;其中第 i 个加油站有汽油 gas[i] 升。你有一辆油箱容量无限的的汽车&#xff0c;从第 i 个加油站开往第 i1 个加油站需要消耗汽油 cost[i] 升。你从其中的一个加油站出发&#xff0c;开始时油箱为空。给定两个整数数组 …...

python文件操作的基本流程

引入 程序运行过程中产生的数据会保存到内存中&#xff0c;如果想要永久保存下来&#xff0c;就必须将数据存放在硬盘上&#xff0c;应用程序如果想要操作计算机的硬件就必须通过操作系统&#xff0c;文件就是操作系统提供给应用程序来操作硬盘的虚拟概念&#xff0c;应用程序…...

1. 两数之和

原题链接&#xff1a; 1. 两数之和 https://leetcode.cn/problems/two-sum/ 完成情况&#xff1a; ##1. n 2 n^2 n2复杂度 2.HashMap进行优化 3.空间换时间方法 即&#xff0c;构建一个 1 0 − 9 10^-9 10−9 到 1 0 9 10^9 109这个大的数组&#xff0c;然后把数填进去&…...

操作系统:06 进程通信

1 基本概念 进程间通信是指两个或多个进程之间交互数据的过程&#xff0c;因为进程之间是相互独立的&#xff0c;为了协同工作必须进行进程间交互数据 2 进程间通信的分类 2.1 简单的进程间通信&#xff1a; 信号(携带附加数据)、文件、命令行参数、环境变量表 2.2 传统的进…...