C++拷贝构造函数和运算符重载--3

简介: C++拷贝构造函数和运算符重载--3

C++拷贝构造函数和运算符重载--2

https://developer.aliyun.com/article/1424586

二,运算符重载

引入:


       在内置类型中,系统给我们自动定义了很大运算符,如:+、-、*、/、++、--、>等。这些内置类型和内置类型运算符的使用都是系统定义好的,可直接使用。现在问题来了,自定义类型要想使用这些运算符又当如何?由于自定义类型是我们自己定义的,系统不知道其结构,所以无法直接供我们使用,但C++为了增强代码的可读性引入了运算符重载的概念,可让自定义类型也使用这些运算符。运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。


运算符重载的定义:


       函数名:关键字operator后面接需要重载的运算符符号。


       函数原型:返回值类型 operator操作符(参数列表)。


这里有以下5个注意:


       1,不能通过连接其他符号来创建新的操作符:比如operator@


       2,重载操作符必须有一个类类型参数


       3,用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不能改变其+本身的含义


       4,作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this指针。


       5,“ .*    ::    sizeof    ?:    . ” 注意这5个运算符不能重载。这个经常在笔试选择题中出现。


在类的内部定义


第一个参数为this指针
// '='操作符,返回类型为类类型Date的引用
Date& operator=(const Date& d);
Date& Date::operator=(const Date& d);//此种情况是在类中声明,在外部实现,用限定符说明是类对象中的成员函数
// "+="操作符,返回类型为类类型Date的引用
Date& operator+=(int day);
Date& Date::operator+=(int day);//此种情况是在类中声明,在外部实现,用限定符说明是类对象中的成员函数
// '+'操作符,返回类型为类类型Date的引用
Date operator+(int day);
Date Date::operator+(int day);//此种情况是在类中声明,在外部实现,用限定符说明是类对象中的成员函数
// '-'操作符,返回类型为类类型Date的引用
Date operator-(int day);
Date Date::operator-(int day);//此种情况是在类中声明,在外部实现,用限定符说明是类对象中的成员函数
// "-="操作符,返回类型为类类型Date的引用
Date& operator-=(int day);
Date& Date::operator-=(int day);//此种情况是在类中声明,在外部实现,用限定符说明是类对象中的成员函数


在类的外部定义


没有默认参数,需要把类写入形参中
// "+="操作符,返回类型为类类型Date的引用
Date& operator+=(const Date& d1, int day);
// '+'操作符,返回类型为类类型Date的引用
Date operator+(const Date& d1, int day);
// '-'操作符,返回类型为类类型Date的引用
Date operator-(const Date& d1, int day);
// "-="操作符,返回类型为类类型Date的引用
Date& operator-=(const Date& d1, int day);

运用细节演示:


       (1)首先,我们先对“ >,<,>=,<=,==,!= ”这几个简单运算符在类对象内定义进行演示和解说。


#include <iostream>
#include <assert.h>
using namespace std;
//再次提醒一下,类对象中的成员函数第一个默认参数为this,且指向此对象,下面运用时就不做说明
class Date
{
public:
  // 全缺省的构造函数
  Date(int year = 1900, int month = 1, int day = 1)
  {
  _year = year;
  _month = month;
  _day = day;
  }
  // ==运算符重载
  bool operator==(const Date& d)
  {
  return _year == d._year &&
    _month == d._month &&
    _day == d._day;
  }
  // !=运算符重载
  bool operator != (const Date& d)
  {
  return !(*this == d);
  }
  // >运算符重载
  bool operator>(const Date& d)
  {
  if (_year > d._year)
    return true;
  else if (_year == d._year && _month > d._month)
    return true;
  else if (_year == d._year && _month == d._month && _day > d._day)
    return true;
  return false;
  }
  // >=运算符重载
  bool operator >= (const Date& d)
  {
  return *this > d || *this == d;
  }
  // <运算符重载
  bool operator < (const Date& d)
  {
  if (_year < d._year)
    return true;
  else if (_year == d._year && _month < d._month)
    return true;
  else if (_year == d._year && _month == d._month && _day < d._day)
    return true;
  return false;
  }
  // <=运算符重载
  bool operator <= (const Date& d)
  {
  return *this < d || *this == d;
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  Date d1;
  Date d2(2023, 10, 16);
  cout << (d1 > d2) << endl;//d1 > d2等效于d1.operator>(d2),这两个表达的意思一样
  cout << d1.operator>(d2) << endl;
  return 0;
}

       在上面代码中要说明的是在运算符表示过程中,我们即可用函数来表示运算符的含义,也可直使用运算符的形式表示含义。


在上面的运算符函数中:
d1 > d2等效于d1.operator(d2)
d1 == d2等效于d1.operator(d2)
上面的输出流中之所以(d1 > d2)用括号括起来是因为“ << ”操作符的运算级别高,会先与之运算。


