详解C++类和对象(下)完结篇

文章目录

  • 写在前面
  • 1. 进一步认识构造函数
    • 1.1 初始化列表
    • 1.2 初始化列表的特性
    • 1.3 explicit关键字
  • 2. static成员变量和static成员函数
    • 2.1 static成员的概念
    • 2.2 static成员的特性
  • 3. 友元
    • 3.1 友元函数
    • 3.1 友元类
  • 4. 内部类
  • 5.匿名对象

写在前面

本篇文章详细介绍了C++类和对象中几个重要的概念和特性,包括初始化列表、Static成员、内部类等,下面我们来一一介绍它们。

1. 进一步认识构造函数

通过上篇文章的介绍,我们知道在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值。

class Date
{
public://构造函数Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}private:int _year;int _month;int _day;
};

虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值
在这里插入图片描述
因此,为了给成员变量一个定义初始化的地方,C++规定了成员变量在初始化列表中进行初始化。

1.1 初始化列表

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

1.2 初始化列表的特性

  1. 每个成员变量在初始化列表中只能出现一次(初始化只能初始化一次)。
    在这里插入图片描述

  2. 类中包含以下成员,必须放在初始化列表位置进行初始化。
    引用成员变量
    const成员变量
    自定义类型成员(且该类没有默认构造函数时)
    在这里插入图片描述

  3. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,
    一定会先使用初始化列表初始化。
    在这里插入图片描述
    上篇文章中提到的在成员变量声明的时候给初始值,如果我们没有使用初始化列表,这个初始值就会在初始化列表的地方使用。
    在这里插入图片描述

  4. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。
    我们来思考一下下面代码的运行结果是什么?

#include <iostream>
using namespace std;class A
{
public:A(int a = 1):_a1(a), _a2(_a1){}void Print(){cout << " _a1 = " << _a1 << ' ' << " _a2 = " << _a2 << endl;}
private:int _a2;int _a1;
};int main()
{A a;a.Print();return 0;
}

运行结果:
在这里插入图片描述
我们不禁会发出疑问,为啥_a2的值是随机值呢?
下面我们来分析一下:
在这里插入图片描述

1.3 explicit关键字

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

例如下面这种情况:
在这里插入图片描述
如果不想发生上述的类型转换,可以使用explicit修饰构造函数,将会禁止构造函数的隐式转换

