C++ operator的细节

C++ operator的细节

运算符重载是C++重要的特性之一,可以是代码看起来更加自然,使编写者在编写代码时操作更加方便。

运算符重载的限制:

  • 重载后运算符的操作数至少有一个是用户定义类型。

  • 不能违反原来操作数的语法规则。

  • 不能创建新的运算符。

  • 不能重载 sizeof 运算符,. 运算符,.* 运算符,:: 运算符, ?: 运算符,RTTI类型运算符。

  • = 运算符,() 运算符,[] 运算符,-> 运算符只能被成员函数重载。

前缀与后缀

一元运算符往往有前缀和后缀两种意义,那么他们在重载时就需分别进行重载。

前缀运算符重载规则:参数列表为空。

后缀运算符重载规则:参数列表有一个匿名的int参数。

//main.cpp
# include <iostream>

class  C
{
public:
    explicit C(int i = 0) :m_i(i) {}
    ~C() {}
    C operator ++()//前自增
    {
        ++m_i;//增加
        return *this;//返回现在的的状态
    }
    C operator ++(int)//后自增
    {
        C tmp(*this);//备份现在的状态
        ++m_i;//增加
        return tmp;//返回先前的的状态
    }
    C operator +()//正号
    {
        C tmp(*this);//拷贝当前状态
        tmp.m_i = +tmp.m_i;//取正
        return tmp;//返回临时对象
    }
    C operator -()//负号
    {
        C tmp(*this);//拷贝当前状态
        tmp.m_i = -tmp.m_i;//取负
        return tmp;//返回临时对象
    }
    friend std::ostream & operator <<(std::ostream & os, const C & other)
    {
        os << other.m_i;
        return os;
    }
private:
    int m_i;
};

int main()
{
    C obj(9);
    std::cout << ++obj << std::endl;
    std::cout << obj++ << std::endl;
    std::cout << -obj << std::endl;
    std::cout << +obj << std::endl;
    return 0;
    /*
    10
    10
    -11
    11
    */
}

new与delete

内存管理运算符通常不需要重载。但如果需要检测代码中的内存错误,优化性能,获得内存使用的统计等,可以重载内存管理运算符实现功能。

new运算符和new[]运算符重载规则:参数个数任意,但第一个参数必须是size_t类型的,返回值必须是void*类型。

delete运算符和delete[]运算符重载规则:只允许有一个参数,且是void*类型,返回值必须是void类型。

//main.cpp
# include <iostream>
# include <list>

using namespace std;

//定义内存信息类
class MemInfo
{
public:
    MemInfo(void *address, size_t size, const char *file, size_t line)
    {
        m_address = address;
        m_size = size;
        strcpy(m_file, file);
        m_line = line;
    }
    ~MemInfo() {}
    void *GetMemoryAddress()const
    {
        return m_address;
    }
    friend ostream & operator <<(ostream & os, const MemInfo & meminfo)
    {
        os << "0x" << meminfo.m_address << " ";
        os << meminfo.m_size << "Byte" << " ";
        os << meminfo.m_file << " ";
        os << meminfo.m_line;
        return os;
    }
private:
    void *m_address;
    size_t m_size;
    char m_file[64];
    size_t m_line;
};

//创建全局内存分配表
list<MemInfo> MemAllocList;

//重载内存管理运算符
void *operator new(size_t size, const char *file, size_t line)
{
    void *p = NULL;
    p = malloc(size);
    //添加内存信息到内存分配表中
    MemAllocList.push_back(MemInfo(p, size, file, line));
    return p;
}
void *operator new[](size_t size, const char *file, size_t line)
{
    return operator new(size, file, line);
}
void operator delete(void *p)
{
    for (list<MemInfo>::iterator MemItr = MemAllocList.begin(); MemItr != MemAllocList.end() && (!MemAllocList.empty()); MemItr++)
    {
        if (MemItr->GetMemoryAddress() == p)
        {
            //删除内存分配表中的此内存信息
            MemAllocList.erase(MemItr);
            break;
        }
    }
    free(p);
}
void operator delete[](void *p)
{
    operator delete(p);
}

