C++ 运算符重载

目录

1. 运算符重载

1.1 概念

1.2 友元函数运算符重载

1.3 成员函数运算符重载

1.4 赋值运算符重载

1.5 类型转换运算符重载

1.6 注意事项


1. 运算符重载

1.1 概念

C++中可以把部分运算符看做成函数,此时运算符也可以重载。

运算符预定义的操作只能针对基本数据类型,但是对于自定义类型,也需要类似的运算操作,此时就可以重新定义这些运算符的功能,使其支持特定类型,完成特定的操作。

如果不做特殊处理,C++ 的 +、-、*、/ 等运算符只能用于对基本类型的常量或变量进行运算,不能用于对象之间的运算。类的对象中有很多个成员变量,运算符不知道对哪个成员变量进行运算,这时候就需要对运算符进行重载,让运算符明确知道要对哪个成员变量进行运算。

其实相当于定义一个函数来进行特定的运算。

运算符重载有两种实现方式:

        ● 友元函数运算符重载

        ● 成员函数运算符重载

1.2 友元函数运算符重载

(1)在类内声明实现运算符重载功能的友元函数名称

(2)在类外定义函数体定义函数实现运算符重载功能

 友元函数实现运算符重载实例:

注意:当自增运算符进行重载时,前置自增 ++i 与后置自增i++的函数名字一样,但是参数不一样,通过函数重载进行区分。

如果是 前置自增 ++i , 参数只有一个进行自增的变量。

如果是后置自增 i++,参数除了进行自增的变量,还需要加一个哑元参数。

// 友元函数 ++运算符重载声明
    // 利用参数不同,进行函数重载
    friend Myint operator ++(Myint &i);   // 前置++
    friend Myint operator ++(Myint &i,int);   // 后置++

#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 &a,Myint &b);
    // 友元函数 -运算符重载声明
    friend Myint operator -(Myint &a,Myint &b);

    // 友元函数 ++运算符重载声明
    // 利用参数不同,进行函数重载
    friend Myint operator ++(Myint &i);   // 前置++
    friend Myint operator ++(Myint &i,int);   // 后置++
};

//加法重载
Myint operator +(Myint &i,Myint &j)
{
    //    Myint int4(0);
    //    int4.a = i.a + j.a;
    //    return int4;

    return i.a + j.a;
}

//减法重载
Myint operator -(Myint &i,Myint &j)
{
    Myint int4(0);
    int4.a = i.a - j.a;
    return int4;
}

// 前置++
Myint operator ++(Myint &i)
{
    //    Myint int4(0);
    //    ++int4.a
    //    return int4;

    return ++i.a;
}

// 后置++
Myint operator ++(Myint &i,int)
{
//        Myint int4(0);
//        int4.a = i.a++;
//        return int4;

            return i.a++;
}

int main()
{
    Myint int1(2);
    Myint int2(int1);  // 拷贝构造函数
    cout << int2.get_int() << endl;
    cout << endl;

    cout << "加法重载:" << endl;
    Myint int3 = int1 + int2;
    cout << int3.get_int() << endl;
    cout << endl;

    cout << "减法重载:" << endl;
    Myint int5 = int1 - int2;
    cout << int5.get_int() << endl;
    cout << endl;

    cout << "后置自增:" << endl;
    cout << (int3++).get_int() << endl; // 后置自增
    cout << int3.get_int() << endl;
    cout << endl;
    Myint int6 = int3++;
    cout << int6.get_int() << endl;
    cout << endl;

    cout << "前置自增:" << endl;
    cout << (++int3).get_int() << endl; // 前置自增
    cout << int3.get_int() << endl;
    cout << endl;
    Myint int7 = ++int3;
    cout << int7.get_int() << endl;
    
    return 0;
}

1.3 成员函数运算符重载

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

 成员函数进行运算符重载实例:

因为进行自增的变量已经进行由this指针代替,所以前置自增为无参函数,后置自增只需要写哑元参数即可。

// 成员函数 ++运算符重载声明
    Myint operator ++();   // 前置++
    Myint operator ++(int);   // 后置++

#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);
    // 成员函数 -运算符重载声明
    Myint operator -(Myint &i);

    // 成员函数 ++运算符重载声明
    Myint operator ++();   // 前置++
    Myint operator ++(int);   // 后置++
};

//加法重载
Myint Myint::operator +(Myint &i)
{
    return this->a + i.a;
}

//减法重载
Myint Myint::operator -(Myint &i)
{
    return this->a - i.a;
}

