C++类和对象(下)(2)

一、友元

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

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

1.1 友元函数

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

class Date
{
public:Date(int year, int month, int day): _year(year), _month(month), _day(day){}ostream& operator<<(ostream& _cout){_cout << _year << " " << _month << " " << _day << endl;return _cout;}
private:int _year;int _month;int _day;
};int main()
{Date d1(2022, 1, 1);d1 << cout;//形式不符合常规调用return 0;
}

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

下面我们来看下友元函数的应用: 

class Date
{friend ostream& operator<<(ostream& _cout, const Date& d);friend istream& operator>>(istream& _cin, Date& d);
public:Date(int year = 2004, int month = 1, int day = 1):_year(year),_month(month),_day(day){}private:int _year;int _month;int _day;
};ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << " " << d._month << " " << d._day << endl;return _cout;
}istream& operator>>(istream& _cin, Date& d)
{_cin >> d._year >> d._month >> d._day;return _cin;
}int main()
{Date d1(2022, 1, 1);//d1 << cout;//形式不符合常规调用Date d;cin >> d;cout << d << endl;return 0;
}

注意:

1.友元函数可访问类的私有成员和保护成员 ,但它并不是类的成员函数

2.友元函数不能用const修饰

3.友元函数可以在类定义的任何地方声明,不受类的访问限定符限制

4.一个函数可以是多个类的友元函数

5.友元函数的调用原理和普通函数的调用原理相同

 2.2 友元类

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

注意:

1.友元的关系是单向的,不具有双向性

例如:下面的代码实例中Time类和Date类,在Time类中声明date类为其友元类,那么可以在Date类中直接访问Time类的私有成员函数,但想在Time类中访问Date类中私有的成员变量则不行。

2.友元关系不可传递

3.友元关系不能继承(关于继承方面以后再来进行介绍)

