c++学习(day4)

news2024/11/18 15:36:45

文章目录

  • 一. 友元(friend)
    • 1 友元函数
      • 1.1 全局函数作为友元函数
      • 1.2 类的成员函数作为友元函数(了解)
    • 2. 友元类
    • 3. 使用友元的注意事项
  • 二. 常成员函数和常对象(const)
    • 1. 常成员函数
    • 2. 常对象
    • 3. mutable关键字
  • 三. 运算符重载
    • 1. 定义
    • 2. 重载的方法
    • 3. 运算符重载要求
    • 4. 调用时机及调用原则
    • 5. 运算符重载的格式
      • 5.1 算术类运算符重载(双目运算符)
      • 5.2 赋值类运算符重载
      • 5.3 关系运算符重载
      • 5.4 单目运算符重载
      • 5.4 单目运算符重载
      • 5.5 自增、自减运算符重载
      • 5.6 插入、提取运算符重载
      • 5.6 不能重载的运算符
      • 5.7 运算符重载注意事项
      • 5.6 不能重载的运算符
      • 5.7 运算符重载注意事项

一. 友元(friend)

友元是一种定义在类外部的普通函数或类

1 友元函数

1.1 全局函数作为友元函数

声明一个全局函数作为类的友元函数,则允许该全局函数,访问类中各个权限下的成员

在类中要将该函数进行声明:friend 全局函数头;

#include <iostream>
using namespace std;

class Stu
{
private:
    string name;
    int age;
public:
    Stu() {}
    Stu(string n, int a) : name(n), age(a) {}

    void show()
    {
        cout << "name = " << name << "   age = " << age << endl;
    }

    friend void display(Stu s); // 在类中将全局函数声明成类的友元函数
};

// 定义全局函数
void display(Stu s)
{
    cout << "name = " << s.name << "   age = " << s.age << endl; // 正常的全局函数不能访问类中私有属性
}

int main()
{
    display(Stu("zhangpp", 18));

    return 0;
}

1.2 类的成员函数作为友元函数(了解)

  1. 声明一个其他类的成员函数作为自己类的友元函数,则允许让该函数访问自己类中的所有成员

  2. 要求该函数必须类内声明类外定义

2. 友元类

  1. 在一个类中声明另一个类当做友元类,则允许友元类中所有成员访问自己的所有权限下的成员

  2. 声明格式:friend class 类名;

#include <iostream>

using namespace std;

class Stu; // 类的前置声明

class Teacher // 老师类
{
private:
    string sub;

public:
    Teacher() {}
    Teacher(string s) : sub(s) {}

    void show(Stu s); // 类内声明
};

class Stu // 学生类
{
private:
    string name;
    int age;

public:
    Stu() {}
    Stu(string n, int a) : name(n), age(a) {}

    void show()
    {
        cout << "name = " << name << "   age = " << age << endl;
    }

    friend void display(Stu s); // 在类中将全局函数声明成类的友元函数

    // friend void Teacher::show(Stu s);             //声明老师类中的成员函数作为友元函数

    // 将整个Teacher类当做友元类
    friend class Teacher;
};

// 定义全局函数
void display(Stu s)
{
    cout << "name = " << s.name << "   age = " << s.age << endl; // 正常的全局函数不能访问类中私有属性
}

// 老师类中的成员函数的定义
void Teacher::show(Stu s)
{
    cout << "Teacher::sub = " << sub << endl;
    cout << "Stu::name = " << s.name << endl; // 其他类不能访问类中私有成员
}

int main()
{
    display(Stu("zhangpp", 18));
    Teacher t1("C++");
    t1.show(Stu("zhangpp", 18));
    return 0;
}

3. 使用友元的注意事项

  1. 友元具有方向性,A把B当做朋友,允许B访问A的所有权限,但是A不一定能访问B的所有权限

  2. 友元不具有交换性:A是B的朋友,但B不一定是A的朋友

  3. 友元不具有传递性:A是B的朋友,B是C的朋友,则A不一定是C的朋友

  4. 友元不具有继承性:父类的朋友不一定是子类的朋友

  5. 由于友元的出现,破坏了了类的封装性,使得访问权限形同虚设。所以不在万不得已的情况下,尽可能少用友元

  6. 必须使用友元的情况:插入和提取运算符重载。(后期讲)

二. 常成员函数和常对象(const)

1. 常成员函数

