C++——类和对象(上)

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

C语言是面向过程的,关注的是过程,分析出求解问题的步骤,通过函数调用逐步解决问题。

例如手洗衣服

C++是基于面向对象的,关注的是对象,将一件事情拆分成不同的对象,靠对象之间的交互完成。

例如用洗衣机洗衣服

总共有四个对象:人、衣服、洗衣粉、洗衣机。

整个洗衣服的过程:人将衣服放进洗衣机、倒入洗衣粉,启动洗衣机,洗衣机就会完成洗衣过程并且甩干。

衣服、洗衣粉、洗衣机四个对象之间交互完成的,人不需要关整个过程主要是:新洗衣机具体是如何洗衣服的,是如何甩干的。

2.类的引入

C语言结构体中只能定义变量,在C++中,结构体内不仅可以定义变量,也可以定义函数。比如:之前在数据结构初阶中,用C语言方式实现的栈,结构体中只能定义变量,现在以C++方式实现会发现struct中也可以定义函数。

struct在C++中升级成了类,里面有成员函数和成员变量  C++类名就是类型。

再也不需要在struct里面定义函数了,在类里面定义就可以。

#include<iostream>

using namespace std;

struct Stack
{
public:
	void Init()
	{
		_a = nullptr;
		_top = _capacity = 0;
	}
	void Push(int x)
	{
		//...
	}

private:
	int* _a;
	int _top;
	int _capacity;
};

int main()
{
	Stack st;
	st.Init();
	st.Push(1);
	st.Push(2);
}

有了类和对象 以后再也不用像C语言害怕发生命名函数冲突

比如写栈的初始化 插入 销毁等等,函数声明和函数定义都要加上相对应实现类型名字栈、队列、链表等等。有了C++以后再也不这样,直接在类里面定义,在main函数里面引用使用即可。

C语言是结构体和函数定义分离

struct Stack
{
	int* a;
	int top;
	int capacity;
};

void StackInit(struct Stack*ps);
void StackPush(struct Stack*ps,int x);

int main()
{
	struct Stack st;
	StackInit(&st);
	StackPush(&st, 1);
	StackPush(&st, 2);
}

而C++兼容C语言 strcut所有玩法 再也不用typedef了,类名就是类型。

#include<iostream>

using namespace std;

struct Stack
{
public:
	void Init()
	{
		_a = nullptr;
		_top = _capacity = 0;
	}
	void Push(int x)
	{
		//...
	}

private:
	int* _a;
	int _top;
	int _capacity;
};

3.类的定义

在C++中,struct类更喜欢用class代替。

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

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

类体中内容称为类的成员: 类中的变量称为类的属性或成员变量; 类中的函数称为类的方法或者成员函数。

#include<iostream>

using namespace std;

class Stack
{
public:
	void Init()
	{
		_a = nullptr;
		_top = _capacity = 0;
	}
	void Push(int x)
	{
		//...
	}

private:
	int* _a;
	int _top;
	int _capacity;
};

int main()
{
	Stack st;
	st.Init();
	st.Push(1);
	st.Push(2);
}

类的两种定义方式

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

#include<iostream>

using namespace std;

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;
	Date d2;
	d1.Init(2023, 10, 28);
	

	return 0;
}

没有call指令了,被当成内联函数展开了。 

2.类声明放在.h文件中,成员函数定义放在.cpp文件中,注意: 成员函数名前需要加类名::

Date.h
#pragma once
#include<iostream>

using namespace std;

class Date
{
public:

	void Print();

private:
	int _year;
	int _month;
	int _day;
};


Date.cpp
#include"Date.h"

void Date::Print()
{
	cout << _year << "-" << _month << "_" << _day << endl;
}

test.cpp
#include"Date.h"
int main()
{
	Date d1;
	d1.Print();
}

一般情况下,更期望采用第二种方式。注意: 我为了方便演示使用方式一定义类,大家后面敲代码或者工作中尽量使用第二种。 

成员变量命名规则的建议:
#include<iostream>

using namespace std;

class Date
{
public:
	void Init(int year, int month, int day)
	{
         是形参还是成员变量?
		year = year;
		month = month;
		day = day;
	}



private:
	int year;
	int month;
	int day;
};

初始化这里是成员变量year呢还是形参year呢?

