c++的运算符重载

运算符重载

在设计结构、联合、类时,为了让它们的对象的操作更简便、易懂,我们会为它们实现部分运算符函数,这种行为被称为运行符重载,我们以自定义string为例进行讲解运算符重载。

1、双目运算符重载
重载为成员运算符函数

1、左边的运算对象如果可能是常量,则需要把运算符函数设置为常函数。

2、如果右边的运算对象可能是常量,则需要给形参设置const属性。

3、一般在运算符函数中不修改运算对象的数据,而是由左右的运算对象的运算结果产生临时对象。

#include <iostream>
#include <stdlib.h>
using namespace std;
​
class Int
{
    int num;
public:
    Int(int num):num(num) {}
    // 双目运算符 成员函数
    const Int operator+(const Int& that)const
    {
        return Int(num+that.num);
    }
    const Int operator-(const Int& that)const
    {
        return Int(num-that.num); 
    }
    const Int operator*(const Int& that)const
    {
        return Int(num*that.num); 
    }
    const Int operator/(const Int& that)const
    {
        return Int(num/that.num); 
    }
    const Int operator%(const Int& that)const
    {
        return Int(num%that.num); 
    }
};

重载为全局运算符函数

给类对象优先重载成员运算符函数时,必须要在类的内部实现,当无法修改对象的源码时,也就无法在结构、联合、类的内部增加成员运算符函数,又想给类对象增加运行符函数,这种情况只能定义全局的运算符函数,把运算对象都作为参数传递给运算符函数。

如何在全局运行符函数内访问私有成员—友元

当一个非成员函数,需要访问类中的私有成员时,可以把函数设置为该类的friend函数(也叫友元函数),这样在函数内就可以访问类的所有成员变量和成员函数。

一般情况下,在类的内部进行声明该函数(头文件内),并在声明的前面添加friend关键字,在类外实现友元函数。

也可以直接在类的内部实现有友函数,即使在类的内部实现也依然不是成员函数。

当重载全局运算符函数基本上都需要使用友元函数,我个人建议把友元函数实现在类的内部。

#include <iostream>
#include <stdlib.h>
using namespace std;
​
class Int
{
    int num;
public:
    Int(int num):num(num) {}
    void show(void)const
    {
        cout << "num=" << num << endl;
    }
    friend const Int operator-(const Int& i1,const Int& i2);
    friend const Int operator*(const Int& i1,const Int& i2);
    friend const Int operator/(const Int& i1,const Int& i2);
    friend const Int operator%(const Int& i1,const Int& i2);
};
​
const Int operator-(const Int& i1,const Int& i2)
{
    return Int(i1.num-i2.num+100);
}
const Int operator*(const Int& i1,const Int& i2)
{
    return Int(i1.num*i2.num+100);
}
const Int operator/(const Int& i1,const Int& i2)
{
    return Int(i1.num/i2.num+100);
}
const Int operator%(const Int& i1,const Int& i2)
{
    return Int(i1.num%i2.num+100);
}

3、输入、输出运算符重载

1、cin、cout是标准库中具有输入、输出功能的类对象,它的类名叫istream、ostream,当我们想给某种类对象增加输入、输出的功能时,就需要实现 >>、<<运算符函数对于该类对象的支持,也就是重载输入、输出运算符。

2、由于cin、cout都在>>、<<运算的左边,如果想实现成员运算符函数,就需要在istream、ostream类中实现,而我们无法增加或修改istream、ostream类的代码,所以只能实现全局的 >>、<< 运算符函数。

3、由于输入、输出过程中需要使用cin、cout记录成功、失败等状态,所以输入、输出函数的istream、ostream要使用引用,且不能用const修饰。

4、输入、输出过程中还可能要访问对象的 私有、保护的成员,所以全局的 >>、<< 运算符函数有必要设置成友元函数(右边对象)。

friend ostream& operator<<(ostream& os,const <类名>& obj)
{
    return os << obj.成员1 << obj.成员1 << ...;
}
friend istream& operator>>(istream& is,<类名>& str)
{
    return is >> obj.成员1 >> obj.成员1 >> ...;
}

练习:实现自定义的MyString类,实现它的构造、拷贝构造、赋值、析构,并重载以下运算符。

==
>
<
>=
<=
!=
​
+
+=
>>
<<

4、单目运算符的重载

单目运算符的重载与双目运算符重载的规则几乎相同,只是运算对象数量不同而已

