类和对象(中)(二)

简介: 类和对象(中)(二)

2. 操作符 ==

1. 错误写法
#include<iostream>
using namespace std;
class date
{
public:
  date(int year = 1, int month = 1, int day = 1)//构造
  {
    _year = year;
    _month = month;
    _day = day;
  }
  void print()
  {
    cout << _year << "-" << _month << "-" << _day << endl;
  }
//private://需要将_year等改为public
  int _year;
  int _month;
  int _day;
};
bool operator ==(const date& d1, const date& d2)//由几个参数,就接收几个
{
//判断年月日是否都相等
  return d1._year == d2._year && d1._month == d2._month && d1._day == d2._day;
}
int main()
{
  date d1(2022,12,21);
  date d2(2022,12,22);
  d1 == d2;
  cout << (d1 == d2) << endl;// 0 代表假
  return 0;
}

第一个参数作为左操作数,第二个参数作为右操作数

这样写看起来是对的,但是这种方法会 把date类中私有的成员变量变成共有的,破坏类的封装,不符合我们本意

2. 正确写法
  • 写入类中作为成员函数
#include<iostream>
using namespace std;
class date
{
public:
  date(int year = 1, int month = 1, int day = 1)//构造
  {
    _year = year;
    _month = month;
    _day = day;
  }
  void print()
  {
    cout << _year << "-" << _month << "-" << _day << endl;
  }
  bool operator ==( const date& d2)// 由于隐藏的this指针的存在,&d1传过来由this指针接收
  {
    return _year == d2._year && _month == d2._month && _day == d2._day;
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  date d1(2022,12,21);
  date d2(2022,12,22);
  d1 == d2;//  d1.operator==(d2) 等价于 d1.operator==(&d1,d2)
  cout << (d1 == d2) << endl;
  return 0;
}

传入类中,由于隐藏的this指针的存在,取第一个参数d1的地址传过去被this指针接收,_year等价于d1._year

但是由于this指针是隐藏的,所以&d1也不需要表现出来直接传入d2即可

3. cout << d1 == d2<< endl; 报错问题
  • 运算符优先级问题,<<代表流插入,<<优先级比==高,所以会先执行cout<<d1 ,剩余的 = =d2无法执行,就会报错

3. 注意事项

1. 不能通过连接其他符号来创建新的操作符 (如 operator@)

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

3.用于内置类型的操作符,其含义不能改变(如 int 加法 不能改变)

  • 所以要改成 (d1= =d2)来保证d1与d2先执行
  • 这里理解很简单,因为运算符重载是针对自定义类型的,对于内置类型,编译器都已经设置好了

4.作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的操作符有一个默认的形参this,限定为第一个形参