由const修饰的成员函数叫常成员函数

格式:

  • 返回类型 成员函数名(参数表) const;

    例如:int function(int x) const

特点:

  1. 在常成员函数中,不能修改成员变量的值(保护成员变量不被修改)

  2. 类中同名的常成员函数和非常成员函数构成重载关系,原因是隐藏的this指针的类型不同

    非常成员函数中: Stu * const  this
    常成员函数中:	  const Stu * const this
    
  3. 非常对象,优先调用非常成员函数,如果没有非常成员函数,则去调用同名的常成员函数

  4. 常对象只能调用常成员函数,没有常成员函数会报错

2. 常对象

const修饰的对象为常对象

  1. 常对象只能调用常成员函数,不能调用非常成员函数

  2. 当一个常引用的目标为非常对象,则通过引用只能调用常成员函数,通过对象优先调用非常成员函数

3. mutable关键字

功能:

取消成员常属性

使用方式:

​ 定义变量前加mutable,那么,该变量就能在常成员函数中被修改

#include <iostream>

using namespace std;

class Stu
{
private:
    string name;
    mutable int age; // 由mutable关键字修饰的成员变量,能在常成员函数中被修改
    double score;

public:
    Stu() {}
    Stu(string n, int a, double s) : name(n), age(a), score(s) {}

    // 有const修饰的成员函数就是常成员函数
    void show() const // const Stu * const this;
    {
        // this = nullptr;
        // this->score = 50; // 在常成员函数中不能修改成员变量的值
        this->age = 100; // 可以更改,因为有关键字修饰
        cout << "name = " << name << endl;
        cout << "age = " << age << endl;
        cout << "score = " << score << endl;
        cout << "AAAAAAAAAAAAAAAAAAAAAA" << endl;
    }

    void show() // Stu * const this;
    {
        this->score = 50; // 在常成员函数中不能修改成员变量的值
        cout << "name = " << name << endl;
        cout << "age = " << age << endl;
        cout << "score = " << score << endl;
        cout << "BBBBBBBBBBBBBBBBBBBBBBBB" << endl;
    }
};

int main()
{
    Stu s1("张三", 20, 99);
    s1.show(); // 50

    const Stu &r = s1;

    r.show();  // 常成员函数
    s1.show(); // 优先调用非常成员函数

    return 0;
}

三. 运算符重载

单、算、关、逻、条、赋、逗

img

1. 定义

所谓运算符重载,就是给运算符新的含义,能够实现“一符多用”,也是属于静态多态的一种,

他能够实现将原本加载到基本数据类型的运算符,在自定义类对象减使用。

好处:能够使得代码更加简洁、易懂,优雅好看

2. 重载的方法

统一的名称:

operator# //#表示运算符

3. 运算符重载要求

功能:

​ 实现运算符对应的操作

参数:

​ 由运算符本身决定

返回值:

​ 由用户自己决定

4. 调用时机及调用原则

调用时机:当使用该运算符时,系统自动调用,无需手动调用

调用原则:左调右参 //a = b; a.operator=(b)

5. 运算符重载的格式

每种运算符都有两个版本的格式:

  • 成员函数版本,类对象本身就是一个参数,形参个数是操作数个数-1

  • 全局函数版,需要使用友元完成,此时参数个数等于操作数个数

以上两个版本的重载函数,只能实现一个,否则调用时会混乱报错

5.1 算术类运算符重载(双目运算符)

种类:

​ +、-、*、/、%。。。

表达式:

​ L#R //L表示左操作数,#表示运算符,R表示右操作数

  • 左操作数:既可以是左值也可以是右值

  • 右操作数:既可以是左值也可以是右值

  • 结果:右值

定义格式:

  • 成员函数版:const 类名 operator#( const 类名 &R ) const

第一个const:保护返回结果不被改变

第二个const:保护右操作数不被修改

第三个const:保护左操作数不被修改

  • 全局函数版:const 类名 operator#(const 类名 &L, const 类名 &R)

5.2 赋值类运算符重载

种类:

​ =、-=、*=、/=、%=、+=。。。

表达式:

​ L#R //L表示左操作数,#表示运算符,R表示右操作数

  • 左操作数:只能是左值

  • 右操作数:既可以是左值也可以是右值

  • 结果:右值

定义格式:

  • 成员函数版: 类名 & operator#( const 类名 &R )

  • 全局函数版: 类名 & operator#(类名 &L, const 类名 &R)

