1.运算符重载介绍
1.C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
2.函数名字为: 关键字operator后面接需要重载的运算符符号
3.函数原型: 返回值类型 operator操作符(参数列表)
如:bool operator<(const int n)
注意:
1.不能通过连接其他符号来创建新的操作符: 比如operator@
2.重载操作符必须有一个类类型参数
3.用于内置类型的运算符,其含义不能改变,例如: 内置的整型+,不能改变其含义
4.作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this指针
重载流插入和流输出
运算符重载中,参数顺序和操作数顺序必须一致
特别的:当出现重载流插入或者流输出时,建议重载为全局函数,否则用起来不符合逻辑
//这么写才能转换(d1是一个日期类成员)
d1.operator<<(cout);
d1 << cout;
//全局以后这么写就可以了 因为参数的前后位置原因
cout << d1;
这里面又涉及了友元的概念(因为要访问类里的私有变量) 如下:
class Date
{
//友元函数声明 可以访问内部成员
friend ostream& operator<<(ostream& out, const Date& d);
//由于成员函数默认的第一个参数为隐含的this指针 所以函数声明在全局
friend istream& operator>>(istream& in, Date& d);
public:
private:
int _year ;
int _month ;
int _day ;
}
//返回值为cout的原因是可以连续重载输出
ostream& operator<<(ostream& out, const Date& d)
{
out << d._year << "年" << d._month << "月" << d._day << "日" << endl;
return out;
}
istream& operator>>(istream& in, Date& d)
{
in >> d._year >> d._month >> d._day;
return in;
}
关于更多的重载
可以查看我的gitee中的date日期类的实现 包含了大部分的操作符重载
例如前置++ 和后置++
链接: 重载gitee地址
2.赋值运算符重载
- 赋值运算符重载格式
1.参数类型:const T&,传递引用可以提高传参效率
2.返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
3.检测是否自己给自己赋值
4.返回*this :要复合连续赋值的含义
class Date
{
public :
Date(int year = 1900, 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 ;
}
关于返回值
关于返回值这里需要特殊说明
出了作用域,返回对象还在没有析构,那就可以用引用返回,减少拷贝返回对象生命周期到了,会析构,传值返回a.返回对象生命周期没到,不会析构,传引用返回
Date& operator=(const Date& d)
{
if(this != &d)
{
_year = d._year;
_month = d._month;
_day = d._day;
}
//注意这里的this是开辟在栈上的
//是main函数创建的类中的 所以可以传引用返回
return *this;
}
返回值传引用主要是为了减少拷贝次数
Date func()
{
Date d;
return d;
}
以上代码的返回值是不是d呢?
注意:返回值并不是d ,d出了作用域都销毁了
这里会生成一个临时拷贝 返回临时对象作为返回值
并且临时变量具有常性
而不生成的方法就是引用返回 但是这里并不能这么做
因为之前已经说明被销毁了 引用也会被销毁
可以这么做
Date& func()
{
static Date d;
return d;
}
拷贝构造和赋值重载的一个区别
特别的:
1.拷贝构造 :一个已经存在的对象,拷贝给另一个要创建初始化的对象
2.赋值重载: 一个已经存在的对象,拷贝赋值给另一个已经存在的对象
==赋值运算符重载成全局函数,注意重载成全局函数时没有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;
}
注意:1.用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝 , 和拷贝构造函数是一样的浅拷贝。
2.和其他默认成员函数一样:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符 重载完成赋值。
3.const成员函数
概念
【概念】:将const修饰的“成员函数”称之为const成员函数,const修饰类成员函数,实际修饰该成员函数隐含的this指针,表明在该成员函数中不能对类的任何成员进行修改
讨论
1.C++中的成员函数隐含的this指针中含有一个const 即: const (类名)* this
2.如果 void Print() const 就是双const 即: const (类名)* const this
3.此时既不能修改其内部的值 也不能修改所指向的地址
4.const默认写在函数声明的右侧
问题:
问题1:const对象 可以调用 非const成员函数吗?
这个当然不可以。若 const对象去调用非const成员函数,会造成【权限放大】的现象,原本在类外const对象的内容是不可以修改的,但是到了函数内部却可以修改了,这是不被允许的
问题2:非const对象 可以调用 const成员函数吗?
这个当然是可以的。非const对象本身就是可读可写的,那在函数内部你要去修改或者不修改都不会有影响(权限缩小)
取地址及const取地址操作符重载
class Date
{
public:
//取地址&重载
Date* operator&()
{
return this;
}
//const取地址&重载
const Date* operator&()const
{
return this;
}
private:
int _year;
int _month;
int _day;
};
当然,如果我们自己不写&重载,编译器也会默认生成
一般不需要我们自己实现
除非不想让别人取到这个类型对象的真实地址
结尾
以下就是我对【C++】类的默认成员函数的理解,如果有不懂和发现问题的小伙伴,请在评论区说出来哦,同时我还会继续更新对C++ 类和对象的理解,请持续关注我哦!!!