运算符重载(友元函数、运算符重载的形式、特殊运算符的重载、类型转换)

本文详细介绍了C++中的友元函数,包括其定义、存在形式及封装性,强调了友元函数在保持封装性的同时提供灵活性的重要性。接着讨论了运算符重载,包括其原则、不能重载的运算符、函数调用运算符、下标访问运算符和自增运算符的重载,特别强调了友元函数在重载自增运算符时的优势。
摘要由CSDN通过智能技术生成

友元函数

什么是友元函数

私有成员只能在类的成员函数内部访问,如果想在别处访问对象的私有成员,只能通过类提供的接口(成员函数)间接地进行。这固然能够带来数据隐藏的好处,利于将来程序的扩充,但也会增加程序书写的麻烦。

在面向对象编程中,友元函数(friend function)是一个指定类(class)的“朋友”,该函数被允许访问该类中private、protected、public的数据成员。普通的函数并不能访问这些数据,然而宣告一个函数成为一个类的友元函数则被允许访问这些数据。

友元函数的宣告可以放在类声明的任何地方,不受访问限定关键字private、protected、public的限制。一个相似的概念是友谊类。

友谊关键字应该谨慎使用。如果一个拥有private或者protected成员的类,宣告过多的友元函数,可能会降低封装性的价值,也可能对整个设计框架产生影响。

友元函数的存在形式有?
  • 友元函数之全局函数
    现在我们有一个全局函数 distance ,通过它计算两个点之间的距离,如果直接访问肯定是不行的,编译会报错。当我们在类Point中将其声明为友元之后,就可以了。
    在这里插入图片描述如图:
    在这里插入图片描述
  • 友元函数之成员函数
    假设类A有一个成员函数,该成员函数想去访问另一个类B类中的私有成员变量。这时候则可以在第二个类B中,声明第一个类A的那个成员函数为类B的友元函数,这样第一个类A的某个成员函数就可以访问第二个类B的私有成员变量了。同样还是求取两个点之间的距离,现在我们再定义一个类 Line ,由Line 中的成员函数 distance 完成:
  • 友元之友元类
    如上的例子,假设类 Line 中不止有一个 distance 成员函数,还有其他成员函数,它们都需要访问Point 的私有成员,如果还像上面的方式一个一个设置友元,就比较繁琐了,可以直接将 Line 类设置为 Point 的友元。

在这里插入图片描述

友元函数的封装性

不可否认,友元在一定程度上将类的私有成员暴露出来,破坏了信息隐藏机制,似乎是种“副作用很大的药”,但俗话说“良药苦口”,好工具总是要付出点代价的,拿把锋利的刀砍瓜切菜,总是要注意不要割到手指的。

友元的存在,使得类的接口扩展更为灵活,使用友元进行运算符重载从概念上也更容易理解一些,而且, C++ 规则已经极力地将友元的使用限制在了一定范围内,它是单向的、不具备传递性、不能被继承,所以,应尽力合理使用友元。

注意:友元的声明是不受 public/protected/private 关键字限制的。

运算符重载

运算符重载的原则

1.不能无中生有(不能定义新的运算符),也不要改变运算符的原有意义。
2.重载不能改变运算符运算对象(即操作数)的个数。
3.重载不能改变运算符的优先级与结合性。
4.重载运算符的函数不能指定默认的参数值。
5.重载运算符函数的参数应至少有一个是类对象(或类对象的引用),不能都是基本类型。

不能重载的运算符
作用域操作符:::

条件操作符:?:

点操作符:.

指向成员操作的指针操作符:->*,.*

 还有 sizeof运算符

.、.*运算符不能重载是为了保证访问成员的功能不能被改变,域运算和sizeof运算符的运算对象是类型而不是变量或一般表达式,不具备重载的特征。

函数调用运算符


使用静态变量计数
在这里插入图片描述
使用私有成员变量

私有成员体现了封装性的特点,而静态全局变量只是起到了一个计数的作用,是共享的。除此之外,func函数只是在逻辑顺序上的执行,而fo可以无限的创建,函数对象可以体现出状态。

一般地,把这种带有状态的函数对象成为闭包—>匿名函数—>lambda表达式

下标访问运算符

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在C++对下标访问运算符重载的好处
1.增加 安全性,对下标进行判断,相比C里面数组安全
2.重载【】之后,可以放在等号的左边

在什么情况下,需要加引用符号
1.防止返回值是对象的时候调用拷贝构造函数
2.允许连续赋值的时候,cout << “hello” << endl;

运算符重载—自增

1.运算符重载之普通函数形式进行重载
在这里插入图片描述
2.运算符重载之成员函数
在这里插入图片描述
3.运算符重载之友元函数的形式进行重载(可以直接对类的私有成员进行操作,非常方便,并且符合加法的习惯,两个操作数,没有采用隐藏this指针的方式,只有一个操作数出现,不符合加法习惯,推荐使用以友元函数的形式进行重载)
在这里插入图片描述特别地,如果以自身状态为改变目标的重载,可以以成员函数的形式进行重载,比较方便。比如这里+=, -=, /=都可以以这种成员函数方式进行重载。
在这里插入图片描述

特殊运算符的重载

前置和后置++的运算符重载

在这里插入图片描述
非常清晰,后置++首先要把表达式的值保存下来,之后对成员变量进行++,然后返回保存下来的表达式的值,注意顺序。其中后置++中参数列表中有一个int,这只表示着,后置++的一个标示,不代表传参。这是实现c++的大佬写的,大佬就是规则的制定者,记住吧少年

这里com是一个局部变量,所以要注意千万不要返回引用,这里要把引用去掉。

这里也可以看得出,前置++和后置++是有区别的,前置++的效率都说效率很高,因为前置++返回的是一个引用,是对象本身后置++返回的是一个局部对象,包含一个执行拷贝构造函数的过程,所以相比下来,效率就比前置++的 执行效率低。

看一个有意思的左值和右值
在这里插入图片描述前置++返回的是对象本身,所以可以加取地址符号,是左值。
而后置++返回的是一个局部变量,是右值。

运算符重载代码:

#include <iostream>
#include <string.h>
#include <vector>

using std::cin;
using std::endl;
using std::cout;
using std::cerr;
using std::vector;
class String {
   
public:
    String()
        : _pstr(nullptr)
    {
   
        cout << "String()" << endl;
    }


    String(const char *pstr)
    {
   
        cout << "String(const char*)" << endl;
        _pstr = new char[strlen(pstr) + 1];
        strcpy(_pstr, pstr);
    }


    String(const String &pstr){
   
        cout << "String(const String&)" << endl;
        _pstr = new char[strlen(pstr._pstr) + 1];
        strcpy(_pstr, pstr._pstr);
    }

    ~String(){
   
        cout << "~String()" << endl;
        if(_pstr != nullptr){
   
            delete _pstr;
            _pstr = nullptr;
        }
    }
    void display() const
    {
   
        cout << _pstr << endl;
    }
    String &operator=(const String &);
    String &operator=(const char *);

    String &operator+=(const String &
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值