答案是形参 因为局部优先 相当于形参给自己赋值没有任何实质性改变。

d1里面是随机值。

为了区分成员变量和形参,C++一般在成员变量名称前面加个下划线_或者在后面加个下划线_,只要你自己能分得清成员变量和形参你随便给符号或者字母,但推荐使用前面加个下划线_,用简洁又高效,辨别成员变量和形参。

#include<iostream>

using namespace std;

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



private:
	int _year;
	int _month;
	int _day;
};

 类的访问限定符及封装

访问限定符

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

访问限定符说明

1.public修饰的成员在类外可以直接被访问。

2. protected和private修饰的成员在类外不能直接被访问(此处protected和private是类似的)。

3.访问权限作用域从该访问限定符出现的位置开始直到下一个访问限定符出现时为止。

4.如果后面没有访问限定符,作用域就到了即类结束。
5.class的默认访问权限为private,struct为public(因为struct要兼容C)

 

5.类的作用域

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

一般在C++中{}里面都能算作作用域。

一般在声明和定义分离时使用域作用限定符::在类里面的函数相关的定义。

6.类的实例

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


1.类是对对象进行描述的,是一个模型一样的东西,限定了类有哪些成员,定义出一个类并没有分配实际的内存空间来存储它,比如:入学时填写的学生信息表,表格就可以看成是类,来描述具体学生信息。

2.一个类可以实例化出多个对象,实例化出的对象占用实际的物理空间,存储类成员变量

类和对象的关系是一对多的。

把类比作楼房图纸 对象是根据图纸已经创建出来的高楼大厦。

所以类里面的成员变量只是设计出了构图 没有实体建筑形成。

实例化的对象才能存储数据,占有物理空间。

 

7.类的对象大小的计算

如何计算类对象的大小

#include<iostream>

using namespace std;

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 d1;//定义了一个对象
	
	cout << sizeof(d1) << endl;
	
}

 答案是12。

为什么会出现是12呢?类里面既有成员变量,又有成员函数,那么一个类的对象中包含了什么?

如果计算类的大小呢?

当我通过调试查看反汇编时,看到了d1和d2调用是同一个地址的函数。 

缺陷:每个对象中成员变量是不同的,但是调用同一份函数,如果按照此种方式存储,当一个类创建多个对象时,每个对象中都会保存一份代码,相同代码保存多次,浪费空间。那么如何解决呢? 

 C++采用了只保存成员变量,成员函数放在公共代码段

比如我们为了让小区的人打上篮球,有必要给每家每户建造一个私人篮球场吗?

显然是不符合现实的,而且会造成资金浪费。

所以我们为了让小区的人打上篮球,只要在公共区域打造一个篮球场,提供给小区的人们娱乐就ok。

C++也效仿了:把成员函数放到公共代码段,当成员变量去找成员函数定义就去公共代码区去找,节省空间。

我们再实验几个实验样例

空类里面既没有成员变量,又没有成员函数

#include<iostream>

using namespace std;

class B
{

};
int main()
{
	
	cout << sizeof(B) << endl;

	
}

无成员变量的类,对象大小开辟一个字节,这个字节不存储数据。 

#include<iostream>

using namespace std;

class B
{

};
int main()
{
	
	B b1;
	B b2;
	cout << sizeof(B) << endl;
	cout << &b1 << endl;
	cout << &b2 << endl;

	
}

为了标识定义的对象曾经存在过,就会开辟一个字节来证明。

类里面既有成员变量又有成员函数

class A
{
public:
	void f()
	{

	}
private:
	int _a;
};

int main()
{
	cout << sizeof(A) << endl;
	

	
}

类里面只有成员函数

class A
{
public:
	void f()
	{

	}
};

int main()
{
	cout << sizeof(A) << endl;
	

	

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

8.类成员函数的this指针

1.this指针的引出

#include<iostream>

using namespace std;

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;
	Date d2;
	d1.Init(2023, 10, 28);
	d2.Init(2023, 10, 29);
	d1.Print();
	d2.Print();

	return 0;
}

Date类中有两个成员函数Init和Print(),函数体中没有关于不同对象的区分,那么当d1调用函数Init和Print()时,所调函数是怎么知道是d1 对象,而不是d2对象呢?

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

