0基础入门C++之类和对象下篇

目录

      • 1.再谈构造函数
        • 1.1构造函数赋值
        • 1.2初始化列表
        • 1.3explicit关键字
      • 2.static成员
        • 2.1概念
        • 2.1静态成员变量
        • 2.2静态成员函数
        • 2.3特性
      • 3.匿名对象
      • 4.友元函数
        • 4.1友元函数
        • 4.2友元类
      • 5.内部类
      • 6.再次理解类和对象

1.再谈构造函数

首先我们先来回忆一下构造函数:

构造函数是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。即构造函数其实就是帮我们对类的成员变量赋一个初值。

1.1构造函数赋值

下面我们来看个例子:

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

虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为 初始化只能初始化一次,而构造函数体内可以多次赋值

下面我们再来看一个例子:

class T
{
private:int _T1;int _T2;
};

这里的int _T1; int _T2;是对成员变量_T1、 _T2的声明,在这里只是声明类里这样两个成员变量。

那定义又是在哪里呢?

这里是引用
这里是对对象整体的定义

那么对象的每个成员变量又是什么时候定义的呢?

我想这时老铁心里肯定这样想:变量整体定义了,它的成员不都也定义了吗?成员不都是属于这个对象的吗?

下面我们再看这个例子:

在这里插入图片描述
在这里我们发现程序无法正常运行,大家来想一下,const修饰的变量有什么特点?
是不是const修饰的变量必须在定义的时候初始化

我想这个时候大家一定想到了:

之前我们在讲解构造函数的时候说,C++11允许内置类型成员变量在类中声明的时候可以给缺省值
在这里插入图片描述
这里程序能够运行了

但是这是C++11才提出来的,那C++11之前呢?如何解决这样的问题呢?

所以我们必须要给成员变量也找一个定义的位置,不然像const这样的成员变量不好处理。

那么成员变量定义到底在哪里呢?

1.2初始化列表

面对上述问题,我们的祖师爷还是把目标锁定在了构造函数。
在构造函数里面呢又搞了一个东西叫做——初始化列表

初始化列表:以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号中的初始值或表达式

举个例子:

对于上面类中const int _a的初始化我们就可以放在初始化列表进行处理:

class T
{public:T(int t1, int t2, int a): _T1(t1), _T2(t2), _a(a){}
private:int _T1;int _T2;const int _a = 1;
};int main()
{T t(1,2,3);return 0;
}

注意:

  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)

这里是引用

  1. 以下三种类成员变量,必须放在初始化列表位置进行初始化:

引用成员变量

const成员变量

没有默认构造函数的自定义类型成员

这里不难理解,因为引用成员变量和const成员变量都必须在定义的时候初始化

对于没有默认构造函数的自定义类型成员:

因为默认生成的构造函数对内置类型不做处理,对自定义类型会去调用它对应的默认构造函数(不需要传参的构造函数都是默认构造函数),所以如果自定义类型成员没有默认构造函数我们就需要自己去初始化它。

  1. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,成员变量都会在初始化列表定义。

  2. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

1.3explicit关键字

我们先举个例子:

class T
{public:T(int t1): _T1(t1){}
private:int _T1;int _T2;};

我们可以用这种方式去创建对象:

int main()
{T t(1);return 0;
}

除此之外还可以这样:

int main()
{T t2 = 1;return 0;
}

这个地方T t2 = 1;,1是一个整型,怎么可以直接去初始化一个类对象呢?
其实这里是一个隐式类型转换。和内置类型之间的隐式类型转换转化是一样的,会产生一个临时变量

那这里T t2 = 1;是如何转换的呢?

这里也会产生一个临时变量,这个临时变量就是用1去构造出来的一个T类型的对象,然后再用这个临时对象去拷贝构造我们的t2。

下面我们用一个小例子证明一下:

class T
{public:T(int t1): _T1(t1){cout << "T(int t)" << endl;}T(const T& t): _T1(t._T1){cout << "T(const T& t)" << endl;}
private:int _T1;
};int main()
{T t2 = 1;return 0;
}