重载为成员运算符函数

唯一的运算对象就是函数的调用者,参数列表为空,[cosnt] T[&] operator<单目运算符>(void)[const]

#include <iostream>
#include <stdlib.h>
using namespace std;
​
class Int
{
    int num;
public:
    Int(int num):num(num) {}
    const Int operator-(void)const
    {
        return Int(0-num);
    }
    bool operator!(void)const
    {
        return !num;
    }
    const Int operator~(void)const
    {
        return Int(~num);
    }
    Int* operator&(void)
    {
        return (Int*)&num;
    }
    const Int* operator&(void)const
    {
        return (const Int*)&num;
    }
    void show(void)const
    {
        cout << "num=" << num << endl;
    }
};

重载为全局运算符函数

与双目运算符一样,只有无法修改运算对象的代码时,才会重载全局运算符函数,参数列只有一个,[cosnt] T[&] operator<单目运算符>([const] T&)[const]

#include <iostream>
#include <stdlib.h>
using namespace std;
​
class Int
{
    int num;
public:
    Int(int num):num(num) {}
    void show(void)const
    {
        cout << "num=" << num << endl;
    }
    
    friend const Int operator-(const Int& that)
    {
        return Int(0-that.num);
    }
    friend bool operator!(const Int& that)
    {
        return !that.num;
    }
    friend const Int operator~(const Int& that)
    {
        return ~that.num;
    }
    friend Int* operator&(Int& that)
    {
        return (Int*)&that.num;
    }
    friend const Int* operator&(const Int& that)
    {
        return (const Int*)&that.num;
    }
};

注意:尽量重载为成员运算符函数。

5、自变运算符重载
前自变运算符重载 ++i/--i

前自变运算符与普通的单目运算符重载方法相同。

后自变运算符重载 ++i/--i

后自变运算符的运算对象也只有一个,为了区别前自变,我们需要在参数列增加一个什么都不做的int关键字,我们把这种用法叫哑元

#include <iostream>
#include <stdlib.h>
using namespace std;
​
class Int
{
    int num;
public:
    Int(int num):num(num) {}
    void show(void)const
    {
        cout << "num=" << num << endl;
    }
    Int& operator++(void)
    {
        num++;
        cout << "前++" << endl;
        return *this;
    }
    Int operator++(int) // 哑元
    {
        cout << "后++" << endl;
        return Int(num++);  
    }
    /*
    friend Int& operator++(Int& that)
    {
        cout << "前++" << endl;
        that.num++;
        return that;
    }
    friend Int operator++(Int& that,int) // 哑元
    {
        cout << "后++" << endl;
        return Int(that.num++);
    }
    */
};

6、new/delete运算符的重载

在C++中是把new/delete关键字当作运算符,也就是运算符函数,所以如果有特殊需要可以对它们进行重载,重载格式参考单目运算符。

new运算符的重载:

new 运算符有两中用法,也就有两个格式重载函数。

格式1:new TYPE

该格式既可以重载为全局函数,也可以重载为成员函数。

格式2:new(ptr) TYPE

该格式只能重载为成员函数,因为C++标准库中已经为该格式的函数。

new/delete运算符有什么用:

1、记录下申请、释放的内存块的地址,方便程序员检测是否有内存泄漏。

2、防止用户大量分配、释放小块内存,产生内存碎片。

3、默认的new只能给类对象分配内存,重载后可以给成员指针一起分配内存,该方法适合重载为类的成员函数。

void* operator new(size_t size)
{
    void* ptr = malloc((size/4+1)*4);
    cout << ptr << "自定义的new"<< endl;
    return ptr;
}
void operator delete(void* ptr)
{
    cout << ptr << "自定义的delete" << endl;
    free(ptr);
}
#include <iostream>
#include <stdlib.h>
using namespace std;
​
class Student
{
    char sex;
    short age;
    float score;
public:
    char* name;
    void* operator new(size_t size)
    {
        cout << "自定义的new运算符成员函数" << endl;
        Student* stup = (Student*)malloc(size);
        stup->name = (char*)malloc(20);
        return stup;
    }
    void operator delete(void* ptr)
    {
        cout << "自定义的delete运算符成员函数" << endl;
        Student* stup = (Student*)ptr;
        free(stup->name);
        free(stup);
    }
};
int main(int argc,const char* argv[])
{
    Student* stup = new Student;
    delete stup;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值