5.3 关系运算符重载

种类:

​ >=、<=、!=、>、<、==。。。

表达式:

​ L#R //L表示左操作数,#表示运算符,R表示右操作数

  • 左操作数:既可以是左值也可以是右值

  • 右操作数:既可以是左值也可以是右值

  • 结果:bool类型的右值

定义格式:

  • 成员函数版: const bool operator#( const 类名 &R ) const

  • ==全局函数版: const bool operator#( const 类名 &L,const 类名 &R ) ==

5.4 单目运算符重载

种类:

​ &、!、-(负号)。。。

表达式:

​ #O //#表示运算符 O表示操作数

  • 操作数:既可以是左值也可以是右值

  • 结果:右值

定义格式:

  • 成员函数版: const 类名 operator#( void ) const

  • 全局函数版: const 类名 operator#( conts 类名 &O)

5.4 单目运算符重载

种类:

​ &、!、-(负号)。。。

表达式:

​ #O //#表示运算符 O表示操作数

  • 操作数:既可以是左值也可以是右值

  • 结果:右值

定义格式:

  • 成员函数版: const 类名 operator#( void ) const

  • 全局函数版: const 类名 operator#( conts 类名 &O)

5.5 自增、自减运算符重载

前置自增:++a

表达式:

​ #O //#表示运算符 O表示操作数

  • 操作数:只能是左值

  • 结果:左值,自身的引用

定义格式:

  • 成员函数版: 类名 & operator#( )

  • 全局函数版: 类名 & operator#( 类名 &O )

后置自增:a++

表达式:

​ O# //#表示运算符 O表示操作数

  • 操作数:只能是左值

  • 结果:右值

定义格式:

  • 成员函数版: 类名 operator#( int )

  • 全局函数版: 类名 operator#( 类名 &O , int)

5.6 插入、提取运算符重载

  1. cin和cout的来源
namespace std
{
    extern istream cin;         /// Linked to standard input
    extern ostream cout;        /// Linked to standard output
}
  1. 从这两个类对象可以看出,cin和cout来自于内置对象,想要对<<和>>进行重载时,如果想要实现成员函数版,则需要多istream和ostream类进行修改,难度较大。

  2. 此时,我们可以使用全局函数版实现这两个运算符的重载,将该全局函数设置成友元函数即可

  3. 因为要用到istream和ostream的类对象和自定义类对象,原则上来说需要在两个类中都要设置成友元函数

  4. 但是,在运算符重载函数中,只会对自定义的类对象访问私有成员,而不会对istream和ostream的类访问私有成员

  5. 所以,最终只需要在自定义类中,将全局函数设置成友元函数即可

表达式:

​ L#R (L是cin或cout #是<<或者>> R是自定义的类对象)

  • 左操作数:istream和ostream的类对象

  • 右操作数:自定义的类对象

  • 结果:左操作数自身的引用

格式:

  • ostream &operator<<(ostream &L, const 类名 &O);

  • istream &operator>>(istream &L, const 类名 &O);

5.6 不能重载的运算符

  1. 成员运算符 .

  2. 成员指针运算符 .*

  3. 条件表达式 ?:

  4. 求字节运算 sizeof

  5. 作用域限定符 ::

5.7 运算符重载注意事项

  1. 运算符重载只能在已有的运算符基础上进行重载,不能凭空捏造一个运算符

  2. 运算符重载不能更改运算符的本质:如不能在加法运算符重载中实现减法

  3. 运算符重载不能改变运算符的优先级

  4. 运算符重载不能改变运算符的结合律

  5. 运算符重载函数不能设置默认参数

​ L#R (L是cin或cout #是<<或者>> R是自定义的类对象)

  • 左操作数:istream和ostream的类对象

  • 右操作数:自定义的类对象

  • 结果:左操作数自身的引用

格式:

  • ostream &operator<<(ostream &L, const 类名 &O);

  • istream &operator>>(istream &L, const 类名 &O);

5.6 不能重载的运算符

  1. 成员运算符 .

  2. 成员指针运算符 .*

  3. 条件表达式 ?:

  4. 求字节运算 sizeof

  5. 作用域限定符 ::

