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

2024-06-21 10:04

本文主要是介绍从0开始C++(五):友元函数运算符重载,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

友元函数

介绍

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;  // 输出结果:8return 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对象转换为intstd::cout << result << std::endl;  // 输出结果:42return 0;
}

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

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

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

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

注意事项

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

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

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

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

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

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

这篇关于从0开始C++(五):友元函数运算符重载的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1080910

相关文章

C++使用栈实现括号匹配的代码详解

《C++使用栈实现括号匹配的代码详解》在编程中,括号匹配是一个常见问题,尤其是在处理数学表达式、编译器解析等任务时,栈是一种非常适合处理此类问题的数据结构,能够精确地管理括号的匹配问题,本文将通过C+... 目录引言问题描述代码讲解代码解析栈的状态表示测试总结引言在编程中,括号匹配是一个常见问题,尤其是在

使用C++实现链表元素的反转

《使用C++实现链表元素的反转》反转链表是链表操作中一个经典的问题,也是面试中常见的考题,本文将从思路到实现一步步地讲解如何实现链表的反转,帮助初学者理解这一操作,我们将使用C++代码演示具体实现,同... 目录问题定义思路分析代码实现带头节点的链表代码讲解其他实现方式时间和空间复杂度分析总结问题定义给定

C++初始化数组的几种常见方法(简单易懂)

《C++初始化数组的几种常见方法(简单易懂)》本文介绍了C++中数组的初始化方法,包括一维数组和二维数组的初始化,以及用new动态初始化数组,在C++11及以上版本中,还提供了使用std::array... 目录1、初始化一维数组1.1、使用列表初始化(推荐方式)1.2、初始化部分列表1.3、使用std::

C++ Primer 多维数组的使用

《C++Primer多维数组的使用》本文主要介绍了多维数组在C++语言中的定义、初始化、下标引用以及使用范围for语句处理多维数组的方法,具有一定的参考价值,感兴趣的可以了解一下... 目录多维数组多维数组的初始化多维数组的下标引用使用范围for语句处理多维数组指针和多维数组多维数组严格来说,C++语言没

Python itertools中accumulate函数用法及使用运用详细讲解

《Pythonitertools中accumulate函数用法及使用运用详细讲解》:本文主要介绍Python的itertools库中的accumulate函数,该函数可以计算累积和或通过指定函数... 目录1.1前言:1.2定义:1.3衍生用法:1.3Leetcode的实际运用:总结 1.1前言:本文将详

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

MySQL数据库函数之JSON_EXTRACT示例代码

《MySQL数据库函数之JSON_EXTRACT示例代码》:本文主要介绍MySQL数据库函数之JSON_EXTRACT的相关资料,JSON_EXTRACT()函数用于从JSON文档中提取值,支持对... 目录前言基本语法路径表达式示例示例 1: 提取简单值示例 2: 提取嵌套值示例 3: 提取数组中的值注意

c++中std::placeholders的使用方法

《c++中std::placeholders的使用方法》std::placeholders是C++标准库中的一个工具,用于在函数对象绑定时创建占位符,本文就来详细的介绍一下,具有一定的参考价值,感兴... 目录1. 基本概念2. 使用场景3. 示例示例 1:部分参数绑定示例 2:参数重排序4. 注意事项5.

使用C++将处理后的信号保存为PNG和TIFF格式

《使用C++将处理后的信号保存为PNG和TIFF格式》在信号处理领域,我们常常需要将处理结果以图像的形式保存下来,方便后续分析和展示,C++提供了多种库来处理图像数据,本文将介绍如何使用stb_ima... 目录1. PNG格式保存使用stb_imagephp_write库1.1 安装和包含库1.2 代码解

C++实现封装的顺序表的操作与实践

《C++实现封装的顺序表的操作与实践》在程序设计中,顺序表是一种常见的线性数据结构,通常用于存储具有固定顺序的元素,与链表不同,顺序表中的元素是连续存储的,因此访问速度较快,但插入和删除操作的效率可能... 目录一、顺序表的基本概念二、顺序表类的设计1. 顺序表类的成员变量2. 构造函数和析构函数三、顺序表