// 前置++
Myint Myint::operator ++()
{


    return ++this->a;
}

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

int main()
{
    Myint int1(2);
    Myint int2(int1);  // 拷贝构造函数
    cout << int2.get_int() << endl;
    cout << endl;

    cout << "加法重载:" << endl;
    Myint int3 = int1 + int2;
    cout << int3.get_int() << endl;
    cout << endl;

    cout << "减法重载:" << endl;
    Myint int5 = int1 - int2;
    cout << int5.get_int() << endl;
    cout << endl;

    cout << "后置自增:" << endl;
    cout << (int3++).get_int() << endl; // 后置自增
    cout << int3.get_int() << endl;
    cout << endl;
    Myint int6 = int3++;
    cout << int6.get_int() << endl;
    cout << endl;


    cout << "前置自增:" << endl;
    cout << (++int3).get_int() << endl; // 前置自增
    cout << int3.get_int() << endl;
    cout << endl;
    Myint int7 = ++int3;
    cout << int7.get_int() << endl;

    return 0;
}

1.4 赋值运算符重载

除了之前学习的无参构造函数、拷贝构造函数和析构函数以外,如果程序员不手写,编译还会给一个类添加赋值运算符重载函数。

赋值运算符=要求左右两个操作数的类型是匹配的,或至少是兼容的。有时希望=两边的操作数的类型即使不兼容也能够成立,这就需要对=进行重载。

C++规定,=赋值运算符重载只能使用成员函数运算符重载。

 赋值运算符重载实例:

int2 = int1; 当进行这句赋值操作时,就需要利用赋值运算符重载。

#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()
{
    cout << "Hello World!" << endl;
    MyInt int1(2);
    MyInt int2(4);

    cout << int1.get_int() << endl;
    cout << int2.get_int() << endl;
    cout << endl;

    int2 = int1;
    cout << int1.get_int() << endl;
    cout << int2.get_int() << endl;

    return 0;
}

1.5 类型转换运算符重载

C++ 中,类型的名字(包括类的名字)本身也是一种运算符,即类型强制转换运算符。

类型强制转换运算符是单目运算符,也可以被重载,但只能重载为成员函数,不能重载为全局函数。

经过适当重载后,(类型名)对象这个对对象进行强制类型转换的表达式就等价于对象.operator 类型名(),即变成对运算符函数的调用。

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

类型转换运算符重载实例:

int a= int1;  运行这一句的时候,把对象中的int类型的成员函数给 变量 int a

string b = int1; 运行这一句的时候,把对象中的srtring类型的成员变量 给 strng b

#include <iostream>

using namespace std;

class MyInt
{
private:
    int a;
    string str = "hello";

public:
    MyInt(int a,string b):a(a),str(b){}

    int get_int()
    {
        return a;
    }

    operator int()
    {
        return a;
    }

    operator string()
    {
        return str;
    }

};

int main()
{
    cout << "Hello World!" << endl;
    MyInt int1(2,"world");
    int a= int1;
    cout << "a=" << a << endl;
    cout << endl;

    string b = int1;
    cout << "b=" << b << endl;
    cout << endl;

    return 0;
}

1.6 注意事项

● 重载的运算符限制在C++语言中已有的运算符范围,不能创建新的运算符。

● 运算符重载本质上也是函数重载,但是不支持函数参数默认值。

● 重载之后的运算符不能改变运算符的优先级和结合性,也不能改变运算符的操作数和语法结构。

● 运算符重载必须基于或者包含自定义类型,即不能改变基本数据类型的运算规则。

● 重载的功能应该与原有的功能相似,避免没有目的的滥用运算符重载。

● 一般情况下,双目运算符建议使用友元函数运算符重载,单目运算符建议使用成员函数运算符重载。