只不过所有的操作对用户是透明的,即用户不需要来传递,编译器自动完成。

编译器实际完成的

this指针相关的实参和形参——不能显示的写  否则编译器会报错 运行不了

2.this的特性

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

 可以看见this指针地址跟&d1&d2都一样,可以根据d1对象的地址通过传实参给this指针做形参。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

计算机视觉的相机选型

#你一般什么时候会用到GPT?# 目前市面上的工业相机大多是基于CCD&#xff08;ChargeCoupled Device&#xff09;或CMOS&#xff08;Complementary Metal Oxide Semiconductor&#xff09;芯片的相机。一般CCD制造工艺更加复杂&#xff0c;也会更贵一点&#xff01; 1、CCD工…

底层全部重构,小米澎湃OS完整系统架构公布

上周&#xff0c;雷军发文称小米全新操作系统澎湃 OS 正式版已完成封包&#xff0c;将逐步接替 MIUI。而后&#xff0c;又有网友曝光小米澎湃 OS 界面。 今日&#xff0c;雷军再度发表长文预热小米澎湃 OS&#xff0c;正式公布了完整系统架构。 据介绍&#xff0c;从架构设计之…

统计学习方法 决策树

文章目录 统计学习方法 决策树决策树模型与学习特征选择决策树的生成ID3 算法C4.5 的生成算法 决策树的剪枝CART 算法CART 回归树的生成CART 分类树的生成CART 剪枝 统计学习方法 决策树 阅读李航的《统计学习方法》时&#xff0c;关于决策树的笔记。 决策树模型与学习 决策…

归结原理、归结演绎推理

主要内容 归结演绎推理范式子句与子句集将谓词公式转化为子句集命题逻辑鲁宾逊归结原理 归结演绎推理 定理证明的实质是对前提P和结论Q证明P →Q的永真性应用反证法&#xff0c;欲证明P →Q&#xff0c;只要证明 P∧~Q 等价于 F鲁宾逊归结原理对机械化推理有重大突破鲁宾逊归…

【Ansible自动化运维工具 1】Ansible常用模块详解(附各模块应用实例和Ansible环境安装部署)

Ansible常用模块 一、Ansible1.1 简介1.2 工作原理1.3 Ansible的特性1.3.1 特性一&#xff1a;Agentless&#xff0c;即无Agent的存在1.3.2 特性二&#xff1a;幂等性 1.4 Ansible的基本组件 二、Ansible环境安装部署2.1 安装ansible2.2 查看基本信息2.3 配置远程主机清单 三、…

windows PC virtualBox 配置

效果&#xff1a; oracle vitualbox 可以访问通PC主机&#xff0c;可以访问外网: 注意&#xff0c;如果docker0网络地址&#xff0c;和PC主机的网络地址冲突了&#xff0c;需要变更docker的网络地址&#xff1a; root/home/mysqlPcap/anti-tamper $ cat /etc/docker/daemon.js…

C语言找出一个二维数组中的鞍点,即该位置上的元素在该行上最大,在该列上最小,也可能没有鞍点

完整代码&#xff1a; /*找出一个二维数组中的鞍点&#xff0c;即该位置上的元素在该行上最大&#xff0c;在该列上最小&#xff0c;也可能 没有鞍点*/ #include<stdio.h> #include<stdlib.h> int main(){int n0;printf("请输入矩阵的行数:");scanf(&qu…

牛客网刷题-(7)

&#x1f308;write in front&#x1f308; &#x1f9f8;大家好&#xff0c;我是Aileen&#x1f9f8;.希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流. &#x1f194;本文由Aileen_0v0&#x1f9f8; 原创 CSDN首发&#x1f412; 如…

168. Excel表列名称

168. Excel表列名称 Java代码&#xff1a; 26进制&#xff0c;但是每个进制是从1开始的&#xff0c;不是从0开始&#xff1b;因此要计算要构建从0开始的求余&#xff01; class Solution {public String convertToTitle(int cn) {StringBuilder sb new StringBuilder();whi…

matlab中类的分别之handle类和value类——matlab无法修改类属性值的可能原因

写在之前&#xff08;吐槽&#xff09; 最近由于变化了一些工作方向&#xff0c;开始需要使用matlab进行开发&#xff0c;哎哟喂&#xff0c;matlab使用的我想吐&#xff0c;那个matlab编辑器又没代码提示&#xff0c;又没彩色&#xff0c;我只好用vscode进行代码编辑&#xf…

