C++入门篇2---类和对象(上)

news2024/11/18 19:58:59

看前须知:何为面向对象?

面向对象(Object-oriented)是一种计算机编程的方法论和编程范式。面向对象的核心思想是将数据(对象)和操作(方法)封装在一起,形成一个相互关联和相互作用的实体,这些实体被称为对象。每个对象都具有自己的特性(属性)和行为(方法),并且能与其他对象进行交互。

面向对象编程的主要特征包括:

1. 封装:将数据和操作封装在一个对象中,使得对象的内部状态对外部是隐藏的,只能通过对象提供的公共接口进行访问和操作。

2. 继承:通过继承机制,一个对象可以从另一个对象上继承属性和方法。继承能够提供代码的重用性和扩展性,使得新的对象可以基于已有对象进行扩展和修改。

3. 多态:多态性使得对象可以根据上下文的不同拥有多种形态和行为。通过多态,同一种方法可以在不同的对象上呈现出不同的行为。

(上面这些仅作为了解接口,不影响下面的阅读,以后会陆续更新相关内容,敬请关注)

1.类的引入

由于C++是一门面向对象的语言,所以引入了类这个概念,从实现上来说,类就是C语言中结构体的升级,使得结构体里不仅能定义成员变量,还能定义成员函数,举个例子

struct Date {
	int _year;
    int _month;
    int _day;
    void Print(){
        cout<<_year<<'/'<<_month<<'/'<<_day<<endl;
    }
    void Init(int year,int month,int day){
        _year=year;
        _month=month;
        _day=day;
    }
};

当然,C++里更习惯用class做类如下,上面的代码之所以能运行主要是为了兼容C语言

class Date {
	int _year;
    int _month;
    int _day;
    void Print(){
        cout<<_year<<'/'<<_month<<'/'<<_day<<endl;
    }
    void Init(int year,int month,int day){
        _year=year;
        _month=month;
        _day=day;
    }
};

好,上面给大家见识过了类的相关实现,那么类的定义是什么?

2.类的定义

class ClassName{

    //类体:有成员变量和成员函数构成

};//注意,这里和结构体一样不能忘记;

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

类的两种定义方式

1.将定义和声明放在类里面,注意:成员函数放在类里面定义,编辑器可能将其当作内联函数

class Date {
	int _year;
    int _month;
    int _day;
    void Print(){
        cout<<_year<<'/'<<_month<<'/'<<_day<<endl;
    }
    void Init(int year,int month,int day){
        _year=year;
        _month=month;
        _day=day;
    }
};

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

//.h文件
class Date {
	int _year;
    int _month;
    int _day;
    void Print();
    void Init(int year,int month,int day);
};
//.cpp文件
void Date::Print(){
    cout<<_year<<'/'<<_month<<'/'<<_day<<endl;
}

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

还有就是要注意一下成员变量命名规则,尽量不要和参数重名

3.类的访问限定符及封装

访问限定符

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

访问限定符一共有pulic(共有),protected(保护),private(私有)三种

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

注意:访问限定符只在编译时有用,当数据映射到内存后,没有任何访问限定符上的区别

封装

封装:将数据和操作数据的方法进行有机结合,隐藏对象的属性和实现细节,仅对外公开接口来
和对象进行交互

4.类的实例化(用类类型创建对象的过程)

这里对类的使用可以参照结构体,引用成员函数和成员变量都是一样的用 ' . '

class Date {
private:
	int _year;
	int _month;
	int _day;
public:
	void Print(){
        cout<<_year<<'/'<<_month<<'/'<<_day<<endl;
    }
    void Init(int year,int month,int day){
        _year=year;
        _month=month;
        _day=day;
    }
};

int main() {
    Date x;
    //x._year=10;//这样赋值是错误的,要注意变量的访问限定符,private不允许我们在类外引用成员变量
    x.Init(2023,7,28);//而public修饰的函数是可以在类外调用的
    x.Print();
	return 0;
}

那么,问一个问题,类的定义占用空间吗???