  • 这里理解很简单,因为运算符重载是针对自定义类型的,对于内置类型,编译器都已经设置好了

4.作为类成员的重载函数时,其形参看起来比操作数数目少1成员函数的操作符有一个默认的形参this,限定为第一个形参

4. 操作符 >

#include<iostream>
using namespace std;
class date
{
public:
  date(int year = 1, int month = 1, int day = 1)//构造
  {
    _year = year;
    _month = month;
    _day = day;
  }
  void print()
  {
    cout << _year << "-" << _month << "-" << _day << endl;
  }
  bool operator >( const date& d2)// 由于隐藏的this指针的存在,&d1传过来由this指针接收
  {
    if (_year > d2._year)//年大为大
    {
      return true;
    }
    else if (_year == d2._year && _month > d2._month) //年相等,月大为大
    {
      return true;
    }
    else if (_year == d2._year && _month == d2._month && _day > d2._day)//年 月相等,天大为大
    {
      return true;
    }
    else
    {
      return false;
    }
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  date d1(2022,12,21);
  date d2(2022,12,22);
  d1 > d2;//等价于 operator>(&d1,d2)
  cout << (d1 > d2) << endl;
  return 0;
}

判断大于时 ,同样存在一个隐藏的this指针,我们只需要判断 年大的就为大 ,年相等 ,月大的就为大,年月相等,天大的就为大,其他情况都为假

5. 操作符 !=

#include<iostream>
using namespace std;
class date
{
public:
  date(int year = 1, int month = 1, int day = 1)//构造
  {
    _year = year;
    _month = month;
    _day = day;
  }
  void print()
  {
    cout << _year << "-" << _month << "-" << _day << endl;
  }
  bool operator==(const date& d2)//d1==d2
  {
    return _year == d2._year && _month == d2._month && _day == d2._day;
  }
  bool operator!=(const date& d2)
  {
    return !(*this == d2);//借助上面的d1==d2的相反即 d1!=d2
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  date d1(2022,12,21);
  date d2(2022,12,22);
  d1 != d2;
  cout << (d1 != d2) << endl;
  return 0;
}

借助上面已经写好的d1==d2 ,取其相反 即为 d1!=d2

6. 操作符 <

#include<iostream>
using namespace std;
class date
{
public:
  date(int year = 1, int month = 1, int day = 1)//构造
  {
    _year = year;
    _month = month;
    _day = day;
  }
  void print()
  {
    cout << _year << "-" << _month << "-" << _day << endl;
  }
  bool operator >(const date& d2)// d1>d2
  {
    if (_year > d2._year)//年大为大
    {
      return true;
    }
    else if (_year == d2._year && _month > d2._month) //年相,月大为大
    {
      return true;
    }
    else if (_year == d2._year && _month == d2._month && _day > d2._day)//年 月相等,天大为大
    {
      return true;
    }
    else
    {
      return false;
    }
  }
  bool operator<(const date& d2)// d1 < d2
  {
    return !(*this > d2);
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  date d1(2022,12,21);
  date d2(2022,12,22);
  d1 < d2;
  cout << (d1 < d2) << endl;
  return 0;
}
  • 若直接写d1<d2 的条件太复杂,直接采用 d1 >d2 的相反,*this 代表 d1

2 .赋值操作符(编译器默认实现)

1. 正常使用

#include<iostream>
using namespace std;
class date
{
public:
  date(int year = 1, int month = 1, int day = 1)//构造
  {
    _year = year;
    _month = month;
    _day = day;
  }
  void print()
  {
    cout << _year << "-" << _month << "-" << _day << endl;
  }
  void operator=(const date& d2)
  {
    //为了防止自己给自己赋值的事情发生,如:d1=d1
    if ( this != &d2)
    {
      _year = d2._year;
      _month = d2._month;
      _day = d2._day;
    }
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  date d1(2022,12,21);
  date d2(2022,12,22);
  d1 =d2;
  return 0;
}
  • 如果是单个赋值这样就符合了,但是还是有连续赋值的情况存在

2. 连续赋值情况的考虑

#include<iostream>
using namespace std;
class date
{
public:
  date(int year = 1, int month = 1, int day = 1)//构造
  {
    _year = year;
    _month = month;
    _day = day;
  }
  void print()
  {
    cout << _year << "-" << _month << "-" << _day << endl;
  }
  date operator=(const date& d)//传值返回 类型为date
  {
    //为了防止自己给自己赋值的事情发生,如:d1=d1
    if (this != &d)
    {
      _year = d._year;
      _month = d._month;
      _day = d._day;
    }
    return *this;
  }
  date(const date& d)
  {
    _year = d._year;
    _month = d._month;
    _day = d._day;
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  date d1(2022, 12, 21);
  date d2(d1);
  date d3;
  d2 = d3 = d1;
  int i = 0;
  int j = 0;
  int z = 0;
  i = j = z;
  return 0;
}
  • 如果为内置类型,如int 则可以进行连续赋值
  • 对于int 来说,根据结合性,j=z ,返回值为j ,i=j,生成最终结果i
  • 对于 d2=d3=d1自定义类型来说,将 d1赋值给d3,将其返回值作为d2= 的右操作数存在
  • 所以operator= 要有一个返回值

传值返回

由于*this为date 类型,属于传值返回,即返回一个临时变量,所以需进行拷贝构造

同时也会多开辟一块空间存储, 就会导致当return ( * this) 返回时,传入拷贝构造中创建临时变量 ,再次从中返回时,才能返回到 主函数中


传引用返回


传 * this的引用作为变量的别名,相当于 * this本身,不会消耗一块空间,自然在return*this 返回时,不会进入拷贝构造中,而是直接返回

所以传引用返回更优

5. const成员

1.对象调用const成员函数

#include<iostream>
using namespace std;
class date
{
public:
  void print()
  {
    cout << _a << endl;
  }
private:
  int _a;
};
int main()
{
  const date a;
  a.print();//权限放大,会报错
  return 0;
}


