C++ 赋值运算重载,const成员,取地址及const取地址操作符重载-CSDN博客
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
C++ 赋值运算重载const成员取地址及const取地址操作符重载
所属专栏C“嘎嘎" 系统学习❤️
>博主首页初阳785❤️
>代码托管chuyang785❤️
>感谢大家的支持您的点赞和关注是对我最大的支持❤️
>博主也会更加的努力创作出更优质的博文❤️
>关注我关注我关注我重要的事情说三遍❤️
1. 赋值运算符重载
1.1 运算符重载
- 我们知道两个内置类型之间是可以进行适合的运算的比如两个整形是可以进行加减乘除的也可以进行比较两个数的大小关系以此相对应chardouble类型的也是可以进行类似的操作的。但是这些都是仅仅有限于内置类型如果变成了自定义类型呢自定义类型也可以做到像自定义类型一样的操作吗?所以C++中为了解决这个方法有了运算符重载的概念。
C++为了增强代码的可读性引入了运算符重载运算符重载是具有特殊函数名的函数也具有其
返回值类型函数名字以及参数列表其返回值类型与参数列表与普通的函数类似。
函数名字为关键字operator后面接需要重载的运算符符号。
函数原型返回值类型 operator操作符(参数列表)
- 注意
1.不能通过连接其他符号来创建新的操作符比如operator@
2.重载操作符必须有一个类类型参数
3.用于内置类型的运算符其含义不能改变例如内置的整型+不 能改变其含义
4.作为类成员函数重载时其形参看起来比操作数数目少1因为成员函数的第一个参数为隐藏的this
4..* :: sizeof ?: .
注意以上5个运算符不能重载。这个经常在笔试选择题中出
现
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// bool operator==(Date* this, const Date& d2)
// 这里需要注意的是左操作数是this指向调用函数的对象
bool operator==(const Date& d2) //操作数opertor
{
return _year == d2._year
&& _month == d2._month
&& _day == d2._day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2;
bool ret = d1 == d2; // ——> 本质是d1.operato==(d2);(operato==整体看作是一个函数名但是做了优化之后就可以直接使用
if (ret)
{
cout << "d1 == d2" << endl;
}
else
{
cout << "d1 != d2" << endl;
}
return 0;
}
1.2 赋值运算符重载
1.赋值运算符重载格式
- 参数类型const T&传递引用可以提高传参效率
- 返回值类型T&返回引用可以提高返回的效率有返回值目的是为了支持连续赋值
- 检测是否自己给自己赋值
- 返回*this 要复合连续赋值的含义
class Date
{
public:
Date(int year = 1, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
Date(const Date& d)
{
_year = d._year;
_month = d._month;
_day = d._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;
Date d2(2023, 10, 28);
d1 = d2;//本质上是——> d1.operator=(d2)
return 0;
}
- 赋值运算符只能重载成类的成员函数不能重载成全局函数
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
int _year;
int _month;
int _day;
};
// 赋值运算符重载成全局函数注意重载成全局函数时没有this指针了需要给两个参数
Date& operator=(Date& left, const Date& right)
{
if (&left != &right)
{
left._year = right._year;
left._month = right._month;
left._day = right._day;
}
return left;
}
int main()
{
Date d1;
Date d2(2023, 10, 28);
d1 = d2;//本质上是——> d1.operator=(d2)
return 0;
}
我们在看一段代码
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
int _year;
int _month;
int _day;
};
int main()
{
Date d1;
Date d2(2023, 10, 28);
d1 = d2;//这里没有进行重载但是也是可以的
return 0;
}
- 原因赋值运算符如果不显式实现
编译器会生成一个默认的
。此时用户再在类外自己实现
一个全局的赋值运算符重载就和编译器在类中生成的默认赋值运算符重载冲突了故赋值
运算符重载只能是类的成员函数
3.用户没有显式实现时编译器会生成一个默认赋值运算符重载以值的方式逐字节拷贝。注
意内置类型成员变量是直接赋值的而自定义类型成员变量需要调用对应类的赋值运算符
重载完成赋值。这一点和前面的拷贝构造是一样的道理。
- 那么有小伙伴就会问了既然我们不写显示实现运算符重载编译器会帮我们实现重载的效果那我们为什么还要自己再写一个呢这个时候我们可以回顾一下我们之前的拷贝构造在我们没有涉及到资源管理的时候拷贝构造是正常的但是一旦我们malloc一块空间的时候就出问题了而这里也是一样的起始赋值运算是一种特殊的拷贝构造。
1.3 前置++/–和后置++/–重载
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// 前置++返回+1之后的结果
// 注意this指向的对象函数结束后不会销毁故以引用方式返回提高效率
Date& operator++()
{
_day += 1;
return *this;
}
private:
int _year;
int _month;
int _day;
};
- 上面是前置++ 的运算符重载操作。
现在小伙伴们想一想后置++怎么办呢
首先就是他的重载格式是什么样的
返回类型是什么
因为我们的后置++ 的规则是先使用后++的也就是说只有在一条语句结束后才会++。
那么我们因该怎么实现呢
在C++中为了区分前置和后置C++中用占位参数来区分前置和后置没有占位参数的是前置又占位参数的是后置并规定占位参数的类型是int。
class Date
{
public:
Date(int year = 1900, int month = 1, int day = 1)
{
_year = year;
_month = month;
_day = day;
}
// 后置++
// 前置++和后置++都是一元运算符为了让前置++与后置++形成能正确重载
// C++规定后置++重载时多增加一个int类型的参数但调用函数时该参数不用传递编译器自动传递
// 注意后置++是先使用后+1因此需要返回+1之前的旧值故需在实现时需要先将this保存一份然后给this + 1
// 而temp是临时对象因此只能以值的方式返回不能返回引用
Date operator++(int)
{
Date temp(*this);//先保存原先的值
_day += 1;//再进行加加
return temp;//最后返回保存的值
}
private:
int _year;
int _month;
int _day;
};
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 << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date d1(2023, 11, 1);
d1.Print();
return 0;
}
我们看这串代码是没什么问题的但是如果我用const修饰一下d1呢
const Date d1(2023, 11, 1);
d1.Print();
这个时候还能通过吗
这个时候就会报错啦因为存在权限放大
原本是:
- 但是我们对d1用const修饰的时候我们传过去的类型是const d1是不可修改的但是我们函数接受的参数类型却不是const不可修改的类型所以这里就有权限放大的问题。
解决这个问题的办法也很简单就是把我我们的形参也改成const修饰的参数即const Date* const this
但是问题是const加在那里C++规定成员函数用const修饰加在形参列表之后
我们在看一下这段代码
class Date
{
public:
Date(int year, int month, int day)
{
_year = year;
_month = month;
_day = day;
}
void Print() const
{
cout << _year << "/" << _month << "/" << _day << endl;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
const Date d1(2023, 11, 1);
d1.Print();
Date d2(2023, 11, 1);
d2.Print();
return 0;
}
- 这里的d2会不会出错呢
分析一下我们的成员函数是用const修饰的而d2却没有使用const修饰的。
但是这里是不会报错的因为这里是属于权限的缩小。
C++规定权限允许权限的平移和缩小的。
所以既然权限允许缩小的话这里建议小伙伴们在写成员函数的时候成员对象不可修改尽量用const修饰这样跟更能保证代码的容错率因为即使成员对象没有用const修饰有权限缩小这特性还是可以通过的。
3. 取地址及const取地址操作符重载
- 这两个默认成员函数一般不用重新定义 编译器默认会生成。
class Date
{
public:
Date* operator&()
{
return this;
}
const Date* operator&()const
{
return this;
}
private:
int _year; // 年
int _month; // 月
int _day; // 日
};
int main()
{
Date d1;
Date d2;
cout << &d1 << endl;
cout << &d2 << endl;
return 0;
}
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |