从0开始C++(五):友元函数运算符重载

news2024/11/27 13:29:02

友元函数

介绍

C++中的友元函数是一种特殊的函数,它可以访问和操作类的私有成员和保护成员。友元函数可以在类的内部或外部声明和定义,但在其声明和定义中需要使用关键字 friend 来标识。友元函数可以是全局函数,也可以是其他类的成员函数。

下面是友元函数的一些重要特点和用法:

  1. 友元函数可以访问和操作类的私有成员和保护成员,这使得函数可以直接访问类的私有数据,而无需通过类的公有接口进行访问。

  2. 友元函数可以在类的内部或外部声明和定义。在类的内部声明友元函数时,使用friend关键字来标识函数为友元函数。在类的外部定义友元函数时,需要在函数的定义前面声明该函数为友元函数。

  3. 友元函数可以是全局函数,也可以是其他类的成员函数。如果友元函数是另一个类的成员函数,需要在该类的声明中将其声明为友元函数。

  4. 友元函数不是类的成员函数,因此它没有隐含的this指针,也无法访问类的非静态成员。

  5. 友元函数的声明可以放在类的任何位置,但其定义必须在类的外部。这是因为友元函数不属于类的成员,所以需要在类的外部定义。

  6. 友元函数可以用于重载操作符。这使得我们能够定义两个不同类对象之间的操作,例如添加两个自定义类的对象。

友元函数提供了一种特殊的访问和操作类的私有成员和保护成员的方式。它在某些情况下可以简化代码实现,但同时也破坏了封装性,因此需要谨慎使用。

创建友元函数

要创建一个友元函数,需要按照以下步骤进行操作:

1、在类内声明友元函数:在类的声明中,使用 friend 关键字来声明友元函数。友元函数可以是全局函数,也可以是其他类的成员函数。例如,下面的代码将一个全局函数声明为类的友元函数:

class MyClass {
public:
    // 声明友元函数
    friend void myFriendFunction();
};

2、在类的外部定义友元函数:在类的外部,需要定义先前声明的友元函数。这样,友元函数就可以访问和操作类的私有成员和保护成员。例如,下面的代码定义了先前声明的友元函数:

// 定义友元函数
void myFriendFunction() {
    // 在此函数中可以访问和操作MyClass的私有成员和保护成员
}

3、使用友元函数:使用类的对象或类名和作用域解析运算符(::)调用友元函数。例如,下面的代码演示了如何使用类对象调用友元函数:

MyClass obj;
myFriendFunction();  // 使用类对象调用友元函数

或者,如果友元函数是另一个类的成员函数,可以使用该类的对象或类名和作用域解析运算符(::)调用友元函数。例如,下面的代码演示了如何使用类对象调用另一个类的成员函数作为友元函数:

class MyClass2 {
public:
    // 声明友元函数
    friend void MyClass::myFriendFunction2();
};

// 定义友元函数
void MyClass::myFriendFunction2() {
    // 在此函数中可以访问和操作MyClass2的私有成员和保护成员
}

MyClass obj;
MyClass2 obj2;
obj.myFriendFunction2();  // 使用类对象调用友元函数

 运算符重载

运算符重载是指在类中重定义运算符的行为,使其适用于特定的类对象。运算符重载可以使得类对象的使用更加自然和方便,同时也提供了更多的灵活性。

要重载运算符,需要定义一个类成员函数或全局函数来执行所需操作,该函数的名称是运算符本身,并使用 operator 关键字声明。例如,要重载"+"运算符,可以定义一个名为operator+()的函数。

以下是一个示例,演示了如何重载"+"运算符:

class MyClass {
private:
    int value;
public:
    MyClass(int v) : value(v) {}

    MyClass operator+(const MyClass& other) {  // 运算符重载函数
        return MyClass(value + other.value);
    }

    int getValue() const {
        return value;
    }
};

