C++---类与对象一

类的定义

class className{//成员字段//成员函数
};
  • class定义类的关键字,className是自己决定的类名,{ } 为类的主体,花括号里是类的内容。类的内容大致分为类的成员属性(变量)和类的成员函数
  • 注意定义类后面需要跟;,与C语言中定义结构体一样。Java中类就不用;

下面以一个栈类举例:

#include<cstdlib>
class Stack {
#define DEFAULT_CAPACITY 4
private:int* _arr;int _top;int _capacity;
public:Stack(int capacity = DEFAULT_CAPACITY) {_arr = (int*)malloc(DEFAULT_CAPACITY * sizeof(int));_top = 0;_capacity = capacity;}void push(int val) {if (_top == _capacity) {int* tmp = (int*)realloc(_arr,2 * _capacity * sizeof(int));if (tmp == nullptr) {exit(-1);}_arr = tmp;_capacity = 2 * _capacity;}_arr[_top++] = val;}bool isEmpty() {return _top == 0;}int pop() {if (isEmpty()) {return 0xFFFF;}return _arr[--_top];}int peek() {if (isEmpty()) {return 0xFFFF;}return _arr[_top-1];}~Stack() {free(_arr);}
};
//#include<iostream>
int main(void) {Stack stack;//创建一个类变量(对象)stack.push(1);//类似中的结构体引用字段,这里同样的方式调用类中函数。stack.push(2);int ret = stack.pop();std::cout<< ret << std::endl;//输出: 2return 0;
}

C++中,并没有规定成员函数和成员变量的位置。推荐函数和字段分开写。

//这是三个成员字段。
private:int* _arr;int _top;int _capacity;

为什么变量命名前面加_?
考虑若是我们取消了下划线,采用如下命名:

Stack(int capacity = DEFAULT_CAPACITY) {arr = (int*)malloc(DEFAULT_CAPACITY * sizeof(int));top = 0;capacity = capacity;
}

局部作用域中的capacity覆盖了类里面的capacity,那么capacity = capacity等价于局部变量自己和自己赋值,对类中的capacity字段没有任何影响,故命名风格改为下划线打头(一种风格)。

C++中的struct

C++是C语言的超集, C++将C中的struct升级成了类,那么现在可以粗略认为class等价于struct
主要区别在于默认的访问权限和继承权限:访问权限下文叙述。
struct 升级成了类,那么意味着:

  1. 类可以定义函数
  2. 类表示类型。
//定义一个链表类---普通的单链表
struct list {//定义链表节点struct Node {int val;Node* next;};Node *head;//头指针//......
};int main() {// 不需要sizeof(struct list),可以省略struct,类名就是类型 std::cout<<"sizeof(list):"<<sizeof(list) << std::endl;return 0;
}

类成员函数的内联性

类内定义的成员函数

  • 当成员函数在类内部定义时,编译器默认将其视为 inline。这种定义方式允许编译器在每个调用点直接插入函数代码,从而可能提高性能。
class MyClass {
public:void inlineFunction() { // 默认 inlinestd::cout << "Inline function" << std::endl;}
};

C++通常将类的声明和定义分开放置,有助于实现接口和实现的分离。
类中放函数定义(提供接口),成员函数在外部实现。

访问修饰符

在这里插入图片描述
C++实现封装的方式:类将对象的属性与方法结合在,让对象更加完善,通过访问权限允许用户使用。

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

类域

C++中,用{ }括起来的都会形成一个域。类定义了一个新的作用域: 类域,类的所有成员都在类的作用域中。
命名冲突在C语言中很明显, C++中类域有效解决了问题。比如C中自定义的Stack和Queue若都定义了size函数,那么如果你想同时引用两个头文件,不可豁免的出现了命名冲突。这时候,就不得不做出折中,选择size方法加上标识以区分。

任何一个变量,编译器都会去找他的出处。编译器默认优先在局部域寻找,然后是全局域,不会去类域中找。类外定义成员时,要使用 : : 作用域操作符指明成员属于哪个类域.


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

类域影响的编译器查找规则,不指定类域,Init函数会被全局函数。
域名限定修饰符中的Init是Date类中的成员函数, 那么既然是类中的函数,那么可以引用类的成员字段。

实例化对象

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

