类和对象(三)

默认成员函数

接下来继续看剩下的两个默认成员函数。

const成员函数

将const修饰的成员函数称之为const成员函数,const修饰成员函数放到成员函数参数列表的后 ⾯。const实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进⾏修改。

先来看例子:

所以C++设计了使用 const 修饰成员函数来达到目的。

所以,只需在成员函数参数列表后添加 const ,就能解决问题。

所以,对于一个类,如果我们希望所有的成员函数都默认为const,即不修改对象状态,我们可以使用const关键字来修饰成员函数。


取地址运算符重载

取地址运算符重载分为普通取地址运算符重载和 const 取地址运算符重载,⼀般这两个函数编译器⾃动 ⽣成的就可以够我们⽤了,不需要去显⽰实现。取地址的意思就是返回当前对象的地址,对于成员函数来讲,this指针就是它的地址。

class Date
{
public://普通取地址运算符重载Date* operator&(){return this;}//const取地址运算符重载,返回一个const Date* 的指针。const Date* operator&() const{return this;}private:int _year;int _month;int _day;
};

友元

友元就是提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类,在函数声明或者类 声明的前⾯加 friend,并且把友元声明放到⼀个类的⾥⾯。外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数。友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制。

#include<iostream>class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//友元函数声明friend void func(const Date& d);private:int _year;int _month;int _day;
};void func(const Date& d)
{std::cout << d._year << "年" << d._month << "月" << d._day << "日" << std::endl;
}int main()
{Date d1;func(d1);return 0;
}

并且⼀个函数可以是多个类的友元函数。

#include<iostream>//前置声明,否则Date类中的友元函数不认识A类
class A;class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}//友元函数声明friend void func(const Date& d, const A& a);private:int _year;int _month;int _day;
};class A
{friend void func(const Date& d, const A& a);private:int _a1 = 1;int _a2 = 2;
};void func(const Date& d, const A& a)
{std::cout << d._year << "年" << d._month << "月" << d._day << "日" << std::endl;std::cout << a._a1 << std::endl;
}int main()
{Date d1;A a;func(d1, a);return 0;
}

友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。

#include<iostream>class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}friend class A;private:int _year;int _month;int _day;
};class A
{
public:void func(const Date& d){std::cout << d._year << "-" << d._month << "-" << d._day << std::endl;std::cout << _a1 << ' ' << _a2 << std::endl;}
private:int _a1 = 1;int _a2 = 2;
};int main()
{Date d;A a;a.func(d);return 0;
}

友元类的关系是单向的,不具有交换性。比如A类是B类的友元,但是B类不是A类的友元。而且友元类关系是不能传递,如果A是B的友元,B是C的友元,但是A不是C的友元。


赋值重载流插入和流提取

上一篇的利用运算符重载在类中实现了各种操作(详见:点这里),接下来就在类内实现流插入和流提取的重载(也就是在类内实现自定义类型的输入输出)。

流插入

通过查阅资料可以看到,cin 是 istream 类型的对象,cout 是 ostream 类型的对象,如果要重载,则类型简单可以写为:

但这样写是有问题的,是不对的。

其报错信息显示出,出现这样的错误本质上是因为参数不匹配造成的。

如果改为这样,就不会报错,也能正常运行。

所以,重载 >> 和 << 时,需要重载为全局函数,因为重载为成员函数,this指针默认抢占了第⼀个形参位置,第⼀个形参位置是左侧运算对象,调⽤时就变成了 << cout 对象,不符合使⽤习惯和可读性。重载为全局函数把 ostream/istream 放到第⼀个形参位置就可以了,第⼆个形参位置当类类型对象。

但又出现了新的问题,就是无法访问类内的成员变量。所以我们可以使用C++的 友元 来访问类内部的成员变量。

但其还不支持连续赋值,和=等运算符一样,它一定是要支持连续赋值的,所以还要进行改造。

但与=运算符不同,流插入流提取运算符是从左到右赋值的。所以得:

#include<iostream>
using namespace std;class Date
{
public:// 全缺省的构造函数Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// 拷贝构造函数Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}// 赋值运算符重载Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}// 析构函数//日期类无要释放的资源,编译器自动生成的析构即可满足要求。void Print(){std::cout << _year << "-" << _month << "-" << _day << std::endl;}//友元函数声明friend ostream& operator<<(ostream& out, const Date& d);private:int _year;int _month;int _day;
};ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}void test()
{Date d1(2024, 6, 6);Date d2(2006, 1, 2);cout << d1 << d2;
}int main()
{test();return 0;
}

接下来就是流提取得重载函数。

流提取

流提取是 istream 类型的对象,所以:

#include<iostream>
using namespace std;class Date
{
public:// 全缺省的构造函数Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// 拷贝构造函数Date(const Date& d){_year = d._year;_month = d._month;_day = d._day;}// 赋值运算符重载Date& operator=(const Date& d){_year = d._year;_month = d._month;_day = d._day;return *this;}// 析构函数//日期类无要释放的资源,编译器自动生成的析构即可满足要求。void Print(){std::cout << _year << "-" << _month << "-" << _day << std::endl;}friend ostream& operator<<(ostream& out, const Date& d);friend istream& operator>>(istream& in, Date& d);private:int _year;int _month;int _day;
};ostream& operator<<(ostream& out, const Date& d)
{out << d._year << "年" << d._month << "月" << d._day << "日" << endl;return out;
}istream& operator>>(istream& in, Date& d)
{cout << "请输入年月日:";in >> d._year >> d._month >> d._day;return in;
}void test()
{Date d1(2024, 6, 6);Date d2(2006, 1, 2);cin >> d1 >> d2;cout << d1 << d2;
}int main()
{test();return 0;
}

内部类

如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。内部类是⼀个独立的类,跟定义在 全局相比,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。并且内部类默认是外部类的友元类。

简单来说就是,内部类可以访问到外部类成员,但外部类不能访问到内部类得成员。

#include<iostream>class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}class A{public:void func(const Date& d){std::cout << d._year << "-" << d._month << "-" << d._day << std::endl;std::cout << _a1 << ' ' << _a2 << std::endl;}private:int _a1 = 1;int _a2 = 2;};private:int _year;int _month;int _day;
};int main()
{Date d1;Date::A a;a.func(d1);return 0;
}

匿名函数

直接⽤ 类型 (实参) 定义出来的对象叫做匿名对象,相⽐之前我们定义的 类型 对象名(实参) 定义出来的叫有名对象。匿名对象⽣命周期只在当前⼀⾏,⼀般用于临时定义⼀个对象。

#include<iostream>class Date
{
public:Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}void Print(){std::cout << _year << "-" << _month << "-" << _day << std::endl;}private:int _year;int _month;int _day;
};int main()
{//有名函数Date d1;d1.Print();//匿名函数Date().Print();return 0;
}

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

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

相关文章

秋招突击——7/17——复习{二分查找——搜索插入位置、搜索二维矩阵,}——新作{链表——反转链表和回文链表,子串——和为K的子数组}

文章目录 引言新作二分模板二分查找——搜索插入位置复习实现 搜索二维矩阵复习实现 新作反转链表个人实现参考实现 回文链表个人实现参考实现 和为K的子数组个人实现参考实现 总结 引言 今天算法得是速通的&#xff0c;严格把控好时间&#xff0c;后面要准备去面试提前批了&a…

C语言实例-约瑟夫生者死者小游戏

问题&#xff1a; 30个人在一条船上&#xff0c;超载&#xff0c;需要15人下船。于是人们排成一队&#xff0c;排队的位置即为他们的编号。报数&#xff0c;从1开始&#xff0c;数到9的人下船&#xff0c;如此循环&#xff0c;直到船上仅剩15人为止&#xff0c;问都有哪些编号…

C语言 | Leetcode C语言题解之第260题只出现一次的数字III

题目&#xff1a; 题解&#xff1a; int* singleNumber(int* nums, int numsSize, int* returnSize) {int xorsum 0;for (int i 0; i < numsSize; i) {xorsum ^ nums[i];}// 防止溢出int lsb (xorsum INT_MIN ? xorsum : xorsum & (-xorsum));int type1 0, type2…

【Mysql】Docker下Mysql8数据备份与恢复

[TOC] 【Mysql】Docker下Mysql8数据备份与恢复 1 创建Mysql容器 格式 docker run -d --name容器名称 -p 宿主端口号:3306 -e MYSQL_ROOT_PASSWORDmysql密码 -e MYSQL_PASSWORDmysql密码 -e TZAsia/Shanghai -v 宿主目录-数据:/var/lib/mysql -v 宿主目录-备份数据:/back…

多态性概念 OOPS

大家好&#xff01;今天&#xff0c;我们将探讨面向对象编程 (OOP) 中的一个基本概念 - 多态性。具体来说&#xff0c;我们将重点介绍其三种主要形式&#xff1a;方法重载、方法覆盖和方法隐藏。对于任何使用 OOP 语言&#xff08;例如 C#&#xff09;的程序员来说&#xff0c;…

NET 语言识别,语音控制操作、语音播报

System.Speech. 》》System.Speech.Synthesis; 语音播报 》》System.Speech.Recognition 语音识别 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Speech.Recog…

mac二进制安装operator-sdk

0. 前置条件 1. 安装go 安装步骤略。 1. 下载operator-sdk源码包 https://github.com/operator-framework/operator-sdk 1.1 选择适合当前go版本的operator版本&#xff0c;在operator-sdk/go.mod文件中可以查看Operator-sdk使用的go版本。 2. 编译 源码包下载后&#x…

C语言航空售票系统

以下是系统部分页面 以下是部分源码&#xff0c;需要源码的私信 #include<stdio.h> #include<stdlib.h> #include<string.h> #define max_user 100 typedef struct ft {char name[50];//名字char start_place[50];//出发地char end_place[50];//目的地char …

