【十一】运算符重载(下)

1、回顾上一节
上一节中,我们通过了两个全局友元函数进行了运算符重载,并且简单说明了如何进行类成员函数的运算符重载,这里首先将全局重载函数改写为成员重载函数!

示例:

#include <iostream>

using namespace std;

class Complex
{
private:
    int a;
    int b;
public:
    Complex(int i = 0, int j = 0)
    {
        a = i;
        b = j;
    }
    //成员函数操作符重载
    Complex operator+ (const Complex& rb);
    friend ostream& operator<< (ostream& out,const Complex& rc);
};

//“+”号运算符为双目运算符,所以重载参数有两个,且只能有两个,但是如果该重载函数为类的
//成员函数,那么就只能有一个显示的参数,因为会有一个隐藏的this指针参数
Complex Complex::operator+ (const Complex& rb)
{
    Complex ret;
    ret.a = this->a + rb.a;
    ret.b = this->b + rb.b;

    return ret;
}

//这里返回类型为ostream类对象的引用,是为了函数调用完成后,还能继续使用cout对象
//比如:cout << c3 << endl;  ==> (cout << c3) << endl;
//如果返回值不为ostream&,那么该调用会失败!
ostream& operator<< (ostream& out, const Complex& rc)
{
    out << rc.a << " + " << rc.b << "i";

    return out;
}

int main()
{
    Complex c1(5, 2);
    Complex c2(4, 9);
    Complex c3 = c1 + c2;   //等价于:c1.operator+(c2);

    cout << c3 << endl;     //等价于:operator<<(cout,c3);

    cout << "Press any key to continue..." << endl;
    cin.get();
    return 0;
}

思考:

  什么时候使用全局函数重载操作符?什么时候使用成员函数重载操作符?

  • 当无法修改左操作数的类的实现时,使用全局函数进行重载,用这种方法也能对原有的类进行功能扩展,即使我们没有源代码
  • C++规定,=, [], ()和->操作符只能通过成员函数进行重载

 
 
2、类的默认操作符重载

  • C++编译器会为每个类提供默认的赋值操作符,既是拷贝构造函数
  • 默认的赋值操作符只是做简单的值复制
  • 类中存在指针成员变量时就需要重载赋值操作符,因为一旦只进行简单的值复制,那么两个对象的的成员变量就同时指向了同一内存空间,这就会引发问题,比如,b对象是a对象的拷贝,如果a对象被析构,那么它申请的内存空间会被释放,而b对象此时正“使用”着该内存空间!

 
 
3、“++”和“–”运算符的重载

  • 这两个操作符只有一个操作数
  • 这两个操作符有前缀和有后缀的区分

思考:

那么,如何重载这两个操作符才能区分前置运算和后置运算??

答案:

  可以通过占位参数来实现,因为操作符的重载本质上还是函数的重载,所以可以用参数的不同来区分两者,这里实现“++”运算符的重载来举例说明!

示例:

#include <iostream>

using namespace std;

class Complex
{
private:
    int a;
    int b;
public:
    Complex(int i = 0, int j = 0)
    {
        a = i;
        b = j;
    }
    //成员函数操作符重载
    Complex operator+ (const Complex& rb);
    friend ostream& operator<< (ostream& out,const Complex& rc);

    Complex operator++ (int);  //obj++
    Complex& operator++ ();   //++obj
};

//“+”号运算符为双目运算符,所以重载参数有两个,且只能有两个,但是如果该重载函数为类的
//成员函数,那么就只能有一个显示的参数,因为会有一个隐藏的this指针参数
Complex Complex::operator+ (const Complex& rb)
{
    Complex ret;
    ret.a = this->a + rb.a;
    ret.b = this->b + rb.b;

    return ret;
}

//这里返回类型为ostream类对象的引用,是为了函数调用完成后,还能继续使用cout对象
//比如:cout << c3 << endl;  ==> (cout << c3) << endl;
//如果返回值不为ostream&,那么该调用会失败!
ostream& operator<< (ostream& out, const Complex& rc)
{
    out << rc.a << " + " << rc.b << "i";

    return out;
}

//为了与内置版本保持一致,后置运算符应该返回对象的原值,返回一个值而非引用
//为了同时重载前置和后置运算符,后置版本接受一个额外的(不被使用)int类型的形参,当我们使用后置运算符时,编译器为这个形参提供一个值为0的实参
Complex Complex::operator++ (int) //obj++
{
    cout << "obj++" << endl;
    Complex temp = *this;

    this->a++;
    this->b++;

    return temp;
}


//这里返回值使用引用是为了和内置版本保持一致
Complex& Complex::operator++ () //++obj
{
    cout << "++obj" << endl;
    this->a++;
    this->b++;

    return *this;
}