int main() {
    MyClass obj1(3);
    MyClass obj2(5);

    MyClass result = obj1 + obj2;  // 使用重载的"+"运算符

    std::cout << result.getValue() << std::endl;  // 输出结果:8

    return 0;
}

上述示例中,我们在MyClass类中重载了"+"运算符。重载函数声明中的参数是另一个MyClass对象(const引用),并返回一个新的MyClass对象。在main函数中,我们创建了两个MyClass对象,然后使用重载的"+"运算符将它们相加,最终得到一个新的MyClass对象。

需要注意的是,在重载运算符时,可以根据需要选择将函数定义为类成员函数全局函数(定义全局函数的时候需要将其声明为友元函数)。对于一些需要访问类私有成员的运算符,比如赋值运算符"=",通常选择将函数定义为类成员函数;对于一些不需要直接访问类私有成员的运算符,可以选择将函数定义为全局函数。

运算符重载可以大大简化代码,并提高可读性和可维护性。但是,需要谨慎使用运算符重载,以避免混淆和误用。同样,不应该过度使用运算符重载,以保持代码的简洁和易读性。

特殊运算符重载

1、赋值运算符重载
除了之前学习无参构造函数拷贝构造函数析构函数之外如果程序员手写编译器自动添加一个赋值运算符重载, 赋值运算符只能使用成员函数实现重载
当类中出现指针类型成员变量默认赋值运算符重载函数类似于默认浅拷贝构造函数因此也需要手动编写解决浅拷贝问题

【常见面试题】一个类如果什么都不编译添加了那些代码

无参构造函数拷贝构造函数析构函数赋值运算符重载函数

2、类型转换运算符重载

类型转换运算符重载允许将一个类的对象转换为另一个类型。

类型转换运算符重载的语法如下:

operator type() {
    // 进行类型转换的操作
}

其中,type是要转换的目标类型。重载的类型转换运算符可以是类的成员函数或类的非成员函数。

下面是一个示例,演示了如何重载类型转换运算符:

class MyClass {
private:
    int value;
public:
    MyClass(int v) : value(v) {}

    operator int() {
        return value;
    }
};

int main() {
    MyClass obj(42);

    int result = obj;  // 使用重载的类型转换运算符将MyClass对象转换为int

    std::cout << result << std::endl;  // 输出结果:42

    return 0;
}

在上述示例中,我们定义了一个名为MyClass的类,并在其中重载了类型转换运算符。重载函数声明中的返回类型是要转换的目标类型(int),并在函数体中返回了MyClass对象的value成员。

在main函数中,我们创建了一个MyClass对象,并将其赋值给一个int类型的变量。由于我们已经重载了类型转换运算符,所以可以直接将MyClass对象转换为int类型。最终,输出结果为42。

需要注意的是,在重载类型转换运算符时,应该在函数体中进行适当的类型转换操作,并返回目标类型的对象。此外,需要慎谨使用类型转换运算符,以避免混淆和误用。

另外,C++还提供了显式转换运算符重载(explicit conversion operator),通过在重载函数前加上 explicit 关键字来实现。这样,在使用显式转换运算符进行类型转换时,需要明确使用转换运算符进行转换。

注意事项

● 重载运算符限制在C++语言中已有运算符范围不能创建新的运算符

● 运算符重载本质上也是函数重载但是不支持函数参数默认值

● 之后运算符不能改变运算符优先级结合不能改变运算符操作数语法结构

● 运算符重载必须基于包含自定义类型不能改变基本数据类型运算规则

● 重载功能应该与原有功能类似避免没有目的滥用运算符重载

● 一般情况下双目运算符建议使用友元函数运算符重载单目运算符建议使用成员函数运算符重载

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

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

相关文章

智慧农业解决方案:华测农机导航技术助力无人农场高效作业

