【c++】重载操作符

目录

  1. 输入和输出操作符
  2. 算术操作符和关系操作符
  3. 下标操作符
  4. 自加、自减操作符
  5. 成员访问操作符

1  输入和输出操作符

1.1 输出操作符

1.1.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(const string &s = "", int v = 0) : ss(s), val(v) {} //构造函数带默认参数
    private:
        int val;
        string ss;
};

ostream& operator<<(ostream& out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
    return out;
}

int main()
{
    A a("hello", 23);
    cout << a << endl;
    A b;
    cout << b << endl;
}

结果

1.1.2 说明

1)IO操作必须为非成员函数

原因:I/O操作的接口返回的是ostream&对象(只有返回左值,这样才可以连续的输出,例如cout << a << b)。自定义的输出操作符应该与其相似。如果将其定义为成员函数(有个首默认参数this,即指向自己的指针),左操作数只能是该类型的对象,则没法办到。例如:Sales_item; item << cout; 与常规定义相反,因此只能为非成员函数。

2)因为要访问指定类的私有成员,所以在该类中声明输出操作符为友员函数。

3)第一个形参必须为引用。因为I/O对象不可以复制。同理返回值必须为一个引用。

4)第一个形参不可以为const,因为写入到流会改变其值。

5)第二个为引用,这样可以避免复制。参数可以为const,可以接收const对象和非const对象;否则,如果为非const,则只能接收非coust对象。一般为const,毕竟只是输出而已,不改变对象。

 

1.2 输入操作符

1.2.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    friend istream& operator>>(istream& in, A& a);
    public:
        A(const string &s = "", int v = 0) : ss(s), val(v) {}
    private:
        int val;
        string ss;
};

ostream& operator<<(ostream& out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
    return out;
}
istream& operator>>(istream& in, A& a)
{
    in >> a.ss >> a.val;
    if(in)
    {
        cout << "Input right" << endl;
    }
    else
    {
        cout << "in.fail:" << in.fail() << endl;
        cout << "input wrong!" << endl;
    }
    return in; 
}

int main()
{
    A a("hello", 23);
    cout << a << endl;
    A b;
    cin >> b;
    cout << b << endl;
}

结果

1.2.2 说明

1)输入与输出操作符的重要区别:输入操作符必须处理错误和文件结束的可能性。

2)输入如果有多个值的话,如果一个数错了,整个输入对象就错了(False),从示例中可以看出,前边赋值正确的已经生效了,后边的用了默认值,可以这样设计:如果输入错误,将整个对象复位,恢复到最初的状态,例:

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    friend istream& operator>>(istream& in, A& a);
    public:
        A(const string &s = "", int v = 0) : ss(s), val(v) {}
        A(const A& a)
        {
            ss = a.ss;
            val = a.val;
        } 

        A& operator=(const A& a) 
        {
            if(this != &a)
            {
                ss = a.ss;
                val = a.val;
                return *this;
            }
        }
    private:
        int val;
        string ss;
};

ostream& operator<<(ostream& out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
    return out;
}
istream& operator>>(istream& in, A& a)
{
    in >> a.ss >> a.val;
    if(in)
    {
        cout << "Input right" << endl;
    }
    else
    {
        cout << "in.fail:" << in.fail() << endl;
        cout << "input wrong!" << endl;
        a = A();
    }
    return in; 
}

int main()
{
    A a("hello", 23);
    cout << a << endl;
    A b;
    b = a;
    cin >> b;
    cout << b << endl;
}
View Code

 

2 算术操作符和关系操作符

2.1 相等操作符

2.1.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend bool operator==(const A& a, const A& b);
    friend bool operator!=(const A& a, const A& b);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
    private:
        string ss;
        int val;
};

bool operator==(const A& a, const A& b)
{
    return a.ss == b.ss && a.val == b.val;
}

bool operator!=(const A& a, const A& b)
{
    return !(a == b);
}