  • 将&a传过去由this指针接收, a指针类型为 const date* ,this指针类型为 date* ,将const date * 传给date * 属于权限的放大
  • 把this指针类型改成 const date* 就可以了,但是由于this指针是隐藏的,要怎么解决呢?
#include<iostream>
using namespace std;
class date
{
public:
  void print()const //this指针类型变为const date*
  {
    cout << _a << endl;
  }
private:
  int _a;
};
int main()
{
  const date a;
  a.print();//正确 权限保持
  return 0;
}

在括号外面加上const,使this指针类型改成 const date*

const 在*左右对于指针的影响

const date* p1 : 修饰的是* p1, const在 * 左面 指针所指向的内容不变

date const * p2 : 修饰的是* p2,const在* 左面 指针所指向的内容不变

date * const p3 : 修饰的是 p3,const在 * 右面,指针本身不变

注意事项

#include<iostream>
using namespace std;
class date
{
public:
  void print()const //this指针类型变为const date*
  {
     _a=10;//报错
    cout << _a << endl;
  }
private:
  int _a;
};
int main()
{
  const date a;
  a.print();//正确 权限保持
  return 0;
}

若在print函数内部修改成员变量_a的值就会报错,_a代表this->_a,但是由于 this指针当前类型为 const date *,使this指向的内容不变

2.成员函数调用const成员函数

#include<iostream>
using namespace std;
class date
{
public:
  void f1()
  {
    f2();
  }
  void f2()const
  {
  }
private:
  int _a;
};
int main()
{
  date a;
  a.f1();
  return 0;
}

在f1中时,this指针的类型为 date*

进入 f2后, this指针 转换为 const date *

属于权限缩小 ,可以实现

#include<iostream>
using namespace std;
class date
{
public:
  void f3()
  {
  }
  void f4()const
  {
    f3();
  }
private:
  int _a;
};
int main()
{
  date a;
  a.f4();
  return 0;
}

f4中 this指针类型为 const date*

f3中 this指针类型为 date*

权限放大了,不可以实现

6.取地址及const取地址操作符重载

#include<iostream>
using namespace std;
class date
{
public:
  date* operator&()
  {
    return this;
  }
  const date* operator&()const
  {
    return this;
  }
};
int main()
{
  date d;
  cout << &d << endl;
  return 0;
}
相关文章
|
7月前
|
编译器 C# C++
【C++】类和对象(四)
【C++】类和对象(四)
|
存储 编译器 C++
|
7月前
|
存储 Java 数据安全/隐私保护
类和对象是什么?(上)
类和对象是什么?
72 4
|
存储 编译器 程序员
类和对象的介绍一
类和对象的介绍一
88 0
|
7月前
|
C语言 C++ 知识图谱
2. C++的类和对象
2. C++的类和对象
46 0
|
7月前
|
编译器 C++
【C++】:类和对象(3)
【C++】:类和对象(3)
71 0
|
7月前
|
存储 Java 编译器
C嘎嘎之类和对象上
C嘎嘎之类和对象上
70 0
|
存储 编译器 C语言
|
Java 编译器
类和对象(一)
类和对象(一)
79 0
|
存储 编译器 C语言
C++类和对象(中)
C++类和对象(中)