//重载内存分配表的流输出运算符
ostream & operator <<(ostream & os, const list<MemInfo> & memalloclist)
{
    for (list<MemInfo>::const_iterator MemItr = memalloclist.begin(); MemItr != memalloclist.end(); MemItr++)
    {
        os<<*MemItr<<endl;
    }
    return os;
}

//创建宏进行替换
#define new new(__FILE__,__LINE__)

int main()
{
    int *var_1 = new int;
    double *var_2 = new double[10];
    char *var_3 = new char('4');
    cout << "Before delete:" << endl;
    cout << MemAllocList;
    delete []var_2;
    cout << "After delete:" << endl;
    cout << MemAllocList;
    /*
    Before delete:
    0x014ACA70 4Byte d:\projects\c++\test\test\main.cpp 87
    0x014A79F8 80Byte d:\projects\c++\test\test\main.cpp 88
    0x014AE710 1Byte d:\projects\c++\test\test\main.cpp 89
    After delete:
    0x014ACA70 4Byte d:\projects\c++\test\test\main.cpp 87
    0x014AE710 1Byte d:\projects\c++\test\test\main.cpp 89
    */
    return 0;
}

重载转换函数也用operator

在重载转函数时,用operator关键字进行重载。重载转换函数必须为类成员函数,返回值不需要与重载转换函数的类型一致,因为C++会根据转换函数的类型进行隐式转换。

重载规则:不能指定返回类型,并且形参表必须为空。

//main.cpp
# include <iostream>

class  C
{
public:
    explicit C(int i = 0) :m_i(i) {}
    ~C() {}
    operator int()
    {
        return m_i;
    }
    operator char()
    {
        return m_i;
    }
    friend std::ostream & operator <<(std::ostream & os,const C & other)
    {
        os << other.m_i;
        return os;
    }
private:
    int m_i;
};

int main()
{
    C obj(65);
    std::cout << int(obj) << std::endl;
    std::cout << char(obj) << std::endl;
    return 0;
    /*
    65
    A
    */
}

何时需要friend

当两不同类型的操作数进行运算时,重载的运算符函数总是后一个操作数类型的友元函数。因为私有的数据,普通函数无法访问,所以必须定义为友元函数才能访问。

重载规则:在所需类型中定义为友元函数。

//main.cpp
# include <iostream>

class  C
{
public:
    explicit C(int i = 0) :m_i(i) {}
    ~C() {}
    friend C operator +(int i,const C & obj)
    {
        C tmp;
        tmp.m_i = i + obj.m_i;
        return tmp;
    }
    friend std::ostream & operator <<(std::ostream & os,const C & other)
    {
        os << other.m_i;
        return os;
    }
private:
    int m_i;
};

int main()
{
    C obj_1(0);
    C obj_2(1);
    obj_1 = 2 + obj_2;
    std::cout << obj_1 << std::endl;
    return 0;
    /*
    3
    */
}

何时需要返回引用类型

当需要重载运算符实现链式调用时,就需要将重载运算符的返回值设置为引用类型。

重载规则:设置返回值为引用类型。

//main.cpp
# include <iostream>

class  C
{
public:
    explicit C(int i = 0) :m_i(i) {}
    ~C() {}
    C  operator =(const C & obj)
    {
        if (&obj != this)
        {
            m_i = obj.m_i;
        }
        return *this;;
    }
    friend std::ostream & operator <<(std::ostream & os, const C & other)
    {
        os << other.m_i;
        return os;
    }
private:
    int m_i;
};

int main()
{
    C obj_1(0);
    C obj_2(1);
    C obj_3(2);
    obj_1 = obj_2 = obj_3;//obj_1.operator=(obj_2.operator=(obj_3));
    std::cout << obj_1 << std::endl;
    std::cout << obj_2 << std::endl;
    std::cout << obj_3 << std::endl;
    return 0;
    /*
    2
    2
    2
    */
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值