int main()
{
    A a("hello", 53);
    A b("hello", 54);
    A c("hello", 54);
    cout << "a == b?:" << (a == b) << endl;
    cout << "a != b?:" << (a != b) << endl;
    cout << "b == c?:" << (b == c) << endl;
    cout << "b != c?:" << (b != c) << endl;
}

结果

2.1.2说明

1)定义了类的==,对应的应该定义!=

 

2.2 关系操作符

2.2.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend bool operator<(const A& a, const A& b);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
    private:
        string ss;
        int val;
};

bool operator<(const A& a, const A& b)
{
    return (a.val < b.val);
}

int main()
{
    A a("hello", 53);
    A b("he", 55);
    cout << "a < b?:" << (a < b) << endl;
}

结果

2.2.2 说明

1)定义了相等操作符,一般也定义关系操作符

2)关系操作符要根据具体的含义定义

 

2.3 赋值操作符

2.3.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        A& operator=(const A& a);
    private:
        string ss;
        int val;
};

ostream& operator<<(ostream &out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
}

A& A::operator=(const A& a)
{
    if(this != &a)
    {
        ss = a.ss;
        val = a.val;
    }
    return *this;
}


int main()
{
    A a("hello", 53);
    A b("he", 55);
    cout << b << endl;
    b = a;
    cout << b << endl;
}

2.3.2 说明

1) 复制操作符完成对同类对象的赋值,参数一般为对类类型的const引用。

2)如果没有,编译器会自动合成一个,类的赋值操作符一定为类的成员变量,以便编译器是否需要自己合成一个。

3)返回值必须为*this的引用,这样就不需要创建和撤销结果的临时副本。同理的有复合赋值操作符,例如

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        A& operator+=(const A &);
    private:
        string ss;
        int val;
};

ostream& operator<<(ostream &out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
}

A& A::operator+=(const A& a)
{
    val += a.val;
    return *this;
}

int main()
{
    A a("hello", 53);
    A b("he", 55);
    a += b;
    cout << a << endl;
}
View Code

结果

 

2.4 加法操作符

2.4.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    friend A operator+(const A &a ,const A &b);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        A(const A&);
        A& operator+=(const A &);
    private:
        string ss;
        int val;
};

A::A(const A& a) 
{
    ss = a.ss;
    val = a.val;
}

ostream& operator<<(ostream &out, const A& a)
{
    out << "a.ss:" << a.ss << " " << "a.val:" << a.val;
}

A operator+(const A &a ,const A &b)
{
    A tmp(a);
    tmp += b;
    return tmp;
}

A& A::operator+=(const A& a)
{
    val += a.val;
    return *this;
}

int main()
{
    A a("hello", 53);
    A b("he", 55);
    a += b;
    cout << a + b << endl;
}

2.4.2 说明

1) 根据复合操作符(如+=)实现算术操作符(如+),比其他方式更有效

 

3 下标操作符

3.1.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        char& operator[](const size_t);
        const& char operator[](const size_t) const;
    private:
        string ss;
        int val;
};

ostream& operator<<(ostream& out, const A& a)
{
    out << "a.val:" << a.val << "  " << "a.ss:" << a.ss;
    return out;
}

char& A::operator[](const size_t index)
{
    return ss[index];
}

const char& A::operator[](const size_t index) const
{
    return ss[index];
}


int main()
{
    A a("hello", 53);
    cout << a[2] << endl;
}

结果

e

3.1.2 说明

1) 下标操作必须为函数成员,因为传递一个参数,还需要另一个指向自己的指针参数,正好函数成员的this可以胜任。

2) 类定义下标时,一般定义两个版本:一个为非const成员,并返回非const引用; 另一个为const成员,并返回const引用。这样应用与const对象时,返回值应为const引用,不能用作赋值的目标。

 

4 自加、自减操作符

4.1 前置自加、自减操作符