我们都知道结构体作为自定义类型不占用空间,只有用结构体创建的对象才会开辟空间,那么同理,作为结构体升级版的类当然也不占用空间,类仅仅是对对象的一种描述(相对结构体更加的具体),是一种模型一样的东西,是不占用空间的,只有用它来定义变量时才会开空间

那么下一个问题,这个空间开多大呢???

由于它和结构体的相似性,我们和容易想到内存对齐,但是还有一点要考虑,成员函数的大小怎么算呢?或者成员函数算作是类定义的变量的大小吗?从节省内存的角度来说,成员函数就不该算作类的大小,因为每一个用类定义的变量,都可以调用成员函数,也就是说成员函数是公用的,但是每个成员变量的值却是不同的,因此,我们就可以大胆的猜测成员函数不算做类变量的大小,下面我们来验证一下猜想

int main() {
	Date d;
	cout << sizeof(d) << endl;
	return 0;
}

 Date类的成员变量按照内存对齐来说大小确实是12字节,符合要求,猜想正确,当然有兴趣的老铁可以自己创建个类来算算,当然忘记内存对齐的可以去回顾一下自定义类型,这篇里面详细讲了结构体的内存对齐的原则,这里就不多废话了

总结:类定义的变量的大小由成员变量决定,而成员函数储存在公共代码区,供大家使用

5.this指针

class Date {
private:
	int _year;
	int _month;
	int _day;
public:
	void Print(){
        cout<<_year<<'/'<<_month<<'/'<<_day<<endl;
    }
    void Init(int year,int month,int day){
        _year=year;
        _month=month;
        _day=day;
    }
};

int main() {
    Date x;
    x.Init(2023,7,28);
    x.Print();
	return 0;
}

在上诉的代码中,其实有一个疑问,为什么成员函数能够给x对象里面的成员变量进行初始化和打印?本质其实是因为编辑器自动将x对象的地址当作参数传给了函数,而函数的参数其实也比我们看到的多了一个this指针,这些步骤都是编辑器默认做的,不需要我们进行操作,也不允许我们进行这种显式传参

class Date {
private:
	int _year;
	int _month;
	int _day;
public:
    //void Print(Date*const this)---编辑器的处理,我们不能这么写
	void Print(){
        cout<<_year<<'/'<<_month<<'/'<<_day<<endl;
    }
    //void Init(Date*const this,int year,int month,int day)---编辑器的处理,我们不能这么写
    void Init(int year,int month,int day){
        _year=year;//也可以这么写:this->_year=year
        _month=month;//this->_month=month
        _day=day;//this->_day=day
    }
};

int main() {
    Date x;
    x.Init(2023,7,28);//x.Init(&x,2023,7,28)---编辑器的处理,我们不能这么写
    x.Print();//x.Print(&x)---编辑器的处理,我们不能这么写
	return 0;
}

总结:

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


这里有个题目考考大家

// 下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	void Print()
	{
		cout << "Print()" << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->Print();
	return 0;
}
// 下面程序编译运行结果是? A、编译报错 B、运行崩溃 C、正常运行
class A
{
public:
	void PrintA()
	{
		cout << _a << endl;
	}
private:
	int _a;
};
int main()
{
	A* p = nullptr;
	p->PrintA();
	return 0;
}

相信很多人会被误导,觉得空指针的解引用会导致运行崩溃,所以两题都选B,那么恭喜你蒙对一题,第二题被你蒙对了。

好,那么我们来看看这两题到底怎么思考,第一题,由于成员函数是在公共代码区,所以调用函数没必要对p进行解引用,其实只要知道指针的类型和函数名编辑器就能得到函数的地址进行调用,所以这里是不会发生解引用操作的,所以第一题正常运行,选A                                                        第二题,和第一题的区别在于打印的是成员变量,那么要找到成员变量,我们就需要知道对象的地址,而很显然我们传的地址是nullptr ( p->Print() <=> p->Print(p), 编辑器自动传参),这里才是对空指针的解引用,而不是我们认为的p的解引用出错,选B

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

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

相关文章

Diffusion mdoel: Denoising Diffusion Probabilistic Models论据解读及实现(一)