<think>好的,我现在要帮用户介绍C++运算符重载。首先,我需要回忆一下运算符重载的基本概念。运算符重载允许用户自定义类型使用C++内置的运算符,比如+、-、*等,使得代码更直观和易读。例如,可以让两个对象直接相加,而不必调用特定的函数。 接下来,我应该考虑用户可能的背景。用户可能是刚开始学习C++,或者已经有一定基础但想深入了解运算符重载。因此,解释需要清晰,从基础开始,逐步深入。可能需要先说明什么是运算符重载,为什么需要它,然后讲解如何实现,包括语法和注意事项。 然后,运算符重载的语法是关键部分。需要详细说明如何定义运算符重载函数,包括成员函数和非成员函数(友元函数)的区别。例如,重载+运算符时,成员函数通常只需要一个参数,因为左操作数是对象本身,而非成员函数需要两个参数。同时,要提到一些运算符必须作为成员函数重载,比如赋值运算符=。 例子是帮助理解的重要部分。我应该举一个简单的例子,比如为自定义的Vector类重载+运算符,这样用户可以看到具体的实现方式。同时,需要区分成员函数和非成员函数的例子,说明它们的不同应用场景。 注意事项和常见问题也不能遗漏。比如不能重载运算符(如.、::、sizeof等),以及重载时保持运算符的原有语义,避免滥用导致代码难以理解。此外,还需要提到运算符的返回类型和参数类型的选择,比如是否返回引用或值,参数的const修饰等。 用户可能还会有疑问,比如运算符重载的使用场景,或者何时应该使用成员函数而非友元函数。因此,在解释过程中需要涵盖这些方面,可能的话,给出一些最佳实践的建议。 最后,总结运算符重载的优点和需要注意的地方,帮助用户全面理解。确保语言通俗易懂,避免过于专业的术语,必要时进行类比,让用户更容易接受。</think>### C++运算符重载详解 #### 1. 什么是运算符重载运算符重载(Operator Overloading)是C++中的一种特性,允许开发者**为自定义类型(如类或结构体)重新定义运算符的行为**。通过重载运算符,可以让对象像内置类型(如`int`、`double`)一样使用`+`、`-`、`*`、`==`等运算符,提升代码可读性和简洁性。 --- #### 2. 如何实现运算符重载运算符重载通过**成员函数**或**全局函数**实现,语法形式为: $$ \text{返回类型 operator 运算符(参数列表)} $$ ##### 示例1:成员函数重载`+` ```cpp class Vector { public: int x, y; // 成员函数重载 + Vector operator+(const Vector& other) { return {x + other.x, y + other.y}; } }; // 使用 Vector v1{1, 2}, v2{3, 4}; Vector v3 = v1 + v2; // 等价于 v1.operator+(v2) ``` ##### 示例2:全局函数重载`<<`(输出流) ```cpp class Student { public: string name; int age; }; // 全局函数重载 << ostream& operator<<(ostream& os, const Student& s) { os << "Name: " << s.name << ", Age: " << s.age; return os; } // 使用 Student s{"Alice", 20}; cout << s; // 输出: Name: Alice, Age: 20 ``` --- #### 3. 常见运算符重载规则 | 运算符类型 | 可重载性 | 示例 | |------------------|----------------|----------------------| | 算术运算符 | `+`, `-`, `*` | `a + b` | | 关系运算符 | `==`, `>`, `<` | `a == b` | | 赋值运算符 | `=`, `+=` | `a = b` | | 下标运算符 | `[]` | `a[0]` | | 函数调用运算符 | `()` | `a(1, 2)` | | **不可重载运算符** | `.`、`::`、`?:`、`sizeof` | 无法重载 | --- #### 4. 关键注意事项 1. **参数限制**: - 至少一个操作数是用户自定义类型(不能全为内置类型)。 - 不能修改运算符的优先级或结合性。 2. **成员函数 vs 全局函数**: - 赋值运算符(`=`)、下标运算符(`[]`)、函数调用运算符(`()`)**必须**作为成员函数重载。 - 输入输出运算符(`>>`、`<<`)通常作为全局函数。 3. **保持语义一致性**: - 例如重载`+`时,不应修改操作数本身,而应返回新对象。 --- #### 5. 完整示例:复数类重载 ```cpp class Complex { private: double real, imag; public: Complex(double r = 0, double i = 0) : real(r), imag(i) {} // 成员函数重载 + Complex operator+(const Complex& other) { return Complex(real + other.real, imag + other.imag); } // 全局友元函数重载 << friend ostream& operator<<(ostream& os, const Complex& c); }; ostream& operator<<(ostream& os, const Complex& c) { os << c.real << " + " << c.imag << "i"; return os; } // 使用 Complex c1(2, 3), c2(4, 5); Complex c3 = c1 + c2; cout << c3; // 输出: 6 + 8i ``` --- #### 6. 应用场景 - 数学计算(向量、矩阵、复数) - 字符串操作(`str1 + str2`) - 容器类(自定义数组、链表) --- #### 7. 总结 **优点**:提升代码直观性,使自定义类型操作更自然。 **注意**:避免过度使用或违反直觉的重载(例如用`+`实现减法)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值