7. C++运算符重载

简介: 7. C++运算符重载

C++运算符重载

什么是运算符重载

  • 运算符重载赋予运算能够操作自定义类型。
  • 运算符重载前提条件: 必定存在一个自定义类型
  • 运算符重载实质: 就是函数调用
  • 友元重载
  • 类重载
  • 在同一自定义类型中,一个运算符只能被重载一次
  • C++重载只能重载已有的运算符,不能重载没有
  • C++重载一般情况不能违背运算符原来的含义(就算语法正确)
  • 注意点:
  • .   ,.* ,?:,:: 不能被重载

#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
  MM() {}
  MM(string name, int score) :name(name), score(score) {}
protected:
  string name;
  int score;
};
int main() 
{
  int a = 1;
  int b = 2;
  int sum = a + b;
  MM mm("小芳", 6);
  MM girl("小芳", 2);
  //error: 没有与这些操作数匹配 "xxx" 运算符
  //MM result = mm + girl;      //错误
  return 0;
}

重载写法

重载函数的写法

//函数定义方式
函数返回值类型  函数名(参数)
{
   //函数体;    
}
//运算符重载也是函数,只是函数名写法不同
//函数名: operator加上运算符组成函数名
//参数:
//    友元重载: 参数个数等于操作数
//    类成员函数: 参数个数等于操作-1
//    函数返回值类型:运算符组成表达式 最终结果是什么类型就返回类型
//    int a; int b;  a+b 返回int
// 函数体:写你真正要实现的效果

友元重载

#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
  MM() {}
  MM(string name, int score) :name(name), score(score) {}
  void print() 
  {
    cout << name << "\t" << score << endl;
  }
  //友元重载
  friend MM operator+(MM a, MM b);    //加法重载函数的声明
protected:
  string name;
  int score;
};
MM operator+(MM a, MM b) 
{
  return MM(a.name, a.score+b.score);  //返回一个匿名对象
}
int main() 
{
  int a = 1;
  int b = 2;
  int sum = a + b;
  MM mm("小芳", 6);
  MM girl("小芳", 2);
  //error: 没有与这些操作数匹配 "xxx" 运算符
  //重载函数的隐式调用 -->mm + girl 解析为:operator+(mm, girl)
  MM result = mm + girl;          //显示绿色就是运算符重载
  result.print();
  //重载函数显示调用:按照函数的调用方式
  MM res = operator+(mm, girl);     //operator+:函数名  参数
  //string aa("12");
  //string bb("2323");
  //cout << (aa > bb) << endl;
  return 0;
}

类重载

#include <iostream>
#include <string>
using namespace std;
class MM
{
public:
  MM() {}
  MM(string name, int score) :name(name), score(score) {}
  void print() 
  {
    cout << name << "\t" << score << endl;
  }
  //友元重载
  friend MM operator+(MM a, MM b);    //加法重载函数的声明
protected:
  string name;
  int score;
};
//类成员函数少一个参数: 对象本身可以表示参数
MM MM::operator-(MM object)
{
  return MM(this->name, this->score - object.score);
}
int main() 
{
  MM mul = mm.operator-(girl);      //类重载显示调用,跟调用普通成员函数一样的
  mul.print();
  MM girlFriend = mm - girl;        //编译器mm - girl翻译为: mm.operator-(girl)
  girlFriend.print();
  return 0;
}

特殊运算符重载

  • 通常情况:单目运算符用类成员函数重载,双目用友元重载
  • = ,(),->,[] 只能采用成员函数重载
  • ++ --运算符重载
  • 增加一个无用参数,标识是后置++或者--
  • 流运算符重载(>> <<)
  • 输入流对象(cin): istream类
  • 输出流对象(cout): ostream类
  • 流重载必须用引用
  • 流重载一定要用友元重载
  • 后缀重载
#include <iostream>
#include <string>
#include <thread>
using namespace std;
class MM 
{
public:
  MM() {}
  MM(string name, int age) :name(name), age(age) {}
  void print() 
  {
    cout << name << "\t" << age << endl;
  }
  //MM operator=(MM) = delete;    //删掉默认的
  //函数重载
  void operator=(int data) 
  {
    this->age += data;
  }
  //++ 为例
  MM operator++()           //前置
  {
    this->age++;
    return *this;         //返回对象本身
  }
  MM operator++(int)          //后置的
  {
    return MM(this->name, this->age++);
  }
  //流运算符的重载
  friend ostream& operator<<(ostream& out, MM& object);
  friend istream& operator>>(istream& in, MM& object);
private:
  string name;
  int age;
};
ostream& operator<<(ostream& out, MM& object) 
{
  //out当做cout用
  out << object.name << "\t" << object.age << endl;
  return out;
}
istream& operator>>(istream& in, MM& object) 
{
  cout << "输入对象属性:";
  //in当做cin用即可
  in >> object.name >> object.age;
  return in;
}
//文本重载, 一般写成下划线系列
//后缀的重载
unsigned long long operator""_h(unsigned long long data) 
{
  return data * 60 * 60;
}
unsigned long long operator""_m(unsigned long long data)
{
  return data * 60;
}
unsigned long long operator""_s(unsigned long long data)
{
  return data;
}
int main() 
{
  MM mm("小芳", 18);
  MM girl;
  girl = mm;        //每一个类中都存在默认的赋值重载
  girl = 8;
  girl.print();
  MM result = ++girl;
  result.print();
  girl.print();
  result = girl++;
  result.print();
  girl.print();
  cin >> girl;
  cout << girl << endl; 
  //this_thread::sleep_for(10s);
  cout << 1_h << endl;
  cout << (1_h + 30_m + 49_s) << endl;
  return 0;
}