       (2)接下来我们对“ +,-,+=,-= ”这几个简单运算符在类对象内定义进行演示和解说。


#include <iostream>
#include <assert.h>
using namespace std;
class Date
{
public:
  // 获取某年某月的天数
  int GetMonthDay(int year, int month)
  {
  assert(year >= 1 && (month >= 1 && month <= 12));
  int MonthDays[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
  if ((month == 2) && ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)))
    return 29;
  return MonthDays[month];
  }
  // 全缺省的构造函数
  Date(int year = 1900, int month = 1, int day = 1)
  {
  _year = year;
  _month = month;
  _day = day;
  }
  // 日期-天数
  Date operator-(int day)
  {
  _day -= day;
  while (_day < 0) {
    if (_month == 1) {
    _year--;
    if (_year < 0) {
      perror("Date Count Error:");
      exit(-1);
    }
    _month = 12;
    }
    else {
    _month--;
    }
    _day += GetMonthDay(this->_year, this->_month);
  }
  return *this;
  }
  // 日期-=天数
  Date& operator-=(int day)
  {
  Date DateCopy(*this);
  //用临时对象返回,相当于函数的返回,需要有个对象去接收,而改变的只是临时对象
  //像直接使用类d1 -= 5,表达的只是此函数的功能,d1的值不会改变,若是d1 = d1 -= 5将会改变
  //DateCopy = DateCopy.operator-(day);
  //return DateCopy;
  //this指针直接指向的是此对象(即此类),用this指针来改变相当于直接改变了d1,类似于达到了改变d1的效果
  *this = DateCopy.operator-(day);
  return *this;
  }
  // 日期+=天数
  Date& operator+=(int day)
  {
  _day += day;
  while (_day > GetMonthDay(this->_year, this->_month)) {
    _day -= GetMonthDay(this->_year, this->_month);
    _month++;
    if (_month > 12) {
    _year++;
    _month -= 12;
    }
  }
  return *this;
  }
  // 日期+天数
  Date operator+(int day)
  {
  Date DateCopy(*this);
  DateCopy.operator+=(day);
  return DateCopy;
  }
  // 日期-日期 返回天数
  int operator-(const Date& d)
  {
  int YearDay = 0, MonthDay = 0, Day = _day - d._day;
  while (--_month) {
    MonthDay += GetMonthDay(_year, _month);
  }
  int month = d._month;
  while (--month) {
    MonthDay -= GetMonthDay(d._year, month);
  }
  _year--;
  int year = d._year - 1;
  for (int YearCount = _year - year; YearCount > 0; YearCount--) {
    YearDay += 365;
    if ((_year % 400 == 0) || ((_year % 4 == 0) && (_year % 100 != 0)))
    YearDay += 1;
    _year--;
  }
  return YearDay + MonthDay + Day;
  }
  void Print() {
  cout << _year << "/" << _month << "/" << _day << endl;
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  Date d1(2023, 10, 16);
  Date d2;
  //+=和+运算符重载
  //这里要说明的是,由于"+="没有返回值,所以在函数对象内部改变的时候一定要用this指针来改变,this指针指向d1
  d1 += 365;
  cout << "d1重载d1+=365: ";
  d1.Print();
  d2 = d1 + 23;
  cout << "d2重载d2=d1+23: ";
  d2.Print();
  //-=和-的运算符重载
  //"-="运算符与"+="同理
  d1 -= 365;
  cout << "d1重载d1-=365: ";
  d1.Print();
  d2 = d1 - 365;
  cout << "d2重载d2=d1-365: ";
  d2.Print();
  //日期-日期的运用
  cout << "d2-d1: " << d2 - d1 << endl;
  return 0;
}

       这里要注意的是函数的返回类型,“ +=,-= ”运算一般是不需要返回类型的,所以在内部实现要用this访问,从而间接实现原对象的运算。“ +,- ”操作符要有返回类型去接收,可直接返回临时对象。


C++拷贝构造函数和运算符重载--4 https://developer.aliyun.com/article/1424601?spm=a2c6h.13148508.setting.29.214f4f0emw3QR7

相关文章
|
27天前
|
存储 编译器 C++
【c++】类和对象(下)(取地址运算符重载、深究构造函数、类型转换、static修饰成员、友元、内部类、匿名对象)
本文介绍了C++中类和对象的高级特性,包括取地址运算符重载、构造函数的初始化列表、类型转换、static修饰成员、友元、内部类及匿名对象等内容。文章详细解释了每个概念的使用方法和注意事项,帮助读者深入了解C++面向对象编程的核心机制。
70 5
|
3月前
|
C++
C++(十五) 运算符重载
C++中的运算符重载允许对已有运算符的功能进行重新定义,从而扩展语言功能、简化代码并提升效率。重载遵循特定语法,如 `friend 类名 operator 运算符(参数)`。重载时需注意不可新增或改变运算符数量、语义、优先级、结合性和返回类型。常见示例包括双目运算符 `+=` 和单目运算符 `-` 及 `++`。输入输出流运算符 `&lt;&lt;` 和 `&gt;&gt;` 也可重载。部分运算符只能作为成员函数重载。
|
6月前
|
C++ 容器
【C++】拷贝构造函数、拷贝赋值函数与析构函数
【C++】拷贝构造函数、拷贝赋值函数与析构函数
125 6
|
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==`。赋值运算符应返回引用并检查自我赋值。当未显式重载时,编译器提供默认实现,但这可能不足以处理资源管理。拷贝构造和赋值运算符在对象复制中有不同用途,需根据类需求定制实现。正确实现它们对避免数据错误和内存问题至关重要。接下来将探讨更多操作符重载和默认成员函数。
|
6月前
|
存储 编译器 C++
【C++】类和对象③(类的默认成员函数:拷贝构造函数)
本文探讨了C++中拷贝构造函数和赋值运算符重载的重要性。拷贝构造函数用于创建与已有对象相同的新对象,尤其在类涉及资源管理时需谨慎处理,以防止浅拷贝导致的问题。默认拷贝构造函数进行字节级复制,可能导致资源重复释放。例子展示了未正确实现拷贝构造函数时可能导致的无限递归。此外,文章提到了拷贝构造函数的常见应用场景,如函数参数、返回值和对象初始化,并指出类对象在赋值或作为函数参数时会隐式调用拷贝构造。