  1. 类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没
    有分配实际的内存空间来存储它;比如:入学时填写的学生信息表,表格就可以看成是一个
    类,来描述具体学生信息。
    类就像谜语一样,对谜底来进行描述,谜底就是谜语的一个实例。
    谜语:“年纪不大,胡子一把,主人来了,就喊妈妈” 谜底:山羊
  2. 一个类可以实例化出多个对象,实例化出的对象 占用实际的物理空间,存储类成员变量
    Person类是没有空间的,只有Person类实例化出的对象才有具体的年龄。
  3. 做个比方。类实例化出对象就像现实中使用建筑设计图建造出房子,类就像是设计图,只设
    计出需要什么东西,但是并没有实体的建筑存在,同样类也只是一个设计,实例化出的对象
    才能实际存储数据,占用物理空间。
class Date
{
public:void Init(int year, int month, int day);private:
//只是声明类中有这个字段,并没有申请空间。int _year;int _month;int _day;
};
int main(void) {//用类这个类型创建一个变量的过程叫做实例化对象。Date date;//只要实例化对象,才会分配空间date.Init(2024, 9, 18);return 0;
}

计算类对象的大小

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

问题:类中既可以有成员变量,又可以有成员函数,那么一个类的对象中包含了什么?如何计算
一个类的大小?
类实例化出的每个对象,都有独⽴的数据空间,所以对象中肯定包含成员变量,那么成员函数是否包含呢?⾸先函数被编译后是⼀段指令,对象中没办法存储,这些指令存储在⼀个单独的区域(代码段),那么对象中⾮要存储的话,只能是成员函数的指针。再分析⼀下,对象中是否有存储指针的必要呢,Date实例化d1和d2两个对象,d1和d2都有各⾃独⽴的成员变量 _year/_month/_day存储各⾃的数据,但是d1和d2的成员函数Init/Print指针却是⼀样的,存储在对象中就浪费了。如果⽤Date实例化100个对象,那么成员函数指针就重复存储100次,太浪费了。

其实函数指针是不需要存储的,函数指针是⼀个地址,调⽤函数被编译成汇编指 令[call 地址],其实编译器在编译链接时,就要找到函数的地址,不是在运⾏时找.
只有动态多态是在运行时找,就需要存储函数地址。

// 类中既有成员变量,又有成员函数
class A1 {
public:void f1() {}
private:int _a;
};class A2 {
public:void f2() {}
};
// 类中什么都没有---空类
class A3
{};
int main(void) {std::cout << "A1:" << sizeof(A1) << " A2:" << sizeof(A2) << " A3:" << sizeof(A3) << std::endl;return 0;
}

输出结果:A1:4 A2:1 A3:1
结论:一个类的大小,实际就是该类中”成员变量”之和,但需注意内存对齐 空类比较特殊,编译器给了空类“一个字节”来唯一标识这个类的对象。

结构体内存对齐

这里只是列出C语言处学的结构体内层对齐规则。

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

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

对于上述类,有这样的一个问题:
Date类中有 Init 与 Print 两个成员函数,函数体中没有关于不同对象的区分,那当d1调用 Init 函
数时,该函数是如何知道应该设置d1对象,而不是设置d2对象呢?
在 C++ 中,调用一个对象的成员函数时,编译器自动将调用该函数的对象地址通过 this 指针传递给该函数。这个 this 指针指向当前调用函数的对象实例,从而让成员函数知道它应该操作哪个对象的成员变量。
具体来说, Date 类中,Init 和 Print 函数其实都隐含了对 this 指针的使用。编译器在编译时,会自动将 this 指针传递给这两个成员函数,使得它们能够操作调用它们的对象的成员变量。下面通过对代码的解释来说明:

class Date
{
public:void Init(int year, int month, int day){// 隐含 this 指针:this->_year, this->_month, this->_day_year = year;_month = month;_day = day;}void Print() //隐含于void Print(Date *this){// 隐含 this 指针:this->_year, this->_month, this->_daycout << _year << "-" << _month << "-" << _day << endl;}private:int _year;int _month;int _day;
};

this指针的特性