int main()
{
    Complex c1(5, 2);
    Complex c2(4, 9);

    Complex temp = c2++; //等价于: temp = c2; c2.operator++(int);
    temp = ++c2; //等价于: c2.operator++(); temp = c2;
    (++c2)++;


    Complex c3 = c1 + c2;   //等价于:c1.operator+(c2);

    cout << c3 << endl;     //等价于:operator<<(cout,c3);

    cout << "Press any key to continue..." << endl;
    cin.get();
    return 0;
}

 
 
4、不应该被重载的运算符

最好不要去重载”&&”、”||” 和 “,” 运算符,原因如下:

  • &&和||内置实现了短路规则
  • “,”号运算符的重载版本无法保证它原有的求值顺序
  • 操作符重载是靠函数重载来完成的
  • 操作数作为函数参数传递
  • C++的函数参数都会被求值,无法实现短路规则

 
 
5、不能被重载的运算符

  • ‘::’ – 作用域运算符
  • ‘.*’ – 成员指针运算符
  • ‘.’ – 成员运算符
  • ‘? :’ – 条件运算符
  • ‘sizeof’ – sizeof运算符

TIPS:
  ”.*/->*” – 成员指针运算符的使用举例

#include <iostream>
using namespace std;


class CTEST
{

public:
    double data;

public:

    CTEST(double x)
    {
        data = x;
    }

    double fx(double x)
    {
        return data*data-x;
    }
};

int main()
{
    CTEST obj(3.14);        //定义一个类对象

    CTEST *p = &obj;        //定义一个对象指针,并指向obj对象

    double CTEST::*ip;      //定义一个类成员变量指针,注意和 double *ip; 区分

    ip = &CTEST::data;      //让ip指针指向一个类成员变量,注意和 ip = &obj.data; 区分

    cout << "obj.*ip = " << obj.*ip << endl;        //通过对象名使用成员变量指针访问
    cout << "obj.data = " << obj.data << endl;      //普通的成员变量访问

    cout << "p->*ip = " << p->*ip << endl;          //通过对象指针使用成员变量指针访问
    cout << "p->data = " << p->data << endl;        //普通的成员变量访问

    double (CTEST::*fp)(double);        //定义一个类成员函数指针,注意和 double (*fp)(double); 区分

    fp = &CTEST::fx;                     //让fp指向类成员函数,这里得显示取地址,注意和 fp = &obj.fx; 区分

    cout << "(obj.*fp)(0.5) = " << (obj.*fp)(0.5) << endl;
    cout << "obj.fx(0.5) = " << obj.fx(0.5) << endl;

    cout << "(p->*fp)(5.5) = "<< (p->*fp)(5.5) << endl;
    cout << "(p->fx)(5.5) = " << (p->fx)(5.5) << endl;

    return 0;
}

 
 
6、小结

  • 操作符重载可以直接使用类的成员函数实现
  • =, [], ()和->操作符只能通过成员函数进行重载
  • ++操作符通过一个int参数进行前置与后置的重载
  • C++中不要重载&&、|| 和 , 操作符
  • C++中不允许重载 ::、.*、. 、? :、sizeof运算符
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C++中,我们可以通过运算符重载来定义自定义的加法和减法运算符。运算符重载是指在类中定义一个函数,使得该函数可以在使用特定运算符时被调用。 以下是加法运算符重载的示例: ```cpp class Complex{ private: double real; double imag; public: Complex(double r = 0, double i = 0){ real = r; imag = i; } Complex operator+(const Complex& c){ Complex res(real + c.real, imag + c.imag); return res; } }; ``` 在上面的示例中,我们定义了一个名为Complex的类,该类具有两个属性:real和imag,表示复数的实部和虚部。我们还定义了一个构造函数和一个加法运算符重载函数。加法运算符重载函数使用operator+作为函数名,并使用const Complex&作为参数。在函数体中,我们创建了一个新的Complex对象,将其实部和虚部初始化为当前对象和传入对象的实部和虚部的和,然后将该对象返回。 下面是减法运算符重载的示例: ```cpp class Complex{ private: double real; double imag; public: Complex(double r = 0, double i = 0){ real = r; imag = i; } Complex operator-(const Complex& c){ Complex res(real - c.real, imag - c.imag); return res; } }; ``` 在上面的示例中,我们定义了一个名为Complex的类,该类具有两个属性:real和imag,表示复数的实部和虚部。我们还定义了一个构造函数和一个减法运算符重载函数。减法运算符重载函数使用operator-作为函数名,并使用const Complex&作为参数。在函数体中,我们创建了一个新的Complex对象,将其实部和虚部初始化为当前对象和传入对象的实部和虚部的差,然后将该对象返回。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值