C++第八弹---类与对象(五)

简介: C++第八弹---类与对象(五)



1、运算符重载

1.1、赋值运算符重载

1. 赋值运算符重载格式

参数类型:const T&,传递引用可以提高传参效率。

返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值。

检测是否自己给自己赋值。

返回*this :要复合连续赋值的含义。

class Date
{
public:
  Date(int year = 2022, int month = 1, int day = 1)
  {
    _year = year;
    _month = month;
    _day = day;
  }
  Date& operator=(const Date& d)
  {
    if (this != &d)
        {
        _year = d._year;
        _month = d._month;
        _day = d._day;
        }
        return *this;
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  Date d1(2022, 2, 2);
  Date d2 = d1;
  return 0;
}

2. 赋值运算符只能重载成类的成员函数不能重载成全局函数

 

class Date
{
public:
  Date(int year = 2022, int month = 1, int day = 1)
  {
    _year = year;
    _month = month;
    _day = day;
  }
//private:
  int _year;
  int _month;
  int _day;
};
Date& operator=(Date& d1,const Date& d2)
{
  //成员变量必须为public访问限定符
  if (&d1 != &d2)
  {
    d1._year = d2._year;
    d1._month = d2._month;
    d1._day = d2._day;
  }
  return d1;
}
int main()
{
  Date d1(2022, 2, 2);
  Date d2 = d1;
  return 0;
}
// 编译失败:
// error C2801: “operator =”必须是非静态成员

原因:赋值运算符如果不显式实现,编译器会生成一个默认的。此时用户再在类外自己实现
一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值
运算符重载只能是类的成员函数。

3. 用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。

注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符
重载完成赋值。

class Time
{
public:
  Time()
  {
    _hour = 1;
    _minute = 1;
    _second = 1;
  }
  Time& operator=(const Time& t)
  {
    if (this != &t)
    {
      _hour = t._hour;
      _minute = t._minute;
      _second = t._second;
    }
    return *this;
  }
private:
  int _hour;
  int _minute;
  int _second;
};
class Date
{
public:
  Date(int year, int month, int day)
  {
    _year = year;
    _month = month;
    _day = day;
  }
private:
  // 基本类型(内置类型)
  int _year = 1970;
  int _month = 1;
  int _day = 1;
  // 自定义类型
  Time _t;
};
int main()
{
  Date d1(2022,1,1);
  Date d2 =d1;
  return 0;
}

既然编译器生成的默认赋值运算符重载函数已经可以完成字节序的值拷贝了,还需要自己实

现吗?当然像日期类这样的类是没必要的。那么下面的类呢?验证一下试试?

// 这里会发现下面的程序会崩溃掉?这里就需要我们以后讲的深拷贝去解决。
typedef int DataType;
class Stack
{
public:
  Stack(size_t capacity = 10)
  {
    _array = (DataType*)malloc(capacity * sizeof(DataType));
    if (nullptr == _array)
    {
      perror("malloc申请空间失败");
      return;
    }
    _size = 0;
    _capacity = capacity;
  }
  void Push(const DataType& data)
  {
    // CheckCapacity();
    _array[_size] = data;
    _size++;
  }
  ~Stack()
  {
    if (_array)
    {
      free(_array);
      _array = nullptr;
      _capacity = 0;
      _size = 0;
    }
  }
private:
  DataType* _array;
  size_t _size;
  size_t _capacity;
};
int main()
{
  Stack s1;
  s1.Push(1);
  s1.Push(2);
  s1.Push(3);
  s1.Push(4);
  Stack s2;
  s2 = s1;
  return 0;
}

注意:如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必

须要实现。

1.2、前置++和后置++重载

前置++:单目操作符,将一个值+1,遵循先++再使用原则。

后置++:单目操作符,将一个值+1,遵循先使用再++原则。

前置++和后置++都是两个+操作符的组合,那怎么区分重载的是前置++还是后置++呢?

C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器
自动传递

class Date
{
public:
  Date(int year = 2020, int month = 2, int day = 2)
  {
    _year = year;
    _month = month;
    _day = day;
  }
  // this指向的对象函数结束后不会销毁,故以引用方式返回提高效率
  Date& operator++()//前置++
  {
    _day += 1;
    return *this;
  }
  Date operator++(int)//后置++  加参数
  {
    //Date temp = *this;//赋值
    Date temp(*this);//拷贝  其中之一即可
    _day += 1;
    return temp;//temp是临时变量,出了函数会自动销毁,所以只能传值返回
  }
private:
  int _year;
  int _month;
  int _day;
};
int main()
{
  Date d(2022, 1, 1);
  Date d1;
  d1 = ++d;
  d1 = d++;
  return 0;
}

前置--后置--同前置++后置++原理,C++规定:后置--重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器自动传递。uu们可以自己下去手动实现喔~。

2、const成员

const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改

我们来看看下面的代码

class Date
{
public:
  Date(int year, int month, int day)
  {
    _year = year;
    _month = month;
    _day = day;
  }
  void Print()
  {
    cout << "Print()" << endl;
    cout << "year:" << _year << endl;
    cout << "month:" << _month << endl;
    cout << "day:" << _day << endl << endl;
  }
  void Print() const
  {
    cout << "Print()const" << endl;
    cout << "year:" << _year << endl;
    cout << "month:" << _month << endl;
    cout << "day:" << _day << endl << endl;
  }
private:
  int _year; // 年
  int _month; // 月
  int _day; // 日
};
int main()
{
  Date d1(2022, 1, 13);
  d1.Print();
  const Date d2(2022, 1, 13);
  d2.Print();
  return 0;
}

1、如果按照上面运行代码,d1打印的是不带const的打印函数,d2打印的是带const的打印函数。

2、如果屏蔽第一个不带const修饰的打印函数,程序依旧可以运行。因为非const类型调用const类型参数属于权限的缩小。

3、如果屏蔽第二个带有const修饰的打印函数,程序就不能正常运行。因为const类型调用非const类型参数属于权限的放大。

总结:

如果不需要改变类中成员函数或者成员变量的值,建议加上const修饰。

请思考下面的几个问题:

1. const对象可以调用非const成员函数吗?

不能,此处属于权限扩大。

2. 非const对象可以调用const成员函数吗?

可以,此处属于权限缩小。

3. const成员函数内可以调用其它的非const成员函数吗?

不能,此处属于权限扩大。

4. 非const成员函数内可以调用其它的const成员函数吗?

可以,此处属于权限缩小。

3、取地址及const取地址操作符重载

这两个默认成员函数一般不用重新定义 ,编译器默认会生成。

 

class Date
{
public:
  // 正常不写取地址重载的实质如下:
  Date* operator&()
  {
    return this;
  }
  const Date* operator&() const
  {
    return this;
  }
  // 可以手动进行修改
  //Date* operator&()
  //{
  //  return nullptr;
  //}
  //const Date* operator&() const
  //{
  //  int a = 10;
  //  return (const Date*)a;
  //}
};
int main()
{
  Date d1;
  const Date d2;
  cout << &d1 << endl;//调用取地址操作符重载
  cout << &d2 << endl;//调用const取地址操作符重载
  return 0;
}

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可,只有特殊情况,才需

要重载,比如想让别人获取到指定的内容!

总结

本篇博客就结束啦,谢谢大家的观看,如果公主少年们有好的建议可以留言喔,谢谢大家啦!

相关文章
|
2天前
|
编译器 C++
C++ 类构造函数初始化列表
构造函数初始化列表以一个冒号开始,接着是以逗号分隔的数据成员列表,每个数据成员后面跟一个放在括号中的初始化式。
43 30
|
16天前
|
C++
C++(十一)对象数组
本文介绍了C++中对象数组的使用方法及其注意事项。通过示例展示了如何定义和初始化对象数组,并解释了栈对象数组与堆对象数组在初始化时的区别。重点强调了构造器设计时应考虑无参构造器的重要性,以及在需要进一步初始化的情况下采用二段式初始化策略的应用场景。
|
16天前
|
存储 编译器 C++
C ++初阶:类和对象(中)
C ++初阶:类和对象(中)
|
16天前
|
C++
C++(十六)类之间转化
在C++中,类之间的转换可以通过转换构造函数和操作符函数实现。转换构造函数是一种单参数构造函数,用于将其他类型转换为本类类型。为了防止不必要的隐式转换,可以使用`explicit`关键字来禁止这种自动转换。此外,还可以通过定义`operator`函数来进行类型转换,该函数无参数且无返回值。下面展示了如何使用这两种方式实现自定义类型的相互转换,并通过示例代码说明了`explicit`关键字的作用。
|
16天前
|
存储 设计模式 编译器
C++(十三) 类的扩展
本文详细介绍了C++中类的各种扩展特性,包括类成员存储、`sizeof`操作符的应用、类成员函数的存储方式及其背后的`this`指针机制。此外,还探讨了`const`修饰符在成员变量和函数中的作用,以及如何通过`static`关键字实现类中的资源共享。文章还介绍了单例模式的设计思路,并讨论了指向类成员(数据成员和函数成员)的指针的使用方法。最后,还讲解了指向静态成员的指针的相关概念和应用示例。通过这些内容,帮助读者更好地理解和掌握C++面向对象编程的核心概念和技术细节。
|
30天前
|
存储 算法 编译器
c++--类(上)
c++--类(上)
|
1月前
|
编译器 C++
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决
virtual类的使用方法问题之C++类中的非静态数据成员是进行内存对齐的如何解决
|
1月前
|
编译器 C++
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
virtual类的使用方法问题之在C++中获取对象的vptr(虚拟表指针)如何解决
|
16天前
|
存储 C++
C++(五)String 字符串类
本文档详细介绍了C++中的`string`类,包括定义、初始化、字符串比较及数值与字符串之间的转换方法。`string`类简化了字符串处理,提供了丰富的功能如字符串查找、比较、拼接和替换等。文档通过示例代码展示了如何使用这些功能,并介绍了如何将数值转换为字符串以及反之亦然的方法。此外,还展示了如何使用`string`数组存储和遍历多个字符串。
|
25天前
|
存储 C++
C++ dll 传 string 类 问题
C++ dll 传 string 类 问题
16 0