对象的隐式转换

对象隐式转换: 就是让对象能够赋值给普通数据

//operator  转换的类型()
//{ 
//  return 要转换类型的数据;
//}
#include <string>
#include <iostream>
using namespace std;
class MM 
{
public:
  MM() {}
  MM(string name, int age) :name(name), age(age) {}
  operator int() 
  {
    return this->age;
  }
protected:
  string name;
  int age;
};
int main() 
{
  MM mm("mm", 39);
  int age = mm;
  cout << age << endl;
  return 0;
}

()运算符的重载

仿函数

让类型可以模仿函数调用的行为: 函数名(参数); 类名() 调用的函数行为

#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
class Data 
{
public:
  //operator()组成函数名
  void operator()() 
  {
    cout << "无参重载()" << endl;
  }
  void operator()(int a, int b) 
  {
    cout << "有参重载(a,b)" << endl;
  }
protected:
};
int main() 
{
  //greater<int>();  //比较准则
  //int array[5] = { 3,4,1,2,32 };
  //sort(array, array + 5, greater<int>());
  //for (auto& v : array) 
  //{
  //  cout << v << "\t";
  //}
  //cout << endl;
  Data data;
  data.operator()();    //显式调用
  data.operator()(1, 2);  //显式调用
  data();         //隐式调用
  data(1, 2);       //隐式调用
  Data{}();       //{}帮助识别  Data()
  Data{}(2, 3);
  return 0;
}

运算符重载案例分析

智能指针

智能指针是用对象方式管理new的内存,可以做到自动释放(本质是析构函数自动调用)内存的功能

#include <iostream>
#include <memory>
using namespace std;
class Auto_Ptr 
{
public:
  Auto_Ptr(int* ptr) :ptr(ptr) {}
  ~Auto_Ptr() 
  {
    if (ptr) 
    {
      delete ptr;
      ptr = nullptr;
    }
  }
  //访问指针
  int* operator->() 
  {
    return this->ptr;
  }
  //访问数据
  int& operator*() 
  {
    return *ptr;
  }
  //禁止拷贝,禁止赋值
  Auto_Ptr(Auto_Ptr&) = delete;
  Auto_Ptr& operator=(Auto_Ptr&) = delete;
protected:
  int* ptr;
};
int main() 
{
  Auto_Ptr object(new int(1999));
  cout << *object << endl;
  //shared_ptr<int>  p(new int(19999));
  //cout << *p << endl;
  //shared_ptr<double>  p2(new double(19.99));
  //cout << *p2 << endl;
  return 0;
}

封装数组

#include <iostream>
#include <vector>     //动态数组
using namespace std;
class my_vector 
{
public:
  my_vector(int capacity = 10) :capacity(capacity) 
  {
    mem = new int[capacity] {0};
    curSize = 0;
  }
  void push_back(int data) 
  {
    mem[curSize++] = data;
  }
  int* begin() 
  {
    return mem + 0;
  }
  int* end() 
  {
    return mem + capacity;
  }
  int& operator[](int index) 
  {
    if (curSize < index)
      curSize = index;
    return mem[index];
  }
  //万金油函数
  int size() 
  {
    return curSize;
  }
  int empty() 
  {
    return curSize == 0;
  }
  ~my_vector() 
  {
    if (mem) 
    {
      delete[] mem;
      mem = nullptr;
    }
  }
protected:
  int* mem;
  int capacity;
  int curSize;
};
int main() 
{
  my_vector vec;
  for (int i = 0; i < 3; i++) 
  {
    vec[i] = i;
  }
  for (auto v : vec) 
  {
    cout << v << "\t";
  }
  cout << endl;
  cout << vec.size() << endl;
  for (int i = 0; i < vec.size(); i++) 
  {
    cout << vec[i] << "\t";
  }
  cout << endl;
  return 0;
}

迭代器实现

//迭代器就是让一个类中类去遍历数据