论文地址&#xff1a;https://arxiv.org/pdf/2006.11239.pdf 1 正向加噪推导 **核心公式1 ** x t α ˉ t ∗ x 0 1 − α ˉ t z t x_t\sqrt{\bar \alpha_t}*x_{0}\sqrt{1-\bar \alpha_t}z_t xt​αˉt​ ​∗x0​1−αˉt​ ​zt​ 证明如下&#xff1a; α t 1 − β…

芯片制造详解.刻蚀原理.学习笔记(五)

本篇笔记是看完原视频后的整理和补充&#xff0c;建议各位观看原视频&#xff0c;这里附上地址。 如何雕刻芯片&#xff1a;刻蚀原理&#xff5c;芯片制造详解05 芯片制造详解.刻蚀原理.学习笔记 五 一、刻蚀技术的分类二、刻蚀中三个关键指标2.1 刻蚀速率2.2 选择比2.3 方向性…

linux配置固定ip

为什么要固定ip&#xff1f; 虚拟机是利用DHCP&#xff08;动态获取ip&#xff09;&#xff0c;ip地址会频繁变化&#xff0c;不利于远程连接linux&#xff0c;同时会改变映射关系。 VMware 第一步&#xff1a;在workstation中配置IP地址网关和网段 1.点击虚拟网络编辑器 …

RISCV - 4 ISA 扩展名命名约定

RISCV - 4 ISA 扩展名命名约定 1 Case Sensitivity2 Base Integer ISA3 Instruction-Set Extension Names4 Version Numbers5 Underscores6 Additional Standard Extension Names7 Supervisor-level Instruction-Set Extensions8 Hypervisor-level Instruction-Set Extensions9…

28_计算机网络(Computer Networks)基础

本篇介绍计算机网络的基础知识。 文章目录 1. 计算机网络历史2. 以太网" (Ethernet)2.1 以太网" (Ethernet)的简单形式及概念2.2 指数退避解决冲突问题2.3 利用交换机减少同一载体中设备2.4 互联网&#xff08;The Internet&#xff09;2.5 路由(routing)2.6 数据包…

【Spring AOP + 自定义注解 + 动态数据源 实现主从库切换读写分离】—— 案例实战

&#x1f4a7; S p r i n g A O P 主从数据源切换 读写分离 自定义注解案例实战&#xff01; \color{#FF1493}{Spring AOP 主从数据源切换 读写分离 自定义注解 案例实战&#xff01;} SpringAOP主从数据源切换读写分离自定义注解案例实战&#xff01;&#x1f4a7; …

第三课:运算符

1.算数运算符 int a 20; int b 10; System.out.println(a b); // 30 System.out.println(a - b); // 10 System.out.println(a * b); // 200 System.out.println(a / b); // 2 System.out.println(a % b); // 0 --->模运算相当于数学中除法的余数 ⚠关于/除法 public s…

QEMU源码全解析19 —— QOM介绍(8)

接前一篇文章&#xff1a;QEMU源码全解析18 —— QOM介绍&#xff08;7&#xff09; 本文内容参考&#xff1a; 《趣谈Linux操作系统》 —— 刘超&#xff0c;极客时间 《QEMU/KVM》源码解析与应用 —— 李强&#xff0c;机械工业出版社 特此致谢&#xff01; 上一回讲到了Q…

2023 云原生编程挑战赛火热报名中!导师解析 Serverless 冷启动赛题

大赛介绍 第四届云原生编程挑战赛&#xff0c;是由阿里云主办&#xff0c;云原生应用平台、天池联合承办的云原生著名品牌赛事。 自 2015 年开始&#xff0c;大赛已经成功举办了八届&#xff0c;并从 2020 年开始升级为首届云原生编程挑战赛&#xff0c;共吸引了超过 53000 支…

python爬虫基本功(三)--爬虫所需网络协议知识超详细总结(下)

前言 大家好&#xff0c;这里是Kaiser&#x1f44f;。本文内容是衔接 &#x1f449;python爬虫基本功(二)—爬虫所需网络协议知识超详细总结&#xff08;上&#xff09;&#x1f448; 一文&#xff0c;为达更好的阅读效果&#xff0c;以及防止知识点出现“断层”&#xff0c;使…

Java方法的使用(重点:形参和实参的关系、方法重载、递归)

