之前我们学过const的用法,当其修饰一个变量时,变量的值不能再发生改变,当其修饰指针时,分两种情况,放在*前面的,指向的值不再发生改变,*后面指向不再发生改变,现在我们再来学习下引用相关的内容。
权限的缩小:
int main()
{
int a = 10;
//权限的缩小是可以的
const auto& b = a;
return 0;
}
权限的放大是不行的
权限的保持:
int main()
{
const int& a = 10;
//此时,
const int& b = a + 10;
return 0;
}
总结:
const修饰时,权限只能维持不变或者减小,绝对不能增大
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其
返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
例如:
//operator运算符 做函数名
bool operator==(const Date& x, const Date& y)
{
return x._year == y._year
&& x._month == y._month
&& x._day == y._day;
}
我们可以利用上面函数来做如下测试:
class Date
{
public:
Date(int year, int month, int day)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
/*bool operator==(const Date& x, const Date& y)
{
}*/
//private:
int _year;
int _month;
int _day;
};
//operator运算符 做函数名
bool operator==(const Date& x, const Date& y)
{
return x._year == y._year
&& x._month == y._month
&& x._day == y._day;
}
int main()
{
Date s1(2024, 1, 29);
Date s2(2024, 2, 30);
cout << (s1 == s2) << endl;
return 0;
}
结果:
上面的内容足以让我们走进这扇大门:
运算符重载写法为:
类型+operator+运算符符号+形参
如果你足够细心,就会发现我们的函数是写在外面的,导致我们private被迫去除,否者我们无法访问到成员变量,所以正确的写法为:放在类中。
class Date
{
public:
Date(int year, int month, int day)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
bool operator==(const Date& y)
{
return this->_year == y._year
&& this->_month == y._month
&& this->_day == y._day;
}
private:
int _year;
int _month;
int _day;
};
要注意的是放在类内部,我们的形参要减少一个,原因是this指针指向第一个参数
关于赋值运算符重载注意事项:
不能通过连接其他符号来创建新的操作符:比如operator@
重载操作符必须有一个类类型参数
用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐
藏的this
.* :: sizeof ?: . 注意以上5个运算符不能重载。这个经常在笔试选择题中出现
第一个是( .* ),别看成了(*---可以重载的)
再写一个大家可以再看看是否掌握:
bool operator<(const Date& y)
{
if (this->_year < y._year)
return true;
else if(this->_year==y._year)
{
if (this->_month < y._month)
return true;
else if (this->_month == y._month)
{
if (this->_day < y._day)
return true;
}
}
return false;
}
现在关于如何定义我们是会了,那么该如何调用呢?
我们通过代码引入:
int main()
{
Date s1(2024, 1, 29);
Date s2(2024, 2, 30);
//常见的三种写法:
//第一种:正常的函数调用即可,只适合于我们写在了类外面的情况
cout << (operator==(s1, s2)) << endl;
//第二种写法:调用类成员函数写法
cout << s1.operator<(s2) << endl;
//第三种写法:我们可以直接简写要比较的函数即可,IDE会自动识别帮我们调用
//但是要注意的是:<<的运算符级别较高,通常需要加()
cout << (s1 == s2) << endl;//等价为:operator==(s1,s2)/s1.operator(s2)
cout << (s1 < s2) << endl;
return 0;
}
所以大体上赋值运算符重载格式如下:
参数类型:const T&,传递引用可以提高传参效率
返回值类型:T&,返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值
检测是否自己给自己赋值
返回*this :要复合连续赋值的含义
Date& operator=(const Date& y)
{
if (this != &y)//检查是否为自己给自己赋值情况
{
this->_year = y._year;
this->_month = y._month;
this->_day = y._day;
}
return *this;
}
这个就是六大默认成员函数之一的赋值重载函数
要注意的是:
赋值运算符只能重载成类的成员函数不能重载成全局函数
用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝。注
意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符
重载完成赋值
该默认函数和拷贝构造规律大体相似,分为浅拷贝和深拷贝
关于我们是否需要自己实现,如果类中未涉及到资源管理,赋值运算符是否实现都可以;一旦涉及到资源管理则必须要实现
下面我们对两者进行区分:
class Date
{
public:
Date(int year, int month, int day)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
Date(const Date& y)
{
cout << "是拷贝构造" << endl;
}
Date& operator=(const Date& y)
{
if (this != &y)//检查是否为自己给自己赋值情况
{
this->_year = y._year;
this->_month = y._month;
this->_day = y._day;
}
return *this;
private:
int _year;
int _month;
int _day;
};
int main()
{
Date s1(2024, 1, 31);
Date s2(s1);
return 0;
}
现在我们的s2如果是调用拷贝构造会显示“是调用拷贝构造”这几个字,如果是调用赋值重载,就什么都不会显示,那么你觉得结果是什么呢?
说明我们这种写法确实是在调用拷贝构造,那么怎么调用赋值重载呢?两者有什么区别呢?
int main()
{
Date s1(2024, 1, 31);
//Date s2(s1);
Date s2;
//调用的两种方法:
// 1.直接赋值调用
s2 = s1;
//成员函数调用法
s2.operator=(s1);
s1.print();
s2.print();
return 0;
}
上面就是对于复制重载的调用方法
关于问题二:
相信大家现在对比两者代码也会发现,在拷贝构造函数中我们是直接对一个创建的变量做初始化,而在复制重载里面我们是对一个已存在的变量做赋值处理
所以区别为:
拷贝构造,同类型一个存在的对象进行初始化要创建的对象
复制重载,已经存在的对象,一个拷贝赋值给另一个已存在的变量
赋值我们的规则是可以连续赋值的,那么我们的函数该如何实现连续赋值呢?
其实该函数就可以处理连续赋值问题,例如:s1=s2=s3,计算机会先将s3的值赋值给s2,在将s2的值赋值给s1,从而达到连续赋值效果
关于复制重载,我们还有两个特例:
--和++,大家都知道我们通常讲该两者分为前置和后置,那么我们如何实现不同的复制重载效果呢?
C++规定:后置++重载时多增加一个int类型的参数,但调用函数时该参数不用传递,编译器
自动传递
class Date
{
public:
Date(int year=2024, int month=1, int day=29)
{
this->_year = year;
this->_month = month;
this->_day = day;
}
//前置++
Date& operator++()
{
this->_day++;
//……后序处理我们先不写
return *this;
}
//后置++
Date operator++(int)
{
Date tmp;
tmp = *this;
//Date tmp(*this);
this->_day++;
return tmp;
}
private:
int _year;
int _month;
int _day;
};
--同理,大家可以自行去实现!
最后,感谢大家的支持!