计算机网络【CN】介质访问控制

信道划分介质访问控制 FDMTDMWDMCDM【掌握eg即可】 随机介质访问控制 CSMA 1-坚持CSMA 非坚持CSMA p-坚持CSMA 空闲时 立即发送数据 立即发送数据 以概率P发送数据&#xff0c;以概率1-p推迟到下一个时隙 忙碌时 继续坚持侦听 放弃侦听&#xff0c;等待一个随机的时…

Centos使用war文件部署jenkins

部署jenkins所需要的jdk环境如下&#xff1a; 这里下载官网最新的版本&#xff1a; 选择jenkins2.414.3版本&#xff0c;所以jdk环境最低得是java11 安装java11环境 这里直接安装open-jdk yum -y install java-11-openjdk.x86_64 java-11-openjdk-devel.x86_64下载jenkins最新…

12种常见的恶意软件类型与防范建议

1、病毒 病毒是迄今为止最常见的恶意软件类型之一。它是一种能够感染、破坏计算机设备&#xff0c;并在其运行系统上自我复制的程序。由于病毒是自我复制的&#xff0c;一旦安装并运行&#xff0c;它们就可以在同一网络上自动从一台设备传播到另一台设备&#xff0c;无需人为干…

ARM汇编指令之数据操作指令

数据搬移指令&#xff1a;立即数&#xff1a;在待判断的32位数&#xff08;以十六进制展开&#xff09;中&#xff0c;寻找一个0~255&#xff08;即0x00~0xff&#xff09;之间的数值&#xff0c;然后将这个数值循环右移偶数个位置&#xff0c;可以得到待判断的数&#xff0c;即…

【期中复习】深度学习

文章目录 机器&#xff08;深度&#xff09;学习的四大核心要素为什么深度学习&#xff0c;不增加网络宽度黑盒模型的问题计算图线性神经网络梯度下降学习率优化方法softmax函数用于多分类交叉熵线性回归与softmax回归的对比为什么需要非线性激活函数感知机线性回归、softmax回…

2023版 STM32实战12 IIC总线读写AT24C02

IIC简述 一个多主从的串行总线&#xff0c;又叫I2C&#xff0c;是由飞利浦公司发明的通讯总线 IIC特点 -1- 串行(逐bit传输) -2- 同步(共用时钟线) -3- 半双工(收发不同进行) -4- 总线上的任何设备都可以是主机 开发使用习惯和理解 -1- 通过地址寻址 -2- 数据线的…

「网络编程」数据链路层协议_ 以太网协议学习

「前言」文章内容是数据链路层以太网协议的讲解。 「归属专栏」网络编程 「主页链接」个人主页 「笔者」枫叶先生(fy) 目录 一、以太网协议简介二、以太网帧格式&#xff08;报头&#xff09;三、MTU对上层协议的影响四、ARP协议4.1 ARP协议的作用4.2 ARP协议报头 一、以太网协…

基于单片机的IC卡门禁系统设计

收藏和点赞&#xff0c;您的关注是我创作的动力 文章目录 概要 一、主要研究内容及总体设计方案1.1 系统方案设计1.2系统工作原理 二、硬件设计2.1 主控电路 三、软件设计3.2主程序设计实物附录1 原理图附录2 源程序清单 四、 结论五、 文章目录 概要 本论文重点通过对射频技术…

小米14系列, OPPO Find N3安装谷歌服务框架,安装Play商店,Google

10月26号小米发布了新款手机小米14,那么很多大家需求问是否支持谷歌服务框架,是否支持Google Play商店gms。因为毕竟小米公司现在安装的系统是HyperOS澎湃OS。但是我拿到手机之后会发现还是开机初始界面会显示power by android,证明这一点他还是支持安装谷歌,包括最近一段时间发…

公司电脑如何限制安装软件

公司电脑如何限制安装软件 安企神终端管理系统下载使用 在企业环境中&#xff0c;电脑已经成为企业中必不可少的办公工具&#xff0c;确保员工的生产力和公司的信息安全是至关重要的。为了实现这一目标&#xff0c;公司可能会限制员工在某些情况下安装软件或者由管理员来为终…