C++ Primer Plus 第十一章

本文详细介绍了C++中的操作符重载规则及其限制条件,包括必须至少有一个操作数是用户定义的类型、不能违反原有语法、不能改变优先级等。此外,还探讨了如何通过友元函数来解决非成员函数重载操作符访问类私有成员的问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//操作符重载
只能重载现有的操作符
操作符重载其实一种函数替换:如
district2 = sid + sara;
district2 = sid.operator()+(sara);     //隐式转换

ex:
mytime.h
class Time
{
private:
     ...
public:
     Time operator+(const Time &t) const;
     Time operator-(const Time &t) const;
     Time operator*(double n) const;
};
mytime.cpp
Time Time::operator+(const Time &t) const
{
     ...
     return time;          //直接return变量会在返回创建其拷贝,所以没有问题(但是应该注意浅拷贝问题),返回局部变量的引用或指针就会有问题
}
于是:
time t,t1,t2;
可以用下列方式调用
t = t1 + 2; <-----> t = t1.operator+(t2);

//重载限制
1 重载后的操作符必须至少有一个操作数是用户定义的类型,这将防止用户为标准类型重载操作符。(例如,不能将减法操作符重载为两个double值的和)
2 重载后的操作符不能违反操作符原来的句法规则,例如,不能将求模操作符% 重载成使用一个操作数(原来的求模操作符需要两个操作数)
3 重载后的操作符优先级不变
4 不能定义新的操作符
5 不能重载下面的操作符
     sizeof()
     .
     .*
     ::
     ?:
     typeid     RTTI操作符
     const_cast
     dynamic_cast
     reinterpert_cast
     static_cast
6 操作符重载可以通过成员函数(类函数)或普通函数重载,但下面的操作符只能通过成员函数重载
     =     赋值操作符
     ()     函数调用操作符
     []  下标操作符
     ->  通过指针访问类成员的操作符

//友元
友元有三种:
1 友元函数
2 友元类
3 友元成员函数
通过让函数成为类的友元,可以赋予该函数与类成员函数相同的访问权限

友元的用处
Time A,B
A = B*2.5;          //因为重载了 *所以,A=B*2.5 --> A.operator*(2.5)
A = 2.5*B;          //编译器无法重载
但是,通过编写普通函数重载--> Time operator*(double m, const Time &t)
A = 2.5*B          //A = 2.5*B --> operator*(2.5, B),但是,这样无法获取Time的私有成员(用友元解决)

加入友元函数
class Time
{
     ...
     friend Time operator*(double m, const Time &t);
     ...
};
友元函数不是Time类的成员函数,所以不加 Time:: 域名限定符
Time operator*(double m, const Time &t)
{
     ....
}

常用的友元:重载<<操作符,注意返回ostream以便实现 os << A << B 的效果
ostream& operator<< (ostream &os, const Time &t)
{
     ...
     return os;
}

NOTE:friend关键字在类成员函数的定义中使用
NOTE:如果你同时定义了相同调用格式的 类成员函数与非类成员函数,会导致编译错误

//类的自动转换盒强制转换
C++不自动转换不兼容类型
int *p = 10;     //type clash wrong!
int *p = (int *) 10 //right

自动转换构造函数
Stonewt(double lbs);
Stonewt myCat;
myCate = 19.6;     //将会自动调用Stonewt(double lbs)创建一个对象,并将其内容复制到myCat中
等价的
Stonewet myCat = 260; <---> Stonewet myCat(260); <---> Stonewet myCat = Stonewt(260);
explicit Stonewt(double lbs);     //关闭这种自动特性的隐式转换,不过仍可使用显式转换,如下:
myCate = (Stonewt)19.6;     //显式转换

隐式转换发生在如下场景:
1 将Stonewet初始化为double值时
2 将double值复制给Stonewet对象时
3 将double值传值给接受Stonewet参数的函数时
4 返回值声明为一个Stonewet的函数,返回一个都变了时

还可以进行如下转换:
Stonewet Jumbo;
JumBo = 7300;     //将7300的int型转换为double型,注意如果还有构造函数Stonewet Jumbo(long) 则因为int既可以转换为long,也可转换为double,因此调用存在歧义,编译错

//转换函数
使用转换函数将类类型转换为元类型(int ,double...)
转换函数如下声明
operator typeName();
StoneWet
{
     operator int();      // 替换为nt Stone_to_Int更安全;
}
StoneWet::operator int();
{
     return int (pounds + 0.5);
}
要注意以下几点:
1 转换函数必须是类方法
2 转换函数不能指定转换类型 //即连void都没有,但是却可以返回参数
3 转换函数不能有参数

//转换函数的缺点!如:
int ar[20];
...
Stonewet temp(14,4);
...
int Temp = 1;
...
cout << ar[tmep] << endl;     //这里的类类型temp将会转换为int值,编译器不会报错

转换总结:
1 只有一个参数的类构造函数会转换,可以用explicit防止隐式转换
2 operator int();可以将类类型转换为int型

两种转换函数可能会混乱!
total = stoenwet1 + stonewet2;    
可能的转换
1. stoenwet1.operator+(stonewet2);    
2. operator+(stoenwet1, stonewet2);    
3. 转换成double加法     //因为Stonewet有double构造函数,且定义了operator double()
//1,2会编译错;1,3 2,3则会混乱 vs会选择1,2
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值