C++运算符重载

发布于 2023-05-03  1119 次阅读


一个简单的类

class test
{
private:
    int m_a,m_b;
    int *p;//存储m_a的地址
};

1.算数运算符重载

加号运算符的重载 (其他运算符同理)

1.1 全局函数重载

class test
{
private:
    int m_a, m_b;

public:
    test(int a = 0, int b = 0) : m_a(a), m_b(b) {}
    friend test operator+(const test &a, const test &b);
    //类外无法访问到类内的私有成员  需要将该函数添加为友元
    void display()
    {
        cout << "m_a:" << m_a << endl;
        cout << "m_b:" << m_b << endl;
    }
};
test operator+(const test &a, const test &b)
{
    test tmp;
    tmp.m_a = a.m_a + b.m_a;
    tmp.m_b = a.m_b + b.m_b;
    return tmp;
}

1.2 成员函数重载

class test
{
private:
    int m_a, m_b;

public:
    test(int a = 0, int b = 0) : m_a(a), m_b(b) {}
    test operator+(const test &b)//此时本对象相当于全局函数中的参数a
    {
        test tmp;
        tmp.m_a = m_a + b.m_a;
        tmp.m_b = m_b + b.m_b;
        return tmp;
    }
    void display()
    {
        cout << "m_a:" << m_a << endl;
        cout << "m_b:" << m_b << endl;
    }
};

2.左移运算符重载

例:将下面代码中的display改为用cout进行输出

class test
{
private:
    int m_a, m_b;

public:
    test(int a = 0, int b = 0) : m_a(a), m_b(b) {}
    void display()
    {
        cout << "m_a:" << m_a << endl;
        cout << "m_b:" << m_b << endl;
    }
};
//注意:左移运算符不应在类内重载 (类内重载格式为 tmp<<cout; 不符合书写规范)
//注意添加友元
ostream &operator<<(ostream &os, const test &t)
{
    os << "m_a:" << t.m_a << endl;
    os << "m_b:" << t.m_b << endl;
    return os;
}

对于上面的代码 cout为ostream类型且只能存在一个 所以需要用引用

返回值要以引用方式返回 保证可以进行链式操作

3.自增运算符重载

class test
{
private:
    int m_a, m_b;

public:
    friend test operator+(const test &a, const test &b);
    friend ostream &operator<<(ostream &os, const test &t);
    test(int a = 0, int b = 0) : m_a(a), m_b(b) {}
    //返回一个引用 便于处理++(++t)等情况
    test &operator++()//前置++
    {
        m_a++,m_b++;
        return *this;
    }
    test &operator++(int)//后置++
    {
        //先存储初始值 自增后再返回初值
        test tmp = *this;
        m_a++,m_b++;
        return tmp;
    }
};

C++通过占位参数 (类型必须为int) 来区分前置和后置自增

(理论上++i的效率比i++更高)

4.赋值运算符重载

C++默认实现了赋值操作(浅拷贝)

当类内存在指针时 为了避免重复释放 需要重载赋值运算符(使用深拷贝)

4.1 错误代码

class test
{
private:
    int m_a, m_b;
    int *p;

public:
    test(int a = 0, int b = 0) : m_a(a), m_b(b), p(new int(m_a)) {}
    ~test()
    {
        if (p != NULL)
        {
            delete p;
            p = NULL;
        }
    }
};
int f()
{
    test a(1, 2), b;
    b = a;
    //此时a b中的指针指向同一块内存区域
    //当释放掉一个后 再次释放就会出错(第二个类内p仍然不为NULL)
}

4.2 解决方法

对赋值运算符进行重载 为第二个类的指针开辟一块新空间

class test
{
private:
    int m_a, m_b;
    int *p;

public:
    test(int a = 0, int b = 0) : m_a(a), m_b(b), p(new int(m_a)) {}
    ~test()
    {
        if (p != NULL)
        {
            delete p;
            p = NULL;
        }
    }
    test &operator=(const test &t)
    {
        m_a = t.m_a;
        m_b = t.m_b;
        p = new int(t.m_a);
        return *this;
    }
};

返回引用可以实现 a=b=c; 的操作

赋值运算符不能重载为全局函数

5.关系运算符重载

具体根据代码需要进行重载

class test
{
private:
    int m_a, m_b;

public:
    test(int a = 0, int b = 0) : m_a(a), m_b(b) {}
    bool operator==(const test &t)
    {
        return (m_a == t.m_a && m_b == t.m_b);
    }
    bool operator!=(const test &t)
    {
        return (m_a != t.m_a && m_b != t.m_b);
    }
    bool operator>(const test &t)
    {
        return (m_a + m_b > t.m_a + t.m_b);
    }
};

6.函数调用运算符重载

仿函数(没有固定写法)

class test
{
private:
    int m_a, m_b;

public:
    test(int a = 0, int b = 0) : m_a(a), m_b(b) {}
    void operator()(int a, int b)
    {
        m_a = a;
        m_b = b;
    }
    void operator()()
    {
        cout << "m_a = " << m_a << endl;
        cout << "m_b = " << m_b << endl;
    }
};
//调用
int main()
{
    test t;
    t(10, 20);
    t();
    return 0;
}