#include <iostream>
using namespace std;class Date
{
public:/*explicit Date(int year = 1900):_year(year){}*/explicit Date(int year, int month = 1, int day = 1):_year(year),_month(month),_day(day){}Date& operator=(const Date& d){//检查是否是自己给自己赋值if (this != &d){_year = d._year;_month = d._month;_day = d._day;}}
private:int _year;int _month;int _day;
};int main()
{//Date d = 2024;return 0;
}

在这里插入图片描述

2. static成员变量和static成员函数

2.1 static成员的概念

在C++中,static 关键字可以用于声明类的成员变量和成员函数,使它们成为类的静态成员。静态成员属于类本身,而不是类的对象,因此所有属于该类的对象共享同一个静态成员。

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

2.2 static成员的特性

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区。
    在这里插入图片描述

  2. 静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明。
    在这里插入图片描述

  3. 类静态成员即可用类名::静态成员或者对象.静态成员来访问。
    在这里插入图片描述

  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员。
    在这里插入图片描述

  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制。
    在这里插入图片描述

通过上面的介绍,我们来思考下面两个问题:
静态成员函数可以调用非静态成员函数吗?
非静态成员函数可以调用类的静态成员函数吗?
在这里插入图片描述

3. 友元

在 C++ 中,友元是一种机制,允许某些非成员函数或外部类访问一个类的私有成员。通过友元关系,外部函数或类可以直接访问另一个类的私有成员,而无需通过公有接口。友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。
友元分为:友元函数友元类

3.1 友元函数

之前我们想打印Date类的成员,是需要自己实现一个Print函数。那能不能使得Date类像内置类型一样,使用cout实现呢?
答案是可以的,这里重载一下流插入(<<)操作符就可以实现。
在这里插入图片描述
下面我们来重载一下Date类的流插入(<<)操作符。

#include <iostream>
using namespace std;class Date
{
public:Date(int year = 1900, int month = 1, int day = 1):_year(year), _month(month), _day(day){}//重载一下流插入<<操作符ostream& operator<<(ostream& out){out << _year << '/' << _month << '/' << '_day' << endl;return out;}private:int _year;int _month;int _day;
};int main()
{Date d1(2024, 2, 7);Date d2(2024, 2, 8);cout << d1 << d2 << endl;return 0;
}

现在有个问题:现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数。运行上面代码报错。
在这里插入图片描述

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

此时就需要友元来解决。operator>>同理。友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字
在这里插入图片描述
友元函数特性:

  1. 友元函数可访问类的私有和保护成员,但不是类的成员函数。
  2. 友元函数不能用const修饰。因为友元函数不是类的成员函数,且没有隐藏的this指针,而const是修饰类的成员函数,修饰的是this指针。
  3. 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
  4. 一个函数可以是多个类的友元函数。
  5. 友元函数的调用与普通函数的调用原理相同。

3.1 友元类

友元类是指在类中通过 friend 关键字声明的外部类,外部类可以访问该类的私有成员和受保护成员
在这里插入图片描述
现在将友元声明注释掉,编译器就会报错。
在这里插入图片描述

友元类特性:

  1. 友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员
  2. 友元关系是单向的,不具有交换性。比如上述A类和B类,在B类中声明A类为其友元类,那么可以在A类中直接访问B类的私有成员变量,但想在B类中访问A类中私有的成员变量则不行。友元关系不能传递如果C是B的友元, B是A的友元,则不能说明C时A的友元。
  3. 友元关系不能继承,在继承位置再给大家详细介绍。

4. 内部类

如果在一个类定义在另一个类的内部这个内部类就叫做内部类。内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员外部类对内部类没有任何优越的访问权限
注意:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元
在这里插入图片描述
内部类特性:

  1. 内部类可以定义在外部类的public、protected、private都是可以的,但是受类域和访问限定符的限制。
    在这里插入图片描述

  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。

  3. sizeof(外部类)=外部类,和内部类没有任何关系。
    在这里插入图片描述

5.匿名对象

匿名对象的概念:
匿名对象是指在不使用变量名的情况下创建的临时对象,它在创建后立即被使用,通常用于简化代码或执行一次性操作。匿名对象可以在需要对象的地方直接创建并使用,而无需定义变量名。

那么我们该如何定义一个匿名对象呢?
在这里插入图片描述
匿名对象的特性:

  1. 定义匿名对象的时候不用给对象取名字。
  2. 生命周期只在定义的一行,程序执行到下一行他就会自动调用析构函数。
    在这里插入图片描述

匿名对象使用场景:
匿名对象在这样场景下就很好用,当然还有一些其他使用场景,这个我们以后遇到了再说。
在这里插入图片描述

至此,本片文章就结束了,若本篇内容对您有所帮助,请三连点赞,关注,收藏支持下。

创作不易,白嫖不好,各位的支持和认可,就是我创作的最大动力,我们下篇文章见!

如果本篇博客有任何错误,请批评指教,不胜感激 !!!
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vector类的模拟实现

实现基本的vector框架 参考的是STL的一些源码&#xff0c;实现的vector也是看起来像是一个简略版的&#xff0c;但是看完能对vector这个类一些接口函数更好的认识。 我们写写成员变量&#xff0c;先来看看STL的成元变量是那些 namespace tjl {template<class T>class …

作业2.7

C基础补习测试题 一、选择题&#xff08;每题2分&#xff0c;共 50 分&#xff09; C语言中&#xff0c;运算对象必须是整型数的运算符是 A 。 A、% B、/ C、%和/ D、* 若有关系x≥y≥z,应使用 A C语言表达式。 A、(x>y)&&(y>z)…

python环境配置(操作简单)

文章目录 下载文件链接过时请私信我 安装python3.9.0下载安装步骤安装python3.9.0步骤 安装pyCharm2023.3.3下载链接安装方法 激活激活链接激活方法 创建项目出现问题 下载文件 链接过时请私信我 链接&#xff1a;https://pan.baidu.com/s/1ORuhvSbBoTxeQfnYhOuiFA?pwd3oan …

Java应用中各类环境变量的优先级及最佳实践

1.引言 Java应用程序的开发和部署过程中&#xff0c;合理利用各类环境变量是关键之一。不同类型的环境变量&#xff0c;如系统环境变量、进程级环境变量、Java启动参数设置的系统属性以及Spring Boot配置文件中的环境变量&#xff0c;它们之间存在优先级差异。 深入理解这些环…

第1章 认识Flask

学习目标 了解Flask框架&#xff0c;能够说出Flask框架的发展史以及特点 熟悉隔离Python环境的创建方式&#xff0c;能够独立在计算机上创建隔离的Python环境 掌握Flask的安装方式&#xff0c;能够独立在计算机上安装Flask框架 掌握PyCharm配置隔离环境的方式&#xff0c;能…

27/100两数相除(位移todo)

题目 27/100两数相除 给你两个整数&#xff0c;被除数 dividend 和除数 divisor。将两数相除&#xff0c;要求 不使用 乘法、除法和取余运算。 整数除法应该向零截断&#xff0c;也就是截去&#xff08;truncate&#xff09;其小数部分。例如&#xff0c;8.345 将被截断为 8 …

【新书推荐】6.4节 标志寄存器

本节内容&#xff1a;8086 CPU内的标志寄存器FLAG为16位寄存器。本节我们将讲述FLAG寄存器各个标志位的使用方法。 ■标志寄存器的标志位&#xff1a;标志位可以分为6个状态标志位和3个控制标志位&#xff0c;此外还有7个保留的标志位。状态标志位用来记录算术逻辑运算的结果。…

C# CAD交互界面-自定义面板集(四)

运行环境 vs2022 c# cad2016 调试成功 一、引用 using Autodesk.AutoCAD.Runtime; using Autodesk.AutoCAD.Windows; using System.Windows.Forms; 二、程序说明 创建自定义面板集&#xff08;PaletteSet&#xff09;的C#命令方法实现。该方法名为CreatePalette&#xff…

Nacos(2)

Nacos部署 服务器端docker部署&#xff08;需要服务器安装好docker&#xff09; 导入sql文件到服务器编写nacos配置文件custom.env&#xff08;示例如下&#xff0c;改为自己服务器nacos相关信息&#xff09; PREFER_HOST_MODEhostname MODEstandalone SPRING_DATASOURCE_PL…

Git介绍和常用命令说明

目录 一、Git概述 1.1 Git是什么 1.2 Git有什么用 1.3 Git仓库介绍 二、Git下载与安装 三、Git代码托管服务&#xff08;远程仓库&#xff09; 四、Git常用命令 4.1 设置用户信息 4.2 获取Git仓库 4.2.1 本地初始化Git仓库 4.2.2 从远程仓库克隆 4.3 本地仓库操作 …

CentOS7如何安装宝塔面板并实现固定公网地址远程访问

文章目录 一、使用官网一键安装命令安装宝塔二、简单配置宝塔&#xff0c;内网穿透三、使用固定公网地址访问宝塔 宝塔面板作为建站运维工具&#xff0c;适合新手&#xff0c;简单好用。当我们在家里/公司搭建了宝塔&#xff0c;没有公网IP&#xff0c;但是想要在外也可以访问内…

电力负荷预测 | 基于AE-LSTM的电力负荷预测(Python)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 电力负荷预测 | 基于AE-LSTM的电力负荷预测(Python) 基于AE-LSTM(自动编码器长短期记忆网络)的电力负荷预测是一种基于深度学习的方法,用于预测未来一段时间内的电力负荷需求。该方法结合了自动编码器和LSTM网…