目录 一、Java方法 * 有返回类型&#xff0c;在方法体里就一定要返回相应类型的数据。没有返回类型&#xff08;void&#xff09;&#xff0c;就不要返回&#xff01;&#xff01; * 方法没有声明一说。与C语言不同&#xff08;C语言是自顶向下读取代码&#xff09;&#…

数电基础知识学习笔记

文章目录&#xff1a; 一&#xff1a;逻辑门 1.逻辑门电路的分类 1.1 按逻辑&#xff08;逻辑门&#xff09; 1.1.1 逻辑定义 1.1.2 常见数字电路相关符号 1.1.3 电路图表示 1.1.4 逻辑门电路图像符号 1.2 按电路结构 1.3 按功能特点 2.高低电平的含义 3.常见的门…

给定长度值length,把列表切分成每段长度为length的N段列表,Kotlin

给定长度值length&#xff0c;把列表切分成每段长度为length的N段列表&#xff0c;Kotlin import kotlin.random.Randomfun main(args: Array<String>) {var source mutableListOf<String>()val end Random.nextInt(30) 1for (i in 0 until end) {source.add(i.…

[SV] 文件操作

Verilog 提供了很多对文件进行操作的系统任务。经常使用的系统任务主要包括&#xff1a; 文件开、闭&#xff1a;​$fopen​, ​$fclose​, ​$ferror​文件写入&#xff1a;​$fdisplay​, ​$fwrite​, ​$fstrobe​, ​$fmonitor​字符串写入&#xff1a;​$sformat​, ​$…

python结合tesseract-ocr识别汉字的训练库过程

一、安装python 例如&#xff0c;安装路径为&#xff1a;C:\rtkapp\python-3.8.0 二、安装opencv 三、安装tesseract-ocr 安装完成后&#xff0c;在系统环境变量path中&#xff0c;添加安装路径C:\rtkapp\Tesseract-OCR 四、打开python安装pytesseract 五、安装java运行环境…

TenserRT(四)在 PYTORCH 中支持更多 ONNX 算子

第四章&#xff1a;在 PyTorch 中支持更多 ONNX 算子 — mmdeploy 0.12.0 文档 PyTorch扩充。 PyTorch转换成ONNX&#xff1a; PyTorch有实现。PyTorch可以转化成一个或者多个ONNX算子。ONNX有相应算子。 如果即没有PyTorch实现&#xff0c;且缺少PyTorch与ONNX的映射关系&…

太猛了,靠“吹牛”过顺丰一面,月薪30K

说在前面 在40岁老架构师尼恩的&#xff08;50&#xff09;读者社群中&#xff0c;经常有小伙伴&#xff0c;需要面试美团、京东、阿里、 百度、头条等大厂。 下面是一个5年小伙伴成功拿到通过了顺丰面试&#xff0c;拿到offer&#xff0c;月薪30K。 现在把面试真题和参考答…

一起学算法(插入排序篇)

概念&#xff1a; 插入排序&#xff08;inertion Sort&#xff09;一般也被称为直接插入排序&#xff0c;是一种简单的直观的排序算法 工作原理&#xff1a;将待排列元素划分为&#xff08;已排序&#xff09;和&#xff08;未排序&#xff09;两部分&#xff0c;每次从&…

Python毕业设计可用小游戏:5个热门类型,引爆学生热情!每个类型附单独案例!

游戏大全 前言1.格斗技能类小游戏2.益智塔防类小游戏3.MMO类型游戏4.养成类游戏5.经济类游戏 总结 前言 大家好&#xff0c;我是辣条哥 在当今数字化时代&#xff0c;编程已经成为一项不可或缺的技能。而Python作为一门简洁易学的编程语言&#xff0c;正受到越来越多学生的青睐…

03_使用execle表生成甘特图

背景 每次排期都需要话很多时间 很可能排期还不对头 这时候需要一个表能看到 1.什么时候项目结束 开始 转阶段 2.当前手上的活能不能做完 当前阶段手上有多少活 3.产品经理每次修改完计划迅速排期 甘特图生成 execle表生成 1.需要使用亿图创建甘特图 2.把当前的甘特图数据进…