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

news2024/11/28 2:31:48

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指针做形参。

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

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

相关文章

如何借助数据集更好的评估NLP模型的性能?

随着信息时代的迅猛发展&#xff0c;每天有无数文本、声音、图片和视频不断涌入互联网。如何从海量数据中提炼有意义信息成为学术界和工业界迫切需要解决的问题。在此背景下&#xff0c;自然语言处理&#xff08;NLP&#xff09;应运而生&#xff0c;成为人工智能领域最为活跃的…

python基础语法(十一)

目录 文件文件是什么文件路径文件操作1. 打开文件关闭文件写文件读文件 关于中文的处理使用上下文管理器 感谢各位大佬对我的支持,如果我的文章对你有用,欢迎点击以下链接 &#x1f412;&#x1f412;&#x1f412;个人主页 &#x1f978;&#x1f978;&#x1f978;C语言 &…

串行原理编程,中文编程工具中的串行构件,串行连接操作简单

串行通信原理编程&#xff0c;中文编程工具中的串行通信构件&#xff0c;串行通信连接设置简单 编程系统化课程总目录及明细&#xff0c;点击进入了解详情。https://blog.csdn.net/qq_29129627/article/details/134073098?spm1001.2014.3001.5502 串行端口 是串行的基础&#…

第22天:time模块与datetime模块

time模块 时间的三种格式&#xff1a; 1. 时间戳&#xff1a;从1970年1月1号到现在的秒数&#xff0c;他是一个数字 2. 结构化时间: 不是让我们看的&#xff0c;让计算机看的&#xff0c;他是时间之间相互转换的时候的中间桥梁 3. 格式化时间&#xff1a;就是符…

【贝叶斯回归】【第 1 部分】--pyro库应用

Bayesian Regression - Introduction (Part 1) — Pyro Tutorials 1.8.6 documentation 一、说明 我们很熟悉线性回归的问题&#xff0c;然而&#xff0c;一些问题看似不似线性问题&#xff0c;但是&#xff0c;用贝叶斯回归却可以解决。本文使用土地平整度和国家GDP的关系数据…

栈、共享栈、链式栈(C++实现)

文章目录 前言1. 栈的顺序存储&#xff08;顺序栈&#xff09;2. 栈的基本操作&#x1f351; 入栈操作&#x1f351; 出栈操作&#x1f351; 获取栈顶元素&#x1f351; 获取栈的长度&#x1f351; 判断是否为空栈&#x1f351; 判断栈是否满了&#x1f351; 打印栈内的元素&am…

『VUE2 - 车牌号软键盘』

一、需求描述 在 VUE2 Vant2 的项目中&#xff0c;实现 车牌号软键盘 的功能。 二、引入全局组件 引入封装好的 vant-number-plate 组件&#xff0c;整个文件夹放在 src/components 里面&#xff1a; git clone https://gitee.com/csheng-gitee/vant-number-plate.git三、具…

IMYAI-人工智能聊天绘画机器人4.0 - 终身学习者的超级生产力工具!

什么是ChatGPT&#xff1f;ChatGPT能帮我干什么&#xff1f; 在开始之前&#xff0c;我们首先需要知道ChatGPT是什么。 ChatGPT 全名Chat Generative Pre-trained Transformer (聊天生成性预训练转换模型) 说简单点&#xff0c;ChatGPT就是一个AI聊天机器人&#xff0c;背后是一…

Redis(08)| 线程模型

一、redis 的线程模型 redis 内部使用文件事件处理器 file event handler&#xff0c;它是单线程的&#xff0c;所以redis才叫做单线程模型。它采用IO多路复用机制同时监听多个 socket&#xff0c;将产生事件的 socket 压入内存队列中&#xff0c;事件分派器根据 socket 上的事…

Vue3.3指北(四)

Vue3.3指北 1、WebPack - VueCLI1.1、WebPack安装VueCli1.2、vue create 创建项目1.3、项目目录结构介绍 2、ViteVue32.1、认识create-vue2.2、使用create-vue创建项目2.3、项目目录剖析2.4、ESlint代码规范及手动修复2.5、通过eslint插件来实现自动修正 3、VueRouter43.1、单页…

