C++运算符重载

简介: C++运算符重载

文章目录


1、双目运算符(重载时需要两个参数)

+ - * /

  • 以+为例
  • 以全局函数的形式进行重载
  • 以成员函数(隐含第一个参数为this, 且不可更改 )的形式进行重载

/// 全局函数重载
#include<iostream>
using namespace std;
// 类声明 --> 避免第14行友元函数声明的有效性
class Obj1;
class Obj2;
class Obj1 {
private:
  int num;
public:
  Obj1(int i = 0) :num(i) {};
  friend int operator+(const Obj1& o1, const Obj2& o2);//14行,如果没有Obj2类声明,这里将会出错
};
class Obj2 {
private:
  int num;
public:
  Obj2(int j = 0) :num(j) {};
  friend int operator+(const Obj1& o1, const Obj2& o2);
};
int operator+(const Obj1& o1, const Obj2& o2) {
  int temp = o2.num + o1.num;
  // 下面的this报错--->说明全局函数的重载并不会传入this
  // cout << "重载运算符内部的this指向--->\r\n" << this << "===========\r\n";
  return temp;
}
int main()
{
  Obj1 oo1(12);
  Obj2 oo2(13);
  cout << oo1 + oo2 << endl;
  return 0;
}

ps: this指针

进行成员函数的形式进行重载之前,我们先来理解一下成员函数里面隐含自带的this指针`

this作用域是在类内部,当在类的非静态成员函数中访问类的非静态成员的时候,编译器会自动将对象本身的地址作为一个隐含参数传递给函数。也就是说,即使你没有写上this指针,编译器在编译的时候也是加上this的,它作为非静态成员函数的隐含形参,对各成员的访问均通过this进行。

  • this指针指向当前对象;
#include <iostream>
using namespace std;
class Date
{
private:
    int _year;
    int _month;
    int _day;
public:
    Date(int year, int month, int day)//构造函数
    {
        _year = year;
        _month = month;
        _day = day;
    };
    void print() {
        cout << &this->_year << "-----"
            <<&this->_month<<"----" 
            << &this->_day << "----"
            << "----\r\n"
            << this << endl;
    }
};
int main()
{
    Date d(2017, 6, 30);
    d.print();
    return 0;
}
  • 输出结果:
//         cout << &this->_year << "-----"
            <<&this->_month<<"----" 
            << &this->_day << "----"
            << "----\r\n"
            << this << endl;
001CFE50-----001CFE54----001CFE58--------
001CFE50       
  • 可以看到this指针指向了year 的地址,这就涉及到了类的内部存储问题了
  • 在C++中,内存分成5个区,他们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
  • this 参考博客

  • 以成员函数的形式进行重载
#include<iostream>
using namespace std;
// 类声明 --> 避免第14行友元函数声明的有效性
class Obj1;
class Obj2;
class Obj1 {
private:
  int num;
public:
  Obj1(int i = 0) :num(i) {};
  friend Obj2& operator+(const Obj1& o1);
};
class Obj2 {
private:
  int num;
public:
  Obj2(int j = 0) :num(j) {};
  Obj2& operator+(const Obj1& o1);
  friend ostream& operator<<(ostream& out, Obj2& o2) {
    cout << o2.num;
    return out;
  }
};
Obj2& Obj2:: operator+(const Obj1& o1) {
  cout << &this->num << "==========" << this << "\r\n";
  cout << "重载运算符内部的this指向的值--->" << *this << "\r\n===========\r\n";
  this->num += 1;
  cout << "this->num=" << this->num << endl;
  return *this;
};
int main()
{
  Obj1 oo1(12);
  Obj2 oo2(14);
  cout << oo2 + oo1 << endl;
  return 0;
}
  • 运行结果

00F0F764==========00F0F764

重载运算符内部的this指向的值—>14

===========

this->num=15

15

  • ps:
  • 如果要实现两个类的加重载,可以使用友元函数进行重载(两个类的引用作为形参)

2、单目运算符

++、–

是否传入int区分是前增还是后增

#include<iostream>
using namespace std;
// 类声明 --> 避免第14行友元函数声明的有效性
class Obj2;
class Obj2 {
private:
  int num;
public:
  Obj2(int j = 0) :num(j) {};
  friend ostream& operator<<(ostream& out, Obj2& o2) {
    cout << o2.num <<endl;
    return out;
  }
  Obj2& operator++() {
    std::cout << "前增量\r\n";
    this->num++;
    return *this;//返回原对象
  };
  Obj2& operator++(int) {
    std::cout << "后增量\r\n" ;
    Obj2 temp(*this); //临时对象存放原有对象的值
    this->num++; //原有对象的值++
    return temp; //返回原有对象
  }
};
int main()
{
  Obj2 oo2(14);
  cout << oo2 << "====>" << &oo2 << endl;
  oo2++;
  cout << oo2 << "====>" << &oo2 << endl;
  ++oo2;
  cout << oo2 << "====>" << &oo2 << endl;
  return 0;
}
  • 运行结果

14

====>004FFB44

后增量

15

====>004FFB44

前增量

16

====>004FFB44


3、插入运算符<<重载

  • 参考以上代码
friend ostream& operator<<(ostream& out, Obj2& o2) {
    cout << o2.num <<endl;
    return out;
  }
  • ps:
  • 声明为友元类的原因:方便访问类的私有或保护成员属性
  • 当然也可以不声明为友元,但是非友元需要通过public方法,访问private、protected;

4、转换运算符()的重载

类似于我们平时的(int)5.02 -->将5.02强制转换成 **int**类型 , 当我们想要强行转换类的类型的时候,就会用到转换运算符的重载了。

  • 转换运算符的声明形式

operator 类型名 ();

  • 他没有返回类型,因为类型名就代表了他的返回类型,如果再写返回类型,则显得有点多余
#include<iostream>
using namespace std;
class RMB {
private:
  unsigned int yuan, jiao;
public:
  RMB( double val = 0) {
    yuan = (unsigned int)val ;
    jiao = (unsigned int)(val*100) % 100;
  }
  /// 转换运算符-->强制类型转换成double
  operator double() {
    return yuan + (double)(jiao / 100);
  }
  friend ostream& operator<<(ostream& out,RMB &r) {
    cout << "===========\r\n";
    cout << "元:"<<r.yuan <<"\r\n角:"<< r.jiao << endl;
    return out;
  }
};
int main()
{
  RMB r(5.21);
  cout << r;
  return 0;
}
  • 输出结果

===========

元:5

角:21

  • 这里有个小坑,当我们不声明为友元的时候(运行的时候注意看输出)
#include<iostream>
using namespace std;
class RMB {
private:
  unsigned int yuan, jiao;
public:
  RMB( double val = 0) {
    yuan = (unsigned int)val ;
    jiao = (unsigned int)(val*100) % 100;
  }
  /// 转换运算符-->强制类型转换成double
  operator double() {
    return yuan + (double)(jiao / 100);
  }
  ostream& operator<<(ostream& out) {
    cout << "===========\r\n";
    cout << "元:"<<this->yuan <<"\r\n角:"<< this->jiao << endl;
    return out;
  }
};
int main()
{
  RMB r(5.21);
  cout << r;
  return 0;
}
  • 输出结果为

5

  • 通过调试可以知道,当程序执行到cout<<r的时候,程序跳转到了
  • operator double() { return yuan + (double)(jiao / 100); }

这也是为什么输出5的原因。

  • 至于为什么呢?
  • –》主要涉及到了运算符优先级的问题
  • 强制类型转换的优先级大于插入运算符

5、赋值运算符的重载

类似于:

RMB r(5.1);
EN e;
e=r; // c++是不允许这样操作的

要使e=r成立,我们就可以人为地进行赋值运算符的重载

#include<iostream>
using namespace std;
class EN;
class RMB {
private:
  int yuan, jiao;
public:
  RMB(double val = 0.0) {
    yuan = (int)val;
    jiao = ((int)(val * 100))% 100;
  }
  double getMoney()  {
    return yuan + (double)jiao / 100;
  }
};
class EN {
private:
  double meiyuan;
public:
  EN(double val = 0) :meiyuan(val) {};
  EN& operator=(RMB& rmb) {
    this->meiyuan = rmb.getMoney();
    return *this;
  }
  void display() {
    cout << meiyuan << endl;
  }
};
int main() 
{
  RMB r(8.67);
  EN e;
  e.display();
  e = r;
  e.display();
}
  • 输出结果

0

8.67

  • 注意点

double getMoney() { return yuan + (double)jiao / 100; }

如果写成

double getMoney() { return yuan + (double)(jiao / 100); }

的话,则不会得到第二个8.67;

  • 原因是因为先对jiao进行类型转换在/100, 可以得到0.67;
  • (jiao/100)进行类型转换的话就可会得到0

THE END !

感谢您的耐心阅读


欢迎指正错误

相关文章
|
5月前
|
编译器 C++
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
47 1
|
6月前
|
程序员 编译器 C++
C++中的运算符重载(Operator Overloading)
C++中的运算符重载(Operator Overloading)
57 1
|
2月前
|
C++
C++(十五) 运算符重载
C++中的运算符重载允许对已有运算符的功能进行重新定义,从而扩展语言功能、简化代码并提升效率。重载遵循特定语法,如 `friend 类名 operator 运算符(参数)`。重载时需注意不可新增或改变运算符数量、语义、优先级、结合性和返回类型。常见示例包括双目运算符 `+=` 和单目运算符 `-` 及 `++`。输入输出流运算符 `&lt;&lt;` 和 `&gt;&gt;` 也可重载。部分运算符只能作为成员函数重载。
|
5月前
|
存储 编译器 C++
【C++】:拷贝构造函数和赋值运算符重载
【C++】:拷贝构造函数和赋值运算符重载
30 1
|
5月前
|
C++ 索引
C++核心技术要点《运算符重载》
C++核心技术要点《运算符重载》
53 2
|
4月前
|
自然语言处理 程序员 C++
C++基础知识(五:运算符重载)
运算符重载是C++中的一项强大特性,它允许程序员为自定义类型(如类或结构体)重新定义标准运算符的行为,使得这些运算符能够适用于自定义类型的操作。这样做可以增强代码的可读性和表达力,使得代码更接近自然语言,同时保持了面向对象编程的封装性。
|
4月前
|
Java 程序员 C++
|
4月前
|
编译器 C++
【C++】详解运算符重载,赋值运算符重载,++运算符重载
【C++】详解运算符重载,赋值运算符重载,++运算符重载
|
5月前
|
编译器 C++
【C++】类和对象③(类的默认成员函数:赋值运算符重载)
在C++中,运算符重载允许为用户定义的类型扩展运算符功能,但不能创建新运算符如`operator@`。重载的运算符必须至少有一个类类型参数,且不能改变内置类型运算符的含义。`.*::sizeof?`不可重载。赋值运算符`=`通常作为成员函数重载,确保封装性,如`Date`类的`operator==`。赋值运算符应返回引用并检查自我赋值。当未显式重载时,编译器提供默认实现,但这可能不足以处理资源管理。拷贝构造和赋值运算符在对象复制中有不同用途,需根据类需求定制实现。正确实现它们对避免数据错误和内存问题至关重要。接下来将探讨更多操作符重载和默认成员函数。
|
6月前
|
程序员 C++
C++程序中的运算符重载
C++程序中的运算符重载
41 2