#include<iostream>
using namespace std;
class Time
{//将Date声明为Time的友元类friend class Date;
public:Time(int hour = 0, int minute = 0, int second = 0):_hour(hour),_minute(minute),_second(second){}private:int _hour;int _minute;int _second;
};class Date
{
public:Date(int year = 2004, int month = 1, int day = 1):_year(year), _month(month), _day(day){}void SetTimeofDate(int hour, int minute, int second){//声明成友元后,Date可以直接访问Time类内的私有和保护成员_t._hour = hour;_t._minute = minute;_t._second = second;}private:int _year;int _month;int _day;Time _t;
};

二、内部类

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

内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象来访问内部类的成员。外部类对于内部类没有任何优越的访问权限。但是内部类是其外部类的友元类内部类可以通过外部类的对象参数来访问外部类的所有成员,但是外部类不是内部类的友元。

也就是说内部类和外部类,它们两个类时独立的,平行的,内部类是个独立的类,放在外部类里面,仅仅受到类域的印象。而且内部类可以放在外部类的私有区,那样的话内部类就是外部类的专属类。

特性:

1.内部类可以定义在外部类的public,protected,private都是可以的

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

3.sizeof(外部类) = 外部类,和内部类没有任何关系

class A
{
private:static int k;int h;
public://B就是A的内部类,并且B是A的友元class B{public:void foo(const A& a){cout << k << endl;cout << a.h << endl;}};
};int A::k = 1;int main()
{A::B b;b.foo(A());return 0;
}

三、匿名对象

关于匿名对象我们先看下面的一段代码来感受一下:

class N
{
public://构造函数N(int a = 0):_a(a){cout << "N(int a)" << endl;}//析构函数~N(){cout << "~N()" << endl;}private:int _a;
};class Solution
{
public:int Sum_solution(int n){return n;}
};int main()
{/*A::B b;b.foo(A());*/N aa1;//不能像下面这样去定义对象,这样的话编译器会无法识别到底是函数声明还是对象定义//A aa1();//我们可以定义匿名对象,匿名对象特点就是不需要名字//但是它的声明周期就只要一行,过了定义的这一行就会直接调用析构函数销毁N();//匿名对象N aa2(2);//匿名对象在如下场景很好用,当然还有一些其他的使用场景Solution().Sum_solution(10);return 0;
}

注意:

1.匿名对象和拷贝时的临时变量都是具有常性的

2.匿名对象生命周期仅在这一行,执行之后就会直接调用析构函数销毁

 四、拷贝对象时的一些编译器优化

在传参和传返回值的过程中,一般编译器会做一些优化,减少对象的拷贝,也是减少了一些时间上的消耗。

在传值传参的时候,先要进行拷贝构造。

对于优化的具体实现这里不做解释,我们只需要记住一般编译器的优化规则:

f(1);

隐式类型,连续构造+拷贝构造->优化为直接构造

f1(A(2));

一个表达式中,连续构造+拷贝构造->优化为一个构造

A aa2 = f2();

一个表达式,连续拷贝构造+拷贝构造->优化为一个拷贝构造

aa1 = f2()

一个表达式中,连续拷贝构造+赋值重载->无法优化

这里的等号是赋值重载,拷贝构造和赋值重载在一起时不能优化的,建议尽量不要用以上写法。

 对于优化这部分到这里就介绍完了。

下面我再来对构造和析构的细节进行一些补充:

五、关于构造和析构的一些补充

1.构造和析构是在栈帧里面的满足先进后出,后进先出的规则,因此后定义的对象先析构,先定义的对象后析构(构造是先定义的先构造,后定义的后构造,构造就相当于入栈,析构是出栈)。

2.若为全局变量,main函数之前就构造了。

3.局部的静态变量在第一次调用的时候构造,第二次调用不会构造,只会初始化一次。

(静态变量只能初始化一次)

4.先构造全局,再构造静态,然后再试普通对象

结语:

关于类和对象的内容,至此就结束了,希望大家能从这几篇博客中对类和对象有更加深刻的认识,接下来会继续更新C++的内容。

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

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

相关文章

Pandas入门篇(二)-------Dataframe篇4(进阶)(Dataframe的进阶用法)(机器学习前置技术栈)

目录 概述一、复合索引&#xff08;一&#xff09;创建具有复合索引的 DataFrame1. 使用 set_index 方法&#xff1a;2.在创建 DataFrame 时直接指定索引&#xff1a; &#xff08;二&#xff09;使用复合索引进行数据选择和切片&#xff08;三&#xff09;重置索引&#xff08…

使用 Langchain、Langfuse、Nemo-gaurdrails、RAGAs构建 RAG 管道并进行监控和评估

原文地址:build-end-to-end-rag-pipeline-with-monitoring-and-evaluation-using-langchain-azure-ai-search 2024 年 4 月 21 日 介绍 使用现代的LLM框架,如Langchain或llamaindex,可以迅速搭建一个用于 RAG 的管道,通常只需编写大约5-6行代码。然而,若要构建一个适用于生…

【小浩算法 BST与其验证】

BST与其验证 前言我的思路思路一 中序遍历判断数组无重复递增思路二 递归边界最大值最小值的传递 我的代码测试用例1测试用例2 前言 BST是二叉树一个经典应用&#xff0c;我们常常将其用于数据的查找以及构建平衡二叉树等。今天我所做的题目是验证一颗二叉树是否为二叉搜索树&…

垃圾的flinkcdc

在 MySQL 中&#xff0c;创建表时使用反引号 将表名或字段名括起来的作用是&#xff1a; 保留字和关键字: 使用反引号可以避免使用MySQL的保留字和关键字作为表名或字段名时产生的冲突。比如&#xff0c;你可以创建一个名为 select 或 order 的表&#xff1a; sqlCopy Code C…

MATLAB实现果蝇算法优化BP神经网络预测分类(FOA-BP)

果蝇算法&#xff08;Fruit Fly Optimization Algorithm, FFOA&#xff09;是一种启发式优化算法&#xff0c;受果蝇觅食行为的启发。将其应用于优化BP神经网络&#xff0c;主要是为了寻找BP神经网络中的最佳权重和偏置值。以下是一个基本的流程&#xff1a; 初始化&#xff1a…

上班族小张的副业之路:下班后的水牛社赚钱故事

在快节奏的都市生活中&#xff0c;上班族小张每天忙碌于办公室与家庭之间&#xff0c;重复着朝九晚五的生活。然而&#xff0c;他内心总渴望寻找一种既能充实生活&#xff0c;又能增加收入的副业方式。直到有一天&#xff0c;他发现了水牛社——一个为他提供丰富副业资源和机会…

信息时代的智慧导航:高效搜索、信息筛选与信任构建的全面指南!

文章目录 一、高效搜索&#xff1a;快速定位目标信息的秘诀二、信息筛选&#xff1a;去伪存真&#xff0c;找到有价值的信息三、信任构建&#xff1a;深入了解与直接沟通《搜索之道&#xff1a;信息素养与终身学习的新引擎》亮点内容简介目录获取方式 随着科技的飞速发展&#…

jenkins汉化不完全问题解决

jenkins安装完Localization:Chinese(Simplified)中文语言包后&#xff0c;发现是出现汉化不完全或者部分汉化的情况&#xff0c;如下图&#xff1a; 解决方法&#xff1a; 启动命令中指定语言 -Duser.languageen_US.UTF-8 或者 -Duser.languageC.UTF-8原因分析&#xff1a;安…

网上招聘系统的设计与实现参考论文(论文 + 源码)

【免费】网上招聘系统的设计与实现.zip资源-CSDN文库https://download.csdn.net/download/JW_559/89251636 网上招聘系统的设计与实现 摘 要 随着时代的发展&#xff0c;中国的互联网技术愈加成熟&#xff0c;已经有越来越多的社会群体开始学会使用互联网技术&#xff0c;整个…

STM32定时器的OC比较和PWM

系列文章目录 STM32单片机系列专栏 C语言术语和结构总结专栏 文章目录 1. 输出比较(OC) 2. PWM 3. PWM的输出 3.1 高级定时器 3.2 通用定时器 4. PWM的输出结构 5. 代码示例 5.1 PWM.c 5.2 PWM.h 5.3 main.c 这篇文章解释了TIM定时器的内部时钟和外部时钟的使用&a…

头歌:Spark的安装与使用

第1关&#xff1a;Scala语言开发环境的部署 相关知识 Scala是一种函数式面向对象语言&#xff0c;它融汇了许多前所未有的特性&#xff0c;而同时又运行于JVM之上。随着开发者对Scala的兴趣日增&#xff0c;以及越来越多的工具支持&#xff0c;无疑Scala语言将成为你手上一件…

SpringBoot 循环引用解决办法

Spring 原生是允许并解决了单层循环引用的&#xff0c;但从 Spring Boot 2.6.0 开始&#xff0c;默认禁止 Bean 之间的循环引用&#xff0c;如果存在循环引用就会启动失败报错。 此时要解决循环引用问题有两个办法&#xff1a; 设置Spring允许循环引用&#xff08;推荐&#x…

《LeetCode力扣练习》代码随想录——贪心算法(买卖股票的最佳时机 II---Java)

《LeetCode力扣练习》代码随想录——贪心算法&#xff08;买卖股票的最佳时机 II—Java&#xff09; 刷题思路来源于 代码随想录 122. 买卖股票的最佳时机 II 贪心 class Solution {public int maxProfit(int[] prices) {int result 0;for (int i 1; i < prices.length; i…

<Linux> 常用基础指令

目录 Linux基础指令ls指令pwd指令cd指令touch指令mkdir指令rm指令cp指令mv指令cat指令tac指令grep指令echo指令zip/unzip指令uname指令 Linux基础指令 ls指令 功能&#xff1a;列出本目录下的文件及子目录 常用的选项&#xff1a; -a 列出所有文件&#xff0c;包括以.开头的…

漫谈:C语言 奇葩的指针定义规则

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 C语言的语法很麻拐。 初学者的…

YOLOv9/YOLOv8算法改进【NO.128】 使用ICCV2023超轻量级且高效的动态上采样器( DySample)改进yolov8中的上采样

前 言 YOLO算法改进系列出到这&#xff0c;很多朋友问改进如何选择是最佳的&#xff0c;下面我就根据个人多年的写作发文章以及指导发文章的经验来看&#xff0c;按照优先顺序进行排序讲解YOLO算法改进方法的顺序选择。具体有需求的同学可以私信我沟通&#xff1a; 首推…

SpringMVC进阶(过滤器解决中文乱码,处理json以及文件上传下载)

文章目录 1.中文乱码处理1.引出问题1.恢复原来取消掉的属性绑定2.启动服务器&#xff0c;引出问题 2.自定义中文乱码过滤器1.MyCharacterFilter.java2.web.xml配置过滤器&#xff08;这个解决乱码的过滤器放到最前面&#xff09;3.结果展示 3.使用Spring过滤器处理&#xff08;…

创建codereview

创建codereview流程 一、开始创建二、选择分支三、添加细节 一、开始创建 点击codereivew按钮 为新的codereview选择一个工程后点击create review 二、选择分支 选择目标分支和要比对的分支&#xff0c;比如develop 三、添加细节 Add branch后&#xff0c;可以继续Edit …

基于Python的在线学习与推荐系统设计与实现(论文+源码)-kaic

题目&#xff1a;在线学习与推荐系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本在线学习与推荐系统就是在这样的大环境下诞生&#xff0…

Python项目开发实战:怎么基于Keras的深度学习来预测房价

注意:本文的下载教程,与以下文章的思路有相同点,也有不同点,最终目标只是让读者从多维度去熟练掌握本知识点。 下载教程:深度学习-基于Keras的Python项目开发实战_波士顿房价预测_编程案例实例教程.pdf 一、引言 在当今信息化社会,房价预测已成为金融、房地产及相关领域…