SpringCloud 微服务全栈体系(七)

第九章 Docker 一、什么是 Docker 微服务虽然具备各种各样的优势&#xff0c;但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中&#xff0c;依赖的组件非常多&#xff0c;不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署&#xff0c;环境不一定一致…

基于SpringBoot的个人博客系统

基于SpringBootVue的个人博客系统的设计与实现~ 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringBootMyBatisVue工具&#xff1a;IDEA/Ecilpse、Navicat、Maven 系统展示 主页 系统公告 博客详情 后台发文 摘要 基于Spring Boot的个人博客系统是一种…

实用搜索小技巧——站在巨人的肩膀上看世界

文章目录 1. 关于搜索效率2. 谷歌搜索语法2.1 “” 限定关键词2.2 intitle 限定标题2.3 限定关键词限定标题2.4 allintitle 标题多个关键词2.5 intext 限定内容关键词2.6 inurl 限定网址关键词2.7 site 限定网址来源2.8 imagesize 限定图片尺寸2.9 filetype 限定文件格式 3. in…

8.自定义组件布局和详解Context上下文

pages/index.vue layout布局运行在服务端 1、在项目的目录下新建layout文件夹&#xff0c;并新建一个blog.vue布局文件 2、在页面中的layout函数里&#xff0c;返回刚才新建布局文件的名字blog就可以使用了 export default {...layout (context) {console.log(context)retu…

探索Vue 3和Vue 2的区别

目录 响应式系统 性能优化 Composition API TypeScript支持 总结 Vue.js是一款流行的JavaScript框架&#xff0c;用于构建用户界面。Vue 3是Vue.js的最新版本&#xff0c;相较于Vue 2引入了许多重大变化和改进。在本文中&#xff0c;我们将探索Vue 3和Vue 2之间的区别。 …

【中国知名企业高管团队】系列50:荣耀手机

今天为您介绍中国手机的一个“新势力”——荣耀。说是“新”是因为他单独运作的时间最短&#xff0c;说他“势力”是因为他的崛起自带光环&#xff0c;市场拓展和发展让OPPO、VIVO和小米都感到巨大的压力&#xff0c;可以说中国市场的大部分份额都被苹果、华为、OPPO、VIVO、小…

图解java.util.concurrent并发包源码系列——深入理解ConcurrentHashMap并发容器,看完薪水涨一千

图解java.util.concurrent并发包源码系列——深入理解ConcurrentHashMap并发容器 HashMap简单介绍HashMap在并发场景下的问题HashMap在并发场景下的替代方案ConcurrentHashMap如何在线程安全的前提下提升并发度1.71.8 JDK1.7的ConcurrentHashMap源码JDK1.8的ConcurrentHashMap源…

2016年上半年上午易错题(软件设计师考试)

以下媒体文件格式中&#xff0c;&#xff08; 12 &#xff09;是视频文件格式。 A &#xff0e; WAV B &#xff0e; BMP C &#xff0e; MP3 D&#xff0e;MOV 以下软件产品中&#xff0c;属于图像编辑处理工具的软件是&#xff08; 13 &#xff09;。 A &#xff0e; Po…

Flask 路由机制分析之一

一、前言 《Flask Run运行机制剖析》这篇我们讲了应用启动的内部机制&#xff0c;启动后就开始监听Http请求了&#xff0c;请求过来如何跳到对应的函数执行&#xff0c;这就是路由机制。我们沿用上一篇例子&#xff0c;来探究一下app.route("/")内部干了些什么事。 …

2017年上半年上午易错题(软件设计师考试)

CPU 执行算术运算或者逻辑运算时&#xff0c;常将源操作数和结果暂存在&#xff08; &#xff09;中。 A &#xff0e; 程序计数器 (PC) B. 累加器 (AC) C. 指令寄存器 (IR) D. 地址寄存器 (AR) 某系统由下图所示的冗余部件构成。若每个部件的千小时可靠度都为 R &…