在金黄的麦田、翠绿的稻田中&#xff0c;农机导航正成为无人农场的新星。如今&#xff0c;无人收割、无人播种、无人插秧等作业模式已不再是遥不可及的梦想&#xff0c;而是智慧农业快速发展中的现实写照。搭载华测导航技术的农机&#xff0c;正在田间地头忙碌。它们如同舞者般…

71-TCP协议工作原理及实战

一 服务器端 #ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> #include <QTcpServer> // 专门用于建立TCP连接并传输数据信息 #include <QtNetwork> // 此模块提供开发TCP/IP客户端和服务器的类QT_BEGIN_NAMESPACE namespace Ui { class M…

亲测5个电脑浏览器高效技巧,保证让你搜索效率倍增!

虽然我们每个人的电脑基本每天都会用到浏览器&#xff0c;但你会发现有的人用起浏览器就是噼里啪啦的&#xff0c;找他要个什么网站他都能快速找到&#xff0c;而有的人&#xff0c;经常打开的是广告搜索的网页&#xff0c;找不到搜索的答案非常慢。小编今天就来跟你分享一下我…

跨区域文件管控解决方案,一文了解

跨区域文件管控是一个涉及在不同地域或区域之间管理和控制文件的过程&#xff0c;它包括安全性、合规性和管理效率等多个方面。以下是一些关键的考量因素&#xff1a; 1.安全性&#xff1a;确保在传输过程中文件不被截获、篡改或泄露。使用加密技术保护文件&#xff0c;并确保传…

解释React中的“端口(Portals)”是什么,以及如何使用它来渲染子节点到DOM树以外的部分。

React中的“端口&#xff08;Portals&#xff09;”是一种将子节点渲染到DOM****树以外的部分的技术。在React应用中&#xff0c;通常情况下组件的渲染是遵循DOM的层次结构&#xff0c;即子组件会渲染在父组件的DOM节点内部。然而&#xff0c;有些情况下&#xff0c;开发者可能…

ArcGIS图斑分区(组)排序—从上到下从左到右

​​ 点击下方全系列课程学习 点击学习—>ArcGIS全系列实战视频教程——9个单一课程组合系列直播回放 ArcGIS图斑分区&#xff08;组&#xff09;从上到下从左到右排序 是之前的内容的升级 GIS技巧100例——12ArcGIS图斑空间排序 关于今天的内容 我们在19年已经和大家分…

Linux机器通过Docker-Compose安装Jenkins发送Allure报告

目录 一、安装Docker 二、安装Docker Compose 三、准备测试用例 四、配置docker-compose.yml 五、启动Jenkins 六、配置Jenkins和Allure插件 七、创建含pytest的Jenkins任务 八、项目结果通知 1.通过企业微信通知 2.通过邮件通知 最近小编接到一个任务用来监测和巡检网…

win10手动安装stable-diffusion-webui

目录 1.python下载安装 2.git下载安装 3.stable-diffusion-webui下载 4.安装s-d-webui的依赖包&#xff08;用国内镜像提速&#xff09; 5.git下载的stable-diffusion-webui&#xff0c;依赖包提示已安装&#xff0c;但运行webui-user.bat后&#xff0c;又开始下载 6.修…

YOLOv10改进 | Neck | 添加双向特征金字塔BiFPN【含二次独家创新】

&#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录&#xff1a;《YOLOv8改进有效涨点》专栏介绍 & 专栏目录 | 目前已有40篇内容&#xff0c;内含各种Head检测头、损失函数Loss、B…

教你使用Python玩转MySQL数据库,大数据导入不再是难题!

数据分析离不开数据库&#xff0c;如何使用python连接MySQL数据库&#xff0c;并进行增删改查操作呢&#xff1f; 我们还会遇到需要将大批量数据导入数据库的情况&#xff0c;又该如何使用Python进行大数据的高效导入呢&#xff1f; 本文会一一讲解&#xff0c;并配合代码和实…

疯狂刷题python版 | 使用PySide6自制刷题软件【源码+解析】