4.1.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        A& operator++();
        A& operator--();
    private:
        string ss;
        int val;
};

ostream& operator<<(ostream& out, const A& a)
{
    out << "a.val:" << a.val << "  " << "a.ss:" << a.ss;
    return out;
}

A& A::operator++()
{
    ++val;
    return *this;
}

A& A::operator--()
{
    --val;
    return *this;
}

int main()
{
    A a("hello", 53);
    cout << a << endl;
    ++a;
    cout << a << endl;
    ++a;
    cout << a << endl;
    --a;
    cout << a << endl;
}

结果

 

4.2 后置自加、自减操作符

4.2.1 示例

#include <iostream>
#include <string>
using namespace std;

class A
{
    friend ostream& operator<<(ostream& out, const A& a);
    public:
        A(string s = "", int v = 0) : ss(s), val(v) {}
        A& operator++();
        A& operator--();
        A operator++(int);
        A operator--(int);
    private:
        string ss;
        int val;
};

ostream& operator<<(ostream& out, const A& a)
{
    out << "a.val:" << a.val << "  " << "a.ss:" << a.ss;
    return out;
}

A& A::operator++()
{
    ++val;
    return *this;
}

A& A::operator--()
{
    --val;
    return *this;
}
A A::operator++(int)
{
    A tmp(*this);
    ++(*this);
    return tmp;
}

A A::operator--(int)
{
    A tmp(*this);
    --(*this);
    return tmp;
}

int main()
{
    A a("hello", 53);
    cout << a << endl;
    ++a;
    cout << a << endl;
    ++a;
    cout << a << endl;
    cout << "hello" << endl;
    cout << (a--) << endl;;
    cout << a << endl;
}

4.2.2 说明

1)为了区分与前置自加、自减操作符的区别,后置需要接受一个而外的(无用的)的int型形参。使用后缀式操作符时,编译器提供0作为这个形参的实参,其唯一目的是为了区别前缀、后缀。

2)a++返回的是加之前的状态,因此,定义一个局部对象,保存(*this),最后返回这个局部变量的备份(注意不可以为引用,毕竟是局部的)。

 

5. 成员访问操作符

5.1.1 示例

#include <iostream>
#include <string>
using namespace std;
class B
{
    public:
        void print_B() { cout << "hello !!" << endl; }
};
class U_Ptr 
{
    friend class HasPtr;
    B* ip;
    size_t use;
    U_Ptr(B *p) : ip(p), use(1) {}
    ~U_Ptr() { delete ip; }
};

class HasPtr
{
    public:
        HasPtr(B *p, int i) : ptr(new U_Ptr(p)), val(i) {}
        HasPtr(const HasPtr &orig) : ptr(orig.ptr), val(orig.val) { ++ptr->use; }
        HasPtr& operator=(const HasPtr &orig);
        ~HasPtr() { if(--ptr->use == 0) delete ptr; }
        B& operator*() { return *ptr->ip; }
        B* operator->() { return ptr->ip; }
    private:
        U_Ptr *ptr;
        int val;
};

HasPtr& HasPtr::operator=(const HasPtr &orig)
{
    if(this != &orig)
    {
        ptr = orig.ptr;
        val = orig.val;
        ++(ptr->use);
    }
    return *this;
}

int main()
{
    HasPtr hasptr1(new B, 23);
    HasPtr hasptr2(hasptr1);
    *hasptr1;
    hasptr1->print_B();
}

结果

hello!!

5.1.2 说明

1) 箭头必须定义为成员函数, 解引用不要求定义为成员,但是可以作为成员。

2) 解引用和箭头操作常用在实现智能指针的类中。

 

 

转载于:https://www.cnblogs.com/kaituorensheng/p/3505115.html

