C++学习五:运算符重载

一.友元

类的数据成员一般定义为私有成员,仅能通过类的成员函数才能读写。如果数据成员定义成公共的,则又破坏了封装性。在某些情况下需要频繁调用数据成员,但是参数传递类型检查都需要时间消耗,所以设计了友元,友元不是类的成员,但是却可以调用类的成员变量.

1.友元函数

友元函数是一种定义在类外部的普通函数,但是需要在类中进行声明。为了和该类的普通成员函数加以区别,在声明前面加了一个关键字friend。友元函数不是成员函数,但是他能够访问类中的私有成员。

注意事项

  • 友元函数没有this指针,因为友元函数不是成员函数
  • 友元函数的“声明”可以放置到类中的任何位置,不受权限修饰符的影响。
  • 一个友元可以访问多个类,只需要在各个类中分别“声明”。

2.友元类

当一个类B成为了另一个类Test的朋友时,类Test的所有成员都能被类B访问,此时类B就是类Test的友元类。

注意事项:

  • 友元关系不能被继承
  • 友元关系不具有交换性(比如:类B声明成类Test的友元,类B可以访问类Test所有的成员,但是类Test不能访问类B中的私有成员,如果需要访问,需要将类Test声明成类B的友元,即互为友元

3.友元成员函数

使类B中的成员函数成为类Test的友元成员函数,这样类B的该成员函数就可以访问类Test的所有成员了。

友元成员函数的声明格式

friend 数据类型 类名::成员函数名(参数);

二.运算符重载

可以将运算符看做是函数处理,比如+实际上就是add函数,而a+b中的a,b就是参数,返回值就是和.

所以函数可以重载,运算符也可以重载,但是存在不能重载的运算符     . (成员运算符)  *(指针运算符)   ?  :(三目运算符)    sizeof   ::(作用域)    

1.友元函数运算符重载

#include <iostream>
using namespace std;

class MyInt
{
private:
    int a;
public:
    MyInt(int a):a(a){}

    int get_int()
    {
        return a;
    }

    // + 运算符重载
    friend MyInt operator +(MyInt &i,MyInt &i2);
};

// 友元函数 实现
MyInt operator +(MyInt &i,MyInt &i2)
{
    // int → MyInt 触发构造函数隐式调用
    return i.a + i2.a;
}


int main()
{
    MyInt int1(2);
    MyInt int2(int1);   // 拷贝构造函数

    MyInt int3 = int1 + int2;    

    cout << int3.get_int() << endl;    // 4

    return 0;
}

2.成员函数运算符重载

成员函数运算符重载相比于友元函数重载,最主要的区别在于,友元函数的第一个输出参数,在成员函数运算符重载中使用this指针代替。因此相同的运算符重载,成员函数运算符重载比友元函数运算符重载参数少一个。

#include <iostream>
using namespace std;

class MyInt
{
private:
    int a;
public:
    MyInt(int a):a(a){}

    int get_int()
    {
        return a;
    }


    MyInt operator +(MyInt &i2);
    
    MyInt operator ++();
    MyInt operator ++(int);
};

// 成员函数 类外实现
MyInt MyInt::operator +(MyInt &i2)
{
    // int → MyInt 触发构造函数隐式调用
    return this->a + i2.a;
}

// 前置自增
MyInt MyInt::operator ++()
{
    return ++this->a;
}



// 后置自增
MyInt MyInt::operator ++(int)
{
    return this->a++;
}

int main()
{
    MyInt int1(2);
    MyInt int2(int1);   // 拷贝构造函数

    MyInt int3 = int1 + int2;
    cout << (++int3).get_int() << endl;
    cout << int3.get_int() << endl;

    return 0;
}

3.特殊运算符重载

赋值运算符重载

如果不写,编译器会自动添加一个赋值运算符重载函数,

#include <iostream>
using namespace std;

class MyInt
{
private:
    int a;
public:
    MyInt(int a):a(a){}

    int get_int()
    {
        return a;
    }

    // 编译器会自动添加赋值运算符重载函数
    MyInt & operator =(MyInt &i)
    {
        cout << "赋值运算符被调用了" << endl;    // 编译器自动添加的赋值运算符重载函数不会打印这句话
        this->a = i.a;
        return *this;
    }
};


int main()
{
    MyInt int1(2);

    MyInt int4(3);
    cout << int4.get_int() << endl;
    int4 = int1;    // 赋值运算符重载
    cout << int4.get_int() << endl;
    return 0;
}

编译器会自动添加哪些函数?

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

类型转换运算符重载

必须使用成员函数运算符重载,且格式特殊

#include <iostream>
using namespace std;

class MyInt
{
private:
    int a;
    string str = "hello";
public:
    MyInt(int a):a(a){}

    int get_int()
    {
        return a;
    }

    // 编译器会自动添加赋值运算符重载函数
    MyInt & operator =(MyInt &i)
    {
        cout << "赋值运算符被调用了" << endl;    // 编译器自动添加的赋值运算符重载函数不会打印这句话
        this->a = i.a;
        return *this;
    }

    // 类型转换运算符重载
    operator int()
    {
        return a;
    }

    operator string()
    {
        return str;
    }
};


int main()
{
    MyInt int1(2);
    int a = int1;
    string str = int1;
    cout << a << endl;
    cout << str << endl;

    return 0;
}

4.运算符重载注意事项

  • 重载的运算符限制在C++语言中已有的运算符范围,不能创建新的运算符。
  • 运算符重载的本质也是函数重载,但是不支持函数参数默认值设定。
  • 重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符的操作数和语法结构。
  • 运算符重载必须基于或包含自定义类型,即不能改变基本数据类型的运算符规则。
  • 重载功能应该与原有功能类似,避免没有目的的滥用运算符重载。
  • 一般情况下,双目运算符建议使用友元函数进行重载,单目运算符建议使用成员函数进行重载。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值