疯狂刷题python版 | 使用PySide6自制刷题软件【源码解析】 一、前言二、思考三、软件设计四、软件实现&#xff08;一&#xff09;使用QWebEngineView控件通过JavaScript代码和chrome内核进行数据交互和逻辑控制&#xff08;二&#xff09;用户分别通过浏览器 GUI和PySide6 GUI…

秋招突击——6/19——复习{(单调队列优化)——最大子序列和,背包问题——宠物小精灵收服问题}——新作{两两交换链表中的节点}

文章目录 引言复习单调队列优化——最大子序列和思路分析实现代码参考实现 背包问题——宠物小精灵的收服问题个人实现参考实现 新作两两交换链表中的节点个人实现参考实现 删除有序数组中的重复项个人实现知识补全迭代器的访问和控制vector删除特定的元素erasevector底层删除元…

15-JS封装:入口函数

目录 1 模块化的基本结构 2 编写封装里的jQuery函数 2.1 对象本身上添加css方法 2.2 对象原型上添加css方法 2.3 自定义构造函数 2.4 优化1-伪数组 2.5 优化2-原型链 2.6 简化代码 需求&#xff1a;给页面中所有的div设置字体颜色为红色 jQuery封装&#xff1a;$("…

1964springboot VUE 智慧社区可视化平台系统开发mysql数据库web结构java编程计算机网页源码maven项目

一、源码特点 springboot VUE社区可视化平台系统是一套完善的完整信息管理类型系统&#xff0c;结合springboot框架和VUE完成本系统&#xff0c;对理解JSP java编程开发语言有帮助系统采用springboot框架&#xff08;MVC模式开发&#xff09;&#xff0c;系统具有完整的源代码…

INFINI Labs 助力开源与教育:免费许可证计划全面升级

在数字化浪潮席卷全球的今天&#xff0c;INFINI Labs 深刻认识到开源项目和教育机构在技术创新与人才培养中的核心作用。因此&#xff0c;我们郑重推出全新升级的免费许可证计划&#xff0c;旨在全球范围内为开源社区和教育界提供有力支持&#xff0c;共同推动软件生态的繁荣与…

策略模式编程

接口定义&#xff1a; public interface ProcessParserStrategy { List<ProcessInfo> parser(String osType, String processInfo); String getApp(); } public interface ConfigParserStrategy { List<ConfigInfo> parser(String configInfo); String getConfigT…

DC/AC电源模块:为通信设备提供稳定的电力供应

BOSHIDA DC/AC电源模块&#xff1a;为通信设备提供稳定的电力供应 在现代通信系统中&#xff0c;稳定可靠的电力供应是确保信息传输连续性和服务质量的关键因素之一。DC/AC电源模块作为通信设备能源管理的核心组件&#xff0c;扮演着至关重要的角色。它不仅负责将输入的直流电…

Spring自定义标签体系和应用

我们知道&#xff0c;在使用Dubbo框架时&#xff0c;需要指定配置文件中的application、protocol、registry、provider、service等服务器端和客户端的配置项&#xff0c;典型的配置方法如下所示。通过这些配置项&#xff0c;我们可以基于Spring容器来启动Dubbo服务。 <!-- …

pytorch lighting: Trying to resize storage that is not resizable

问题 在用pytorch lighting进行训练时碰到如下错误 即 Trying to resize storage that is not resizable 。 解决方案 在dataloader采样图片以及label时&#xff0c;保证每次采样的图片的分辨率不变。

抖去推,筷子剪辑,超级编导短视频矩阵系统,应该怎么选择?

选择一个适合您需求的软件平台&#xff0c;然后按照以下步骤进行选择&#xff1a; 研究和比较不同平台&#xff1a;比较不同的短视频编辑软件&#xff0c;例如抖音、快手等&#xff0c;看看它们提供了哪些功能和特点。 确定需求&#xff1a;确定您希望在短视频中实现的功能和效…