注意:拷贝构造函数也是有初始化列表的,因为拷贝构造函数是构造函数的一个重载形式
那我们现在运行程序,看T t2 = 1; 是不是先用1调构造函数创建一个临时变量,然后再调拷贝构造构造t2
在这里插入图片描述
这里确实调用了构造函数,但是并没有调用拷贝构造函数

那问题到底出在哪里了?

其实,C++编译器针对自定义类型产生临时变量的情况,会进行优化。编译器用1构造一个对象,然后再去调拷贝构造,效率受到影响,所以优化成一步,直接拿1去构造我们要创建的对象

当然,不一定所有的编译器都会优化,但是一般比较新一点的编译器在这里都会优化。

在这里想告诉大家的是:

构造函数不仅可以构造与初始化对象,对于单个参数或者除第一个参数无默认值其余均有默认值的构造函数,还具有类型转换的作用。

那如果我们这里不想让它支持类型转换了,有没有什么办法呢?

这就要用到一个关键字——explicit
我们只需在对应得构造函数前面加上explicit关键字:
在这里插入图片描述
在这里插入图片描述

对于单参数的构造函数是支持这种类型转换的,那多参数的构造函数呢?

这里C++98是不支持多参数的构造函数进行隐式类型转换的。但是C++11对这块进行了扩展,使得多参数的构造函数也可以进行隐式类型转换
在这里插入图片描述

2.static成员

2.1概念

声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用 static修饰的成员函数,称之为静态成员函数静态成员变量一定要在类外进行初始化

那么static成员有什么用呢? 我们先来看一个小题目:

实现一个类,计算程序中创建出了多少个类对象。

老铁们思考一下,可以怎么做?

首先要创建一个类对象,一定是通过构造函数或者拷贝构造创建的。那我们可以定义一个全局变量n,初值为0。然后每次调用构造函数或者拷贝构造创建对象时就让n++

但是这种方法真的好吗?

其实是不太好的,首先这里我们定义一个全局变量,首先它可能会发生命名冲突;其次,全局变量在哪都能访问(C++讲究封装)

我想这个时候老铁可能又想到一种方法:

我们把统计个数的这个n变量放到类里面,这样它就属于这个类域了,然后如果不想让它在类外面被访问到,我们可以把它修饰成私有的。

但是这种方法真的可行吗?

如果直接放到类里面,作为类的一个成员变量,那它就属于对象,但我们要统计程序中创建对象的个数,这样我们每次创建一个对象n就会定义一次,是不是不行啊,不能让它属于每个对象,应该让它属于整个类。

2.1静态成员变量

对于上述问题我们可以这样解决:

在它前面加一个static修饰,让它成为静态成员变量。那这样它就不再属于某个具体对象了,而是存储在静态区,为所有类对象所共享。规定静态成员变量的初始化(定义的时候赋初值)一定要在类外,定义时不添加static关键字,类中只是声明
在这里插入图片描述

2.2静态成员函数

静态成员函数有一个特性:静态成员函数没有隐藏的this指针,不能访问任何非静态成员
因为非静态成员是属于对象的,都是通过this指针去访问的,而静态成员函数是没有this指针的。

2.3特性

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区
  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明,静态成员变量一定要在类外进行初始化
  3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制

3.匿名对象

现在有这样一个类:

class T
{public:T(int t1 = 0): _T1(t1){cout << "T(int t)" << endl;}~T(){cout << "~T()" << endl;
private:int _T1;
};

我们现在想要用这个类去创建对象,除了我们之前学的方法之外,其实我们还可以这样创建对象:
在这里插入图片描述
这里我们用T这个类创建了一个匿名对象。
匿名对象的特点就是没有名字,但是它的生命周期只在创建它的这一行。

但是要注意,和临时变量一样,如果我们用匿名对象去初始化一个引用的话,它的生命周期就会被延长至该引用被销毁。并且这里肯定都要加const的,因为临时变量和匿名对象都具有常性。

那匿名对象有什么用呢?

现在有一个类Solution,里面有一个非静态成员函数Sum_Solution,我们知道想要调用类里面的非静态成员函数,是需要通过对象去调用的:
在这里插入图片描述

现在有了匿名对象,我们就可以这样调用了
在这里插入图片描述
在这里插入图片描述

4.友元函数

友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

友元分为:友元函数和友元类

4.1友元函数

在之前的类和对象的学习中我们讲过运算符重载:

现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要将operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。
在这里插入图片描述

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在 类的内部声明,声明时需要加friend关键字

说明:

  1. 友元函数可访问类的私有和保护成员,但不是类的成员函数
  2. 友元函数不能用const修饰
  3. 友元函数可以在类里面的任何地方声明,不受类访问限定符限制
  4. 一个函数可以是多个类的友元函数
  5. 友元函数的调用与普通函数的调用原理相同

4.2友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员

  1. 友元关系是单向的,不具有交换性。
  2. 友元关系不能传递

如果C是B的友元, B是A的友元,则不能说明C时A的友元

  1. 友元关系不能继承,在继承位置再给大家详细介绍。

5.内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。

比如这样:

class A
{
private:int a;
public:class B {private:int b;};
};

内部类并不属于外部类,它和对应的外部类是相互独立的,只是受外部类类域的限制
对于上面那个类来说,我们想拿A中的内部类B去创建对象,这样是不行的:
在这里插入图片描述

这样才行:
在这里插入图片描述

内部类天生就是其对应的外部类的友元类。参见友元类的定义,内部类可以通过外部类的对象参数来访 问外部类中的所有成员。但是外部类不是内部类的友元。

特性:

  1. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  3. sizeof(外部类)=外部类,和内部类没有任何关系。

6.再次理解类和对象

现实生活中的实体计算机并不认识,计算机只认识二进制格式的数据。如果想要让计算机认识现实生活中的实体,用户必须通过某种面向对象的语言,对实体进行描述,然后通过编写程序,创建对象后计算机才可以认识。比如想要让计算机认识洗衣机,就需要:

  1. 用户先要对现实中洗衣机实体进行抽象—即在人为思想层面对洗衣机进行认识,洗衣机有什么属性,有那些功能,即对洗衣机进行抽象认知的一个过程
  2. 经过1之后,在人的头脑中已经对洗衣机有了一个清醒的认识,只不过此时计算机还不清楚,想要让计算机识别人想象中的洗衣机,就需要人通过某种面相对象的语言(比如:C++、Java、Python等)将洗衣机用类来进行描述,并输入到计算机中
  3. 经过2之后,在计算机中就有了一个洗衣机类,但是洗衣机类只是站在计算机的角度对洗衣 机对象进行描述的,通过洗衣机类,可以实例化出一个个具体的洗衣机对象,此时计算机才能洗衣机是什么东西。
  4. 用户就可以借助计算机中洗衣机对象,来模拟现实中的洗衣机实体了。

在类和对象阶段,大家一定要体会到,类是对某一类实体(对象)来进行描述的,描述该对象具有哪些属性,哪些方法,描述完成后就形成了一种新的自定义类型,用然后用该自定义类型就可以实例化具体的对象
在这里插入图片描述

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

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

相关文章

付费上班,你听说过吗?

众所周知&#xff0c;打工人上班是要拿工资的&#xff0c;哪怕工资再少&#xff0c;也是对打工人劳动的报酬。 然而&#xff0c;最近职场上出现了一个新概念&#xff0c;叫做“付费上班”。什么意思呢&#xff1f;你在公司给老板打工&#xff0c;老板不但不需要给你钱&#xff…

推荐几个适合上班摸鱼的神操作!

俗话说“上班摸鱼一时爽&#xff0c;一直摸鱼一直爽”&#xff0c;"今天&#xff0c;你摸鱼了吗&#xff1f;" 人不是机器&#xff0c;在工作中难免会有疲劳的时候&#xff0c;据权威研究表明&#xff0c;人的专注忍耐极限是2小时&#xff08;我说自己怎么工作一会就…

花5分钟判断,你的Jmeter技能是大佬还是小白!

jmeter 这个工具既可以做接口的功能测试&#xff0c;也可以做自动化测试&#xff0c;还可以做性能测试&#xff0c;其主要用途就是用于性能测试。但是&#xff0c;有些公司和个人&#xff0c;就想用 jmeter 来做接口自动化测试。 你有没有想过呢&#xff1f; 下面我就给大家讲…

潮流玩具行业研究:肇始于童心,进阶于品牌

遍览海内外同行&#xff0c;我们认为依赖外部IP授权的模式难以诞生伟大的潮玩品牌&#xff0c;打造原创IP才是获得持久生命力与高利润率的进阶之路。原创潮玩公司需要积极开拓原创IP&#xff0c;实现从“个别潮玩形象”到“系列潮玩IP”&#xff0c;再到“潮流品牌IP”的三级跃…

361度:聚焦主业品牌加速升级,童装业务打造第二增长极

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;太平洋证券近期发布研报给予361度&#xff08;01361&#xff09;“买入”评级&#xff0c;太平洋证券在研报中称&#xff0c;361度作为国内第四大国产运动品牌&#xff0c;深耕大众运动市场20载&a…

直流无刷电机工作原理及有感方波控制

BLDC方波控制 BLDC工作原理BLDC换向驱动过程有感控制模式 BLDC工作原理 首先要知道&#xff0c;BLDC转起来是基于什么原理 BLDC包括定子&#xff08;线圈&#xff09;和转子&#xff08;永磁体&#xff09;&#xff0c;线圈要通电&#xff0c;通电的线圈具有磁场&#xff0c;该…

传统进销存软件上云势在必行

随着移动互联网的迅猛发展&#xff0c;云服务也是整个社会发展的趋势。传统进销存软件上云势在必行。云端进销存数据安全&#xff0c;操作方便快捷&#xff0c;大大提升工作效率&#xff0c;帮助老板随时随地做生意&#xff0c;也为以后扩大公司经营打好基础&#xff01; 传统软…

进销存软件选哪个好?

以前&#xff0c;在朱泽内金融行业&#xff0c;大多数的较大型企业管理都是纯手工历史记录&#xff0c;包括企业业务流程管理、财务管理记帐等。因为&#xff0c;很多较大型企业体量不大&#xff0c;人员有限&#xff0c;在组织工作职能的划分上也比较混乱&#xff0c;常常是一…

经销商如何挑选一款适合自己的进销存软件?

传统会展民营企业在互联网发展迅速的今天&#xff0c;如果不借助于高效率的控制系统展开网络化结构调整&#xff0c;是无法跟得上时代的步伐的&#xff0c;粗放式低效率的管理工作方式只会引致民营企业越来越困难&#xff0c;生产成本不断增加、销售收入不能获得提高&#xff0…

Excel打造进销存管理系统,让Excel自动化办公~

Excel打造进销存管理系统https://edu.csdn.net/course/detail/38573 进销存管理系统是一个综合性案例&#xff0c;融合函数&#xff0c;透视表&#xff0c;基本图表&#xff0c;宏&#xff0c;VBA&#xff0c;Microsoft Query&#xff0c;Power Query 从基础表格构建 &#xf…

openGauss学习笔记-52 openGauss 高级特性-LLVM

文章目录 openGauss学习笔记-52 openGauss 高级特性-LLVM52.1 适用场景52.2 非适用场景52.3 其他因素对LLVM性能的影响52.4 LLVM使用建议 openGauss学习笔记-52 openGauss 高级特性-LLVM openGauss借助LLVM&#xff08;Low Level Virtual Machine&#xff09;提供的库函数&…

vue2 自定义指令,插槽

一、学习目标 1.自定义指令 基本语法&#xff08;全局、局部注册&#xff09;指令的值v-loading的指令封装 2.插槽 默认插槽具名插槽作用域插槽 二、自定义指令 1.指令介绍 内置指令&#xff1a;v-html、v-if、v-bind、v-on… 这都是Vue给咱们内置的一些指令&#xff0c;…

Java“牵手”天猫商品快递费用API接口数据,天猫API接口申请指南

天猫平台商品快递费用接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取天猫商品的标题、价格、库存、商品快递费用&#xff0c;宝贝ID&#xff0c;发货地&#xff0c;区域ID&#xff0c;快递费用&#xff0c;月销量、总销量、库存、详情…

freenom php,Freenom免费域名.TK、.CF、.ML、.GA注册及使用方法

去年,Freenom网站来了个大改版,不仅网站页面进行了大幅度调整,更重要的是Freenom这次终于统一了.TK、.CF、.ML、.GA这四个免费域名账号的后台登录,原先.TK、.CF、.ML、.GA都有各自独立的账号系统,现在全部统一使用Freenom的后台账号管理系统。 改版后的Freenom实际上整合了…

<七> objectARX开发:创建自定义实体

1、介绍 在某些情况下,CAD中的实体对象无法满足需求,我们需要针对实际情况来设计并绘制自定义的实体,下面就用一个简单的例子来介绍一下自定义实体绘制。 实体形状:包括实体夹点和文字夹点拖动实现。 2、效果 3、创建自定义实体的步骤 新建一个从AcDbEntity继承的类,如C…

穷建站(二):在DnsPod中为申请的tk域名进行域名解析

文章目录 1 序2 DnsPod域名解析2.1 DnsPod网站账号注册2.2 在DnsPod中添加需要解析的域名 3 在Freenom中进行域名解析配置 1 序 在上一篇博文中&#xff1a;穷建站&#xff08;一&#xff09;&#xff1a;申请免费的tk顶级域名 博文中已经成功的申请了一个tk顶级域名&#xff…

最容易申请到的免费顶级域名.tk

TK与COM、NET、CN、TV一样同属顶级域名、是小国家域名、也是网络上最容易申请到的免费域名之一。 Dot TK网站提供免费和收费两种域名:免费域名必须保证在90天内有25次访问,否则将域名给收回。 免费注册的用户仅有其域名的使用权。只要您每九十天在您的域名名称里有活动一次,…

关于申请个人域名和虚拟主机---个人域名篇(.tk顶级域名)

本文介绍国外免费域名.tk的注册和部分使用,顶级域名哦 从这里注册.tk,打开后会是这个样子 填一个你想申请的域名,这里我填的测试域名是wokanxing.tk 填完后 go 当然可以用自己的DNS解析..但是我没有..而且主机屋的貌似不支持.tk的解析.最近我在问客服,等有进展再告诉大家 当…

TK域名首次注册教程(咸干花生)

http://wenku.baidu.com/link?urlrvRbl9BWNOSKnNffHy-u0TK9lJfZifPSnHdARGhT8oVuKaxU0fPX-QyEcH43KFinmJztbvEIRVabYw8sxK_5TEI6r2EGhsmORwSKVVKq0u_ http://wenku.baidu.com/link?urljUE7rnWFsm4UZ-58RckyFx63Vy7xNstOrfSXP12RKGIx57zOEcpOnH3rpIituAppG1YzYE-3-OhDN5jismEy…

穷建站(一):申请免费的tk顶级域名

文章目录 1 序2 注册免费的tk顶级域名 1 序 建一个个人网站我相信是很多人从初中甚至是高中开始就想做的一件事情&#xff0c;起码我是这样的。 在初中的时候第一次上网&#xff0c;我就很好奇网站到底是怎么建起来的&#xff0c;我们又是如何通过互联网去访问到我们的站点并成…