拷贝构造函数和运算符重载(下)

简介: 拷贝构造函数和运算符重载(下)

operator<运算符重载

下面代码进行演示

//主要进行演示流程
class Person{
  public:
    Person(int age){
        _age=age;
    }
    bool operator<(const Person& p){
        if(_age<p.age) return true;
        else return false;
    }
    bool operator==(const Person& p){
        if(_age==p._age) return true;
        else return false;
    }
    bool operator<=(const Person& p){
        return (*this == p) && (*this < p);
    }
    int _age;
};
int main()
{
  Person P1(10);
  Person P2(20);
  cout << (P1 < P2) << endl;
    return 0;
}

为了提高服用率,我们通常将利用其他运算符重载来实现我们需要的运算符重载

bool operator<(const Person& p){
        if(_age<p.age) return true;
        else return false;
    } 
//只需要知道一个 < 一个 ==就能得到所有的比较大小的运算符重载
    bool operator==(const Person& p){
        if(_age==p._age) return true;
        else return false;
    }
    bool operator<=(const Person& p){
        return (*this == p) && (*this < p);
    }
//我们一定注意的是,运算符重载使用的的传引用,这样可以提高效率

赋值运算符

赋值运算符为operator=,这个运算符重载有一些细节要求

赋值运算符重载的格式

  1. 参数类型:const T&,传递引用可以提高传参效率,和上述保持一致
  2. 返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
  3. 检测是否自己给自己赋值
  4. 返回*this :要复合连续赋值的含义
//首先我们来看内置类型赋值的情况
int main()
{
    int n=10;
    n=20;
    int i,j,k;
    i=j=k=0;//连续赋值,0先给k返回的结果给了j再给了i,以至于i=j=k
    //所以我们需要的返回值类型应该为类类型 例如Person
    //又因为,传引用返回可以提高效率(少一次拷贝构造返回),所以我们选择的是类类型&  如Person&
    cout<<n<<endl;//输出结果为n  这个会改变n的数值
    return 0;
}

所以我们自定义类型的赋值运算符重载也要这样,所以我们应该这样做

class Person{
  public:
    Person(int age){
        _age=age;
    }
    Person& operator=(const Person& p){
      if(*this!=p){
            //如果两个对象不是同一个对象
            _age=p._age;//进行赋值
        }
        return *this;//这个this的生命周期不在类里面,所以是可以传引用返回
    }
    int _age;
};
int main()
{
    Person p1(10);
    Person p2(20);
    cout<<p1=p2<<endl;
  return 0;
}

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

Vs2022版本的编译器对于全局的赋值运算符重载会直接编译报错,并提示,operator=必须是成员函数

这是因为,我们规定返回类型为传引用,但是如果是全局函数,那么左值的生命周期在调用完函数之后把就结束的,所以这个地方也有问题,且“operator =”必须是非静态成员

原因解释:

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

也就是说,这个实际上就是存在默认的赋值运算符重载,所以才不能用于全局函数

用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

总结:

  • 对于赋值运算符重载,在没有自定义的时候,编译器会自动提供默认赋值运算符重载,且这个默认函数是值拷贝,也就是浅拷贝的
  • 内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。
  • 对于类似于栈Stack这样的类,是需要自定义的,但是对于Date或者上述Person类是不需要的,使用默认的即可
  • 如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现。

前置++和后置++重载

我们先看内置类型前置++和后置++的区别

int main()
{
    int n=10;
    int a=n++;//后++,这一行n还是为10 这个代码结束 后 n为11
    int b=++n;//先++,这一行n就为11
    cout<<a<<" "<<b<<endl;
    return 0;
}

所以自定义类型也需要按照内置类型的方式来实现前置后置++

class Person {
public:
    void Print() {
        cout << _age << endl;
    }
    Person(int age) {
        _age = age;
    }
    //我们规定前置++为无参
    Person& operator++() {
        (*this)._age++;
        return *this;
    }
    //后置++  括号使用这个无参类型表示
    Person operator++(int) {
        Person tmp = *this;
        (*this)._age+=1;
        return tmp;//返回临时变量,所以不能传引用返回
    }
    int _age;
};
int main()
{
    Person p(10);
    cout << p._age << endl;
    p++;
    p.Print();
    cout << p._age << endl;
    ++p;
    cout << p._age << endl;
    return 0;
}

相关文章
|
4月前
|
存储 编译器 C++
【C++】:拷贝构造函数和赋值运算符重载
【C++】:拷贝构造函数和赋值运算符重载
26 1
|
5月前
|
存储 编译器 C++
【c++】拷贝构造函数
【c++】拷贝构造函数
【c++】拷贝构造函数
|
5月前
|
编译器 C++
C++拷贝构造函数和运算符重载--1
C++拷贝构造函数和运算符重载--1
|
5月前
|
C++
C++拷贝构造函数和运算符重载--2
C++拷贝构造函数和运算符重载--2
|
5月前
|
编译器 C++
C++拷贝构造函数和运算符重载--4
C++拷贝构造函数和运算符重载--4
|
5月前
|
C++
C++拷贝构造函数和运算符重载--5
C++拷贝构造函数和运算符重载--5
|
5月前
|
C++
C++拷贝构造函数和运算符重载--3
C++拷贝构造函数和运算符重载--3
|
存储 编译器 C++
拷贝构造函数和运算符重载(上)
拷贝构造函数和运算符重载(上)
C++中拷贝构造函数的使用
C++中拷贝构造函数的使用
177 0