5.7 运算符重载注意事项

  1. 运算符重载只能在已有的运算符基础上进行重载,不能凭空捏造一个运算符

  2. 运算符重载不能更改运算符的本质:如不能在加法运算符重载中实现减法

  3. 运算符重载不能改变运算符的优先级

  4. 运算符重载不能改变运算符的结合律

  5. 运算符重载函数不能设置默认参数

  6. 成员函数版的参数要比全局函数版的参数少一个,原因是对象本身就是一个参数

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

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

相关文章

【微服务笔记17】微服务组件之Gateway实现动态路由、配置路由规则、路由过滤器

这篇文章&#xff0c;主要介绍微服务组件之Gateway实现动态路由、配置路由映射规则、路由过滤器。 目录 一、动态路由配置 1.1、动态URI路由配置 &#xff08;1&#xff09;引入eureka客户端依赖 &#xff08;2&#xff09;添加路由配置 1.2、服务名称转发配置 二、断言配…

基于 Windows 安装 ESP32 Arduino 软件开发环境

ESP32 Arduino 源码库&#xff1a;arduino-esp32ESP32 Arduino 环境搭建说明&#xff1a;About Arduino ESP32 其他软件环境需求&#xff1a; Git 环境 1、安装 Arduino 软件 可在 Arduino 官网 获取 Windows 端 Arduino 安装包&#xff0c;如下&#xff1a; 使用如下 .exe 一…

JVM类加载过程

文章目录 1、加载2、链接2.1 验证2.2 准备2.3 解析 3、初始化3.1 类初始化练习3.2 懒汉式单例练习 4、类加载器4.1 启动类加载器4.2 扩展类加载器4.3 双亲委派模式4.4 线程上下文类加载器4.4 自定义类加载器 5、运行时优化5.1 即时编译逃逸分析方法内联&#xff08;Inlining&am…

StressAppTest的简介

StressAppTest的全称是Stressful Application Test (stressapptest) 的简称http://code.google.com/p/stressapptest/ 这里我们可以将其简化为SAT。 SAT试图让来自处理器和I/O到内存的数据尽量随机化,以创造出模拟现实的环境来测试现在的硬件设备是否稳定。 SAT的大概作用如…

【Mysql 学习笔记】

Mysql 笔记记录 MySQL学习笔记一、 DDL1. DDL 查询和创建数据库2. DDL 修改、删除、使用数据库3. DDL 查询数据表4. DDL 创建数据表5. DDL 修改数据表6. DDL 删除数据表 二、DML MySQL学习笔记 一、 DDL 1. DDL 查询和创建数据库 #查询所有数据库 SHOW DATABASES; #查询某个数…

PMP项管2023年5月的备考准备攻略!现在看还来得及!

2023年共有4次PMP考试&#xff0c;分别是3月、5月、8月、11月&#xff0c;由于3月份考试不开放新报名&#xff0c;所以第一次备考PMP的同学可以选择参加5月份考试。那么&#xff0c;现在备考5月份PMP考试还来得及吗&#xff1f; 现在开始备考5月PMP考试&#xff0c;时间是非常…

蓝牙技术|消息称三星正研发智能戒指Galaxy Ring

根据韩媒 MT 报道&#xff0c;三星内部正在开发继 Galaxy Watch、Galaxy Fit 之后的另一款健康追踪设备 Galaxy Ring。 报道称这款智能戒指配备 PPG&#xff08;光电容积脉搏波&#xff09;传感器和 ECG&#xff08;心电图&#xff09;传感器&#xff0c;可以准确追踪佩戴者的…

云智慧助力MLOps加速落地

背景 随着数字化和计算能力的发展&#xff0c;机器学习&#xff08;Machine Learning&#xff09;技术在提高企业生产力方面所涌现的潜力越来越被大家所重视&#xff0c;然而很多机器学习的模型及应用在实际的生产环境并未达到预期&#xff0c;大量的ML项目被证明是失败的。从…

云计算中的网络安全技术及其应用

云计算已经成为当今企业信息化的主要选择之一。它提供了可靠的数据存储和处理能力&#xff0c;同时降低了企业的IT成本。然而&#xff0c;云计算的安全问题也随之而来。网络安全技术的应用对于保护云计算的安全至关重要。本文将探讨云计算中的网络安全技术及其应用&#xff0c;…

Golang每日一练(leetDay0041) 股票买卖4题