#include <iostream>
#include <string>
using namespace std;
struct Node 
{
  int data;
  Node* next;
  Node() :next(nullptr){}
  Node(int data) :data(data), next(nullptr) {}
  Node(int data, Node* next) :data(data), next(next) {}
};
class List 
{
public:
  List() :headNode(new Node),curSize(0){}
  void push_front(int data) 
  {
    headNode->next = new Node(data, headNode->next);
    curSize++;
  }
  Node* begin() 
  {
    return headNode->next;
  }
  Node* end() 
  {
    return nullptr;
  }
  class iterator 
  {
  public:
    iterator() :pmove(nullptr) {}
    void operator=(Node* pmove) 
    {
      this->pmove = pmove;
    }
    bool operator!=(Node* pmove) 
    {
      return this->pmove != pmove;
    }
    iterator operator++() 
    {
      this->pmove = this->pmove->next;  //链表++不了
      return *this;
    }
    int operator*() 
    {
      return this->pmove->data;     //*运算访问数据
    }
  private:
    Node* pmove;      //需要指针访问数据
  };
protected:
  Node* headNode;
  int curSize;
};
void my_list() 
{
  List list;
  for (int i = 0; i < 3; i++) 
  {
    list.push_front(i);
  }
  List::iterator it;
  for (it = list.begin(); it != list.end(); ++it)
  {
    cout << *it << " ";
  }
  cout << endl;
}
int main() 
{
  string str = "ILoveyou";
  for (int i = 0; i < str.size(); i++) 
  {
    cout << str[i];
  }
  cout << endl;
  //类中类访问一个容器数据
  string::iterator it;
  for (it = str.begin(); it != str.end(); it++) 
  {
    cout << *it;    //*指针取值运算
  }
  cout << endl;
  //cout << *str.end() << endl;
  my_list();
  return 0;
}

重载的特殊问题

//对象与常量运算
#include <iostream>
#include <string>
using namespace std;
class Data 
{
public:
  Data() {}
  Data(int num) :num(num) {}
  //friend Data operator+(Data data, int num);
  //friend Data operator+( int num, Data data);
  //Data operator+(Data data) 
  //{
  //  return Data(this->num + data.num);
  //}
  void print() 
  {
    cout << num << endl;
  }
  friend Data operator+(Data data1, Data data2);
protected:
  int num;
};
//Data operator+(Data data, int num) 
//{
//  return Data(data.num + num);
//}
//Data operator+(int num, Data data) 
//{
//  return Data(num + data.num);
//}
Data operator+(Data data1, Data data2) 
{
  return Data(data1.num + data2.num);
}
int main() 
{
  Data data(1);
  Data temp;
  //data.成员函数(1);
  temp = data + 1;
  //1+data : 1.成员函数()
  temp = 1 + data;   //类成员函数没办法完成
  temp.print();
  return 0;
}
目录
相关文章
|
1月前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
83 5
|
6月前
|
编译器 C++
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
C++进阶之路:何为运算符重载、赋值运算符重载与前后置++重载(类与对象_中篇)
53 1
|
7月前
|
程序员 编译器 C++
C++中的运算符重载(Operator Overloading)
C++中的运算符重载(Operator Overloading)
62 1
|
3月前
|
C++
C++(十五) 运算符重载
C++中的运算符重载允许对已有运算符的功能进行重新定义,从而扩展语言功能、简化代码并提升效率。重载遵循特定语法,如 `friend 类名 operator 运算符(参数)`。重载时需注意不可新增或改变运算符数量、语义、优先级、结合性和返回类型。常见示例包括双目运算符 `+=` 和单目运算符 `-` 及 `++`。输入输出流运算符 `&lt;&lt;` 和 `&gt;&gt;` 也可重载。部分运算符只能作为成员函数重载。
|
6月前
|
存储 编译器 C++
【C++】:拷贝构造函数和赋值运算符重载
【C++】:拷贝构造函数和赋值运算符重载
32 1
|
6月前
|
C++ 索引
C++核心技术要点《运算符重载》
C++核心技术要点《运算符重载》
54 2
|
5月前
|
自然语言处理 程序员 C++
C++基础知识(五:运算符重载)
运算符重载是C++中的一项强大特性,它允许程序员为自定义类型(如类或结构体)重新定义标准运算符的行为,使得这些运算符能够适用于自定义类型的操作。这样做可以增强代码的可读性和表达力,使得代码更接近自然语言,同时保持了面向对象编程的封装性。
|
5月前
|
Java 程序员 C++
|
5月前
|
编译器 C++
【C++】详解运算符重载,赋值运算符重载,++运算符重载
【C++】详解运算符重载,赋值运算符重载,++运算符重载
|
6月前
|
编译器 C++
【C++】类和对象③(类的默认成员函数:赋值运算符重载)
在C++中,运算符重载允许为用户定义的类型扩展运算符功能,但不能创建新运算符如`operator@`。重载的运算符必须至少有一个类类型参数,且不能改变内置类型运算符的含义。`.*::sizeof?`不可重载。赋值运算符`=`通常作为成员函数重载,确保封装性,如`Date`类的`operator==`。赋值运算符应返回引用并检查自我赋值。当未显式重载时,编译器提供默认实现,但这可能不足以处理资源管理。拷贝构造和赋值运算符在对象复制中有不同用途,需根据类需求定制实现。正确实现它们对避免数据错误和内存问题至关重要。接下来将探讨更多操作符重载和默认成员函数。