<think>好的,用户想了解C++中如何实现操作符重载,特别是实现方法和示例。首先,我需要回忆操作符重载的基本概念和规则。操作符重载允许用户自定义类型像内置类型一样使用运算符,比如+、==等。根据提供的引用内容,用户已经提到了一些关键点,比如使用operator关键字,重载关系运算符的例子,以及字符串类中的等号和下标操作符重载。 接下来,我需要整理实现方法。根据引用[2],重载运算符需要使用operator@的函数,其中@代表运算符。操作符重载可以作为类的成员函数或全局函数。成员函数的话,左操作数是当前对象,而全局函数则需要所有操作数作为参数。例如,引用[3]中的Student类重载了>运算符作为成员函数,比较分数。 然后,考虑示例部分。用户可能需要不同类型的操作符重载示例,比如算术运算符、关系运算符、赋值运算符和下标运算符。例如,引用[4]和[5]提到了字符串类中的=和[]重载,可以引用这些例子。此外,需要注意重载的限制,比如不能创建新运算符,不能改变运算符的优先级和结合性,这些需要提到以避免用户误解。 还需要注意语法正确性,比如参数传递方式,返回类型。例如,赋值运算符通常返回引用以便链式调用,而比较运算符返回bool。同时,友元函数的使用场景,比如当左操作数不是类的实例时,需要全局函数重载,如<<运算符常用于输出,需要作为友元重载。 最后,生成相关问题需要考虑用户可能进一步的问题,比如重载的限制、常用运算符的应用场景、深浅拷贝的问题等。确保问题覆盖用户可能感兴趣的扩展知识点,帮助他们深入理解。 总结步骤:先解释基本概念,再分点讲解实现方法,每种方法配以示例代码,最后注意事项和常见问题。确保引用正确的参考资料,并在适当的位置添加引用标记,如引用[1]、[2]等。同时,代码部分需要用正确的格式,行内公式用$...$,独立公式用$$...$$,但根据用户问题,可能代码示例较多,公式较少,需注意调整。</think>### C++ 操作符重载实现方法详解 #### 一、操作符重载基础 操作符重载允许为**自定义类型**(如类或结构体)定义运算符的行为,使其支持与内置类型相似的运算逻辑。通过定义名为 `operator@` 的函数实现(`@` 表示运算符,如 `+`、`>` 等)[^2]。 #### 二、实现方法分类 1. **成员函数重载** - 运算符左操作数为当前对象,右操作数为参数。 - 示例:重载 `>` 运算符比较学生成绩 ```cpp class Student { public: bool operator>(const Student& other) { return this->score > other.score; // 比较分数[^3] } }; ``` 2. **全局函数重载** - 需声明为 `friend` 以访问私有成员,适用于左操作数非当前类对象的情况。 - 示例:重载 `<<` 运算符输出对象 ```cpp friend ostream& operator<<(ostream& os, const Student& s) { os << s.name << ":" << s.score; return os; } ``` #### 三、常见运算符重载示例 1. **算术运算符:`+`** ```cpp Vector operator+(const Vector& v) { return Vector(x + v.x, y + v.y); // 向量相加 } ``` 2. **关系运算符:`==`** ```cpp bool operator==(const String& s) { return strcmp(data, s.data) == 0; // 字符串内容比较[^4] } ``` 3. **赋值运算符:`=`** ```cpp String& operator=(const String& s) { if (this != &s) { delete[] data; data = new char[strlen(s.data) + 1]; strcpy(data, s.data); } return *this; // 支持链式赋值[^4] } ``` 4. **下标运算符:`[]`** ```cpp char& operator[](int index) { return data[index]; // 实现类似数组的访问[^5] } ``` #### 四、注意事项 1. **不可重载的运算符** - `::`(作用域解析)、`.*`(成员指针访问)、`?:`(三元条件)等。 2. **运算符优先级不变** - 重载后运算符的优先级和结合性与原有定义一致。 3. **深浅拷贝问题** - 涉及资源管理的运算符(如 `=`)需正确处理深拷贝,避免内存泄漏。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值