目录 121. 买卖股票的最佳时机 &#x1f31f; 122. 买卖股票的最佳时机 II &#x1f31f;&#x1f31f; 123. 买卖股票的最佳时机 III &#x1f31f;&#x1f31f;&#x1f31f; 188. 买卖股票的最佳时机 IV &#x1f31f;&#x1f31f;&#x1f31f; &#x1f31f; 每…

2023第六届世界燕窝及天然滋补品博览会

2023上海燕窝展|上海燕博会|虫草节、鱼胶、灵芝、海参、滋补品展|滋补大会 摘要&#xff1a;燕博会、上海燕窝展、上海燕博会、2023上海燕博会、2023上海燕窝展、2023中国燕窝展、2023燕窝展&#xff0c;2023原装进口燕窝展&#xff0c;2023干制燕窝展,2023即食燕窝展,2023燕窝…

前端开发中有哪些常用的数组操作方法?

javascript数组 简介 JavaScript 数组用于在单一变量中存储多个值。 JavaScript数组是无类型的&#xff0c;数组元素可以是任意类型&#xff0c;并且同一个数组中元素类型也可以不同。 实例 var cars ["Saab", "Volvo", "BMW"];什么是数组&…

探索【Stable-Diffusion WEBUI】的插件:画布扩绘(Outpaint)

文章目录 &#xff08;零&#xff09;前言&#xff08;一&#xff09;局部重绘&#xff08;Inpaint&#xff09;&#xff08;二&#xff09;画布扩绘&#xff08;Outpaint&#xff09;&#xff08;2.1&#xff09;图片画布扩大&#xff08;插件&#xff1a;OpenOutpaint&#x…

回炉重造九---DNS服务器

1、DNS服务器的相关概念和技术 1.1 DNS服务器的类型 主DNS服务器从DNS服务器缓存DNS服务器&#xff08;forward DNS服务器{转发器}&#xff09; 1.1.1 主DNS服务器的作用 管理和维护所负责解析的域内解析库的服务器1.1.2 从DNS服务器的作用 从主服务器或从服务器“复制”解…

检测并打印C++编译器支持的feature(附Visual Studio 2022和gcc-12测试、对比结果)

C标准快速迭代&#xff0c;不同的系统平台和编译器对C各种新功能的支持不同&#xff0c;通过这个程序可以测试所用编译器对各个版本C的支持情况。另一方面&#xff0c;可以在代码中通过这些宏针对不同版本编写不同的代码分支。 源码下面附上Visual Studio 2022的测试结果&#…

32道子网划分习题详细解析

目录 1 子网划分概念&#xff1a; 2 划分方法&#xff1a; 子网划分方法&#xff1a;段&#xff0c;块&#xff0c;数的计算三步。 段就是确定ip地址段中既有网络地址&#xff0c;又有主机地址的那一段是四段中的那一段&#xff1f; 块就确定上一步中确定的那一段中的主机…

【C语言】21-结构体

本文目录 • 一、什么是结构体 • 二、结构体的定义 • 三、结构体变量的定义 • 四、结构体的注意点 • 五、结构体的初始化 • 六、结构体的使用 • 七、结构体数组 • 八、结构体作为函数参数 • 九、指向结构体的指针 说明&#xff1a;这个C语言专题&#xff0c;是学习iOS开…

算法设计与智能计算 || 专题七: 主成分分析的统计学视角

主成分分析的统计学视角 文章目录 主成分分析的统计学视角PCA 的统计学视角1. 寻找第一个主成分2. 获取第二个主成分3. 非零均值随机变量的主元4. 零均值随机变量的样本主元5. PCA 降维案例 主成分分析是将高维空间中的数据集拟合成一个低维子空间的方法&#xff0c;到目前为止…

搞定常见八大排序

文章目录 注意事项插入排序插入排序希尔排序 分组预排序选择排序堆排序直接选择排序(最拉胯的排序) 交换排序冒泡排序快速排序1. hoare版本如何解决快排缺陷&#xff1f;2.挖坑法版本3.双指针法版本&#xff08;建议&#xff09;快排算法优化实现非递归快排 归并排序归并排序 非…

Rainbond 结合 Jpom 实现云原生 本地一体化项目管理

Jpom 是一个简而轻的低侵入式在线构建、自动部署、日常运维、项目运维监控软件。提供了&#xff1a; 节点管理&#xff1a;集群节点&#xff0c;统一管理多节点的项目&#xff0c;实现快速一键分发项目文件项目管理&#xff1a;创建、启动、停止、实时查看项目控制台日志&…