  1. this指针的类型:类类型* const,即成员函数中,不能给this指针赋值。
  2. 只在“成员函数”的内部使用
  3. this指针本质上是“成员函数”的形参,当对象调用成员函数时,将对象地址作为实参传递给
    this形参。所以对象中不存储this指针。
  4. this指针是“成员函数”第一个隐含的指针形参,一般情况由编译器通过ecx寄存器自动传
    递,不需要用户传递.
  1. this指针存在哪里?
    函数栈帧的局部变量中,或者在函数内。
  2. this可以为nullptr?
    在C++中this指针不能为nullptr,它始终指向当前对象(而当前对象是已分配有效地址的变量)。调用非静态成员函数时,this指针必须指向有效的对象实例。
    如果内部没有出现类似this->?操作,那么程序不会崩溃,但这种本身就是未定义行为。

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

理解人工智能、机器学习与深度学习的关系

1. 人工智能&#xff08;AI&#xff09;宏观的智能概念 人工智能&#xff08;Artificial Intelligence, AI&#xff09;是一个广泛的领域&#xff0c;涉及设计和开发能够表现出智能行为的计算机系统。这些系统可以模拟或执行类似于人类的认知功能&#xff0c;如学习、推理、决…

react 路由 react-router/react-router-dom

react-router-dom中包含react-router 安装前者即可 npm install react-router-dom -Simport { BrowserRouter as Router, Route, Link, Switch } from react-router-dom <Switch>组件&#xff0c;和switch语法一样&#xff0c;遇到匹配就结束&#xff0c;后面的<Route…

如何全面优化MySQL性能

MySQL数据库性能优化是一项复杂而细致的任务&#xff0c;它涉及到数据库设计、查询优化、服务器配置等多个方面。以下是几个关键的步骤和策略&#xff0c;旨在帮助提升MySQL数据库的运行效率&#xff1a; 优化数据库设计 选择合适的数据类型&#xff1a;合理选择数据类型不仅能…

树——数据结构

这次我来给大家讲解一下数据结构中的树 1. 树的概念 树是一种非线性的数据结构&#xff0c;它是由n(n>0&#xff09;个有限结点组成一个具有层次关系的集合。 叫做树的原因&#xff1a;看起来像一棵倒挂的树&#xff0c;根朝上&#xff0c;叶朝下。 特殊结点&#xff1a…

vmware中的ubuntu系统扩容分区

1.虚拟机关机 右击虚拟机/设置&#xff0c;进入虚拟机设置 3.启动虚拟机&#xff0c;进入命令行 4.fdisk -l查看要扩展的分区名 5.resize要扩容的分区 su root parted /dev/sda resizepart 3 100% fdisk -l resize2fs /dev/sda3 df -T完成 6.其他 进入磁盘管理 fdisk /d…

Doker学习笔记--黑马

介绍&#xff1a;快速构建、运行、管理应用的工具 在不同的服务器上部署多个应用&#xff0c;但是往往不同应用之间会有冲突&#xff0c;因为它们所依赖的环境&#xff0c;函数库&#xff0c;配置都不一样&#xff0c;此时docker在运行时形成了一个隔离环境&#xff08;容器&am…

idea上传jar包到nexus

注意&#xff1a;确保idea中项目为maven项目&#xff0c;并且在nexus中已经创建了maven私服。 1、配置pom.xml中推送代码配置 <distributionManagement> <repository> <id>releases</id> <url>http://127.0.0.1:8001/repository/myRelease/<…

c++9月18日

1&#xff0c;斐波那契数列 int str 0;int num 0;int kgo 0;int qto 0;cout<<"请输入字符串";string str1;getline(cin,str1);for(int i0;i<(int)(str1.size());i){if((str1.at(i)>65&&str1.at(i)<90)||(str1.at(i)>97&&str1.…

【oj刷题】二分查找篇:二分查找算法的原理和应用场景

前言&#xff1a; 二分查找算法&#xff0c;又称折半查找算法&#xff0c;是一种在有序数组中查找特定元素的高效查找方法。它通过将搜索区间不断缩小一半&#xff0c;从而在对数时间内找到目标元素。二分查找是基于分治策略的一种典型应用&#xff0c;能够高效的处理许多问题&…

Golang Beego+Vue打造的高校科研工作管理系统,让信息发布更及时,项目管理更透明

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

基于深度学习的眼部疾病检测识别系统

温馨提示&#xff1a;文末有 CSDN 平台官方提供的学长 QQ 名片 :) 1. 项目简介 眼部疾病的早期诊断对于防止视力下降乃至失明至关重要。然而&#xff0c;专业的医疗资源分布不均&#xff0c;尤其是在偏远地区&#xff0c;人们很难获得专业的眼科医生提供的及时诊断服务。本系统…

密码学基础 C#实现门限共享密码算法

加密社 概念 门限秘密共享是一种密码学技术&#xff0c;将秘密 S 分割为 n 个部分&#xff0c;并将这些部分分发给 n 个参与者。所谓门限&#xff0c;是在分割这些秘密的时候&#xff0c;设置一个大小位于 1 和 n 之间的 k 值&#xff0c;使得给定任意 k−1 个或更少的秘密份额…

PaddleNLP本文分类及docker部署流程

本文记录使用PaddleNLP进行文本分类的全流程 参考&#xff1a;https://github.com/PaddlePaddle/PaddleNLP/tree/develop/legacy/applications/text_classification/multi_class 文章目录 1. 数据准备2. 模型训练2.1 准备关键库2.2 模型训练&#xff06;验证2.3 模型测试2.4 结…

comsol多物理场仿真技术与应用入门教学

一、COMSOL 多物理场仿真基础强化 几何建模 1、二维对象和三维对象的建模流程和快速建模方法&#xff0c;通过二维对象构建三维对象、三维提取二维结构等详细操作&#xff1b; 2、缩放、拉伸、阵列、移动、拷贝、镜像、旋转、线段、参数化曲线、布尔运算、转换等常用操作演示…

Java迭代器Iterator和Iterable有什么区别?

在 Java 中&#xff0c;我们对 List 进行遍历的时候&#xff0c;主要有这么三种方式。 第一种&#xff1a;for 循环。 for (int i 0; i < list.size(); i) {System.out.print(list.get(i) "&#xff0c;"); } 第二种&#xff1a;迭代器。 Iterator it list.i…

【JVM安装MySQL】

环境 > VMware Workstation Pro > CentOS 7 >Navicat Premium Lite > MobaXterm添加 MySQL Yum 仓库 根据操作系统在下载界面选取对应yum库进行下载 wget https://dev.mysql.com/get/mysql80-community-release-el7-9.noarch.rpm在文件下载界面安装 rpm -ivh mysq…

C++_类和对象(中篇)—— const成员函数、取地址运算符的重载

目录 三、类和对象&#xff08;中&#xff09; 6、取地址运算符重载 1、const成员函数 2、取地址运算符的重载 三、类和对象&#xff08;中&#xff09; 6、取地址运算符重载 1、const成员函数 将const修饰的成员函数称之为const成员函数&#xff0c;const修饰成员函数…

多语言建站怎样利于SEO 中英文网店系统的推广方式

外贸电商独立站是很多企业出海的选择&#xff0c;今天我来说一下多语种网站建设的问题。 联合国给出的世界常用语言有六种&#xff0c;有汉、英、法、俄、阿、西&#xff0c;但是我见过最疯狂的一件事就是有的网络公司给客户建网站&#xff0c;有40种、50种语言&#xff0c;甚至…

客户端/服务器的简易实现

目录 一,网络编程套接字 二,UDP/TCP的区别(​编辑) 三,UDP API使用 四,TCP API使用 一,网络编程套接字 socket socket(操作系统给应用程序的API,起了一个名字,就成为socket API) socket API提供了两套API分别为UDP和TCP: 二,UDP/TCP的区别() TCP有链接,可靠传输,面向字…

neo4j节点关联路径的表示、节点的增删改查

目录 核心概念节点的增删改查&#xff08;1&#xff09;增&#xff08;2&#xff09;查&#xff08;3&#xff09;删&#xff08;4&#xff09;改 neo4j文档&#xff1a;https://neo4j.com/docs/ https://neo4j.com/docs/cypher-manual/current/introduction/ 核心概念 节点 ne…