JAVA 异步编程(线程安全)二

1、线程安全 线程安全是指你的代码所在的进程中有多个线程同时运行&#xff0c;而这些线程可能会同时运行这段代码&#xff0c;如果每次运行的代码结果和单线程运行的结果是一样的&#xff0c;且其他变量的值和预期的也是一样的&#xff0c;那么就是线程安全的。 一个类或者程序…

多线程初阶(二)- 线程安全问题

目录 1.观察count 原因总结 2.解决方案-synchronized关键字 &#xff08;1&#xff09;synchronized的特性 &#xff08;2&#xff09;如何正确使用 语法格式 3.死锁 &#xff08;1&#xff09;造成死锁的情况 &#xff08;2&#xff09;死锁的四个必要条件 4.Java标准…

若依二次开发

口味改造 原&#xff1a; 改造&#xff1a; 1./** 定义口味名称和口味列表的静态数据 */ 2.改变页面样式 3.定义储存当前选中的口味列表数组&#xff0c;定义改变口味名称时更新当前的口味列表 4.改变页面样式 6.格式转换 7.定义口味列表获取焦点时更新当前选中的口味列表

【DGL系列】简单理解graph.update_all和spmm的区别

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 背景介绍 源码分析 小结一下 背景介绍 我们在看GNN相关的论文时候&#xff0c;都会说到邻接矩阵与特征矩阵之间是用到了spmm&#xff0c;在很久…

深入理解Linux网络(二):UDP接收内核探究

深入理解Linux网络&#xff08;二&#xff09;&#xff1a;UDP接收内核探究 一、UDP 协议处理二、recvfrom 系统调⽤实现 一、UDP 协议处理 udp 协议的处理函数是 udp_rcv。 //file: net/ipv4/udp.c int udp_rcv(struct sk_buff *skb) {return __udp4_lib_rcv(skb, &udp_…

【web】-反序列化-to_string

<?php highlight_file(__FILE__); class A{public $s;public function __destruct(){echo "hello".$this->s;}} class B{public $cmd;public function __toString(){system($this->cmd);return 1;} } unserialize($_GET[code]); __toString()当对象被当着…

《梦醒蝶飞:释放Excel函数与公式的力量》17.1使用命名范围和工作表函数

第17章&#xff1a;使用命名范围和工作表函数 17.1 命名范围的优势 在Excel中&#xff0c;使用命名范围是一个强大且灵活的功能&#xff0c;它可以极大地提高工作效率和公式的可读性。命名范围不仅使公式更容易理解&#xff0c;还减少了错误的可能性。以下将详细介绍命名范围的…

自然语言大模型介绍

1 简介 最近一直被大语言模型刷屏。本文是周末技术分享会的提纲&#xff0c;总结了一些自然语言模型相关的重要技术&#xff0c;以及各个主流公司的研究方向和进展&#xff0c;和大家共同学习。 2 Transformer 目前的大模型基本都是Transformer及其变种。本部分将介绍Transf…

24暑假算法刷题 | Day18 | LeetCode 530. 二叉搜索树的最小绝对差,501. 二叉搜索树中的众数,236. 二叉树的最近公共祖先

目录 530. 二叉搜索树的最小绝对差题目描述题解 501. 二叉搜索树中的众数题目描述题解 236. 二叉树的最近公共祖先题目描述题解 530. 二叉搜索树的最小绝对差 点此跳转题目链接 题目描述 给你一个二叉搜索树的根节点 root &#xff0c;返回 树中任意两不同节点值之间的最小差…

Python 更换 pip 源详细指南

目录 前言pip 国内源临时换源方法一&#xff1a;添加参数方法二&#xff1a;设置环境变量 永久换源方法三&#xff1a;修改配置方法四&#xff1a;pip 命令修改 总结 前言 在我们使用 Python 3 时&#xff0c;pip 是一个不可或缺的工具&#xff0c;它用于安装和管理第三方库。…

在虚拟机 CentOS7 环境下安装 MySQL5.7 数据库

配置目标 在虚拟机的 Linux CentOS7 环境下安装 MySQL5.7 版数据库&#xff0c;并能从宿主机 Windows 系统连接该数据库&#xff08;默认端口&#xff1a;3306&#xff09;。 1. 准备工作 WMware 虚拟机&#xff1a;VMware Workstation 16 ProCentOS7 镜像&#xff1a;CentO…

基于密钥的身份验证(Linux-Linux)

A主机&#xff1a; 1、生成密钥对 [rootservera ~]# ssh-keygen查看公钥 注&#xff1a;id_rsa为私钥&#xff08;证书&#xff09;&#xff0c;id_rsa.pub为公钥 2、注册公钥到服务器 [rootservera ~]# ssh-copy-id root172.25.250.106 查看.ssh 3、使用密钥连接服务器 #…