第十一章——使用类

一、运算符重载
1.C++多态之一,其实*在C语言已经被重载,取地址和乘法。

operator op(list)
operator*()//重载*运算符

2.必须是有效的运算符
3.类中定义重载 operator +()成员函数,则

operator +(){...};
district = sid + sara;//普通调用形式
district = sid.operator+(sara);//编译器转换为:隐式调用sid,显式调用sara

4.(1)返回对象或实际类型,将创建对象或实际类型的副本进行返回。
(2)切记不可返回指向局部变量或临时对象的引用,函数执行完后,变量或对象被释放。
(3)代码

Time Time::sum(const Time &t) const
{
	Time time;
	return time;
}

(4)重载,替换

Time Time::operator+(const Time &t) const//sum替换为operator+即可
district = sid + sara;
district = sid.operator+(sara);//运算符左侧为调用对象,右侧为传参对象。

5.重载限制
(1)重载后的运算符必须至少有一个操作数为用户定义的类型,防止用户为标准类型重载运算符,例如将-重载为+号。
(2)使用运算符时不能违背运算符原来的句法规则。不能将%重载为一个操作数的运算符。
(3)不能修改运算符优先级
(4)不能创建新运算符
(5)部分运算符无法重载
(6)=、[]、()、->运算符只能通过类成员函数进行重载,其他的可重载运算符可通过类成员函数或非类成员函数重载。
(7)尽量遵循一定规则。例如*不要重载为交换,应使用swap()
二、友元
1.友元函数、友元类、友元成员函数
2.对类私有成员的访问,通过公有方法,友元函数等。
3.为类重载二元运算符时,常常需要友元。第一个参数为对象,第二个为传参。

Time Time :: operator *(double n) const
{
}//调用时第一个参数为对象,第二个为传参
A = B * 2.75;
A = B.operator*(2.75);
A = 2.75 * B//编译器不能通过成员函数调用来替换表达式。
//需使用非成员函数
Time operator*(double n, const Time & B);//非成员重载运算符函数
//表达式左侧为第一个参数,右侧为第二个。

4.引入问题,常规的非成员函数不能直接访问类的私有数据。友元函数可访问。
5.创建友元
(1)将其声明放在类的原型声明中,并添加关键字friend,只有类声明可以决定友元。

friend Time operator*(double n, const Time & B);

(2)非成员函数,不可通过成员运算符调用
(3)与成员函数的权限相同
(4)定义,定义中不需要添加friend,不添加Time::限定符
(5)也可以实现为:

Time operator*(double n, const Time & B)
{
	//为类重载操作符,将非类参数作为第一个操作数,可以用友元函数反转操作数
	return B * n;//调用类成员函数实现
}

6.重载<<运算符
(1)版本一:使cout直接显示类,替换原来的show函数。
必须使用友元函数。使用Time成员函数来重载<<,对象需作为第一个操作数,意味着

cout << trip;	//被转换为如下形式
trip << cout;

使用友元函数

void operator<< (ostream & os, const Time & t)
{
	os << t.hours << "hours" << t.minutes << "minutes" << endl;
}

通常情况下,os引用cout对象,也有情况下引用cerr对象。输出错误信息。
(2)版本二:连续输出情况下

cout << x << y;
(cout << x) << y;	//括号中为cout对象

因此重载代码修改为需返回一个cout对象

ostream & operator<< (ostream & os, const Time & t)
{
	os << t.hours << "hours" << t.minutes << "minutes" << endl;
	return os;
}

注意,类继承属性,可让os指向ostream或其子类ofstream,从而将内容输出到文件

ofstream fout;
fout.open("test.txt");
Time trip(12, 40);
fout << trip;
//最后一条语句被转换为	operator<< (fout, trip);

7.运算符重载作为成员函数,与作为非成员函数
成员函数

Time operator+ (const Time &t) const;

非成员函数

friend Time operator+ (const Time &t1, const Time &t2);

加法运算符需要两个操作数,成员函数隐式1个显式1个,非成员函数,显式2个。
两种声明仅可取一种,防止二义性。
8.矢量类重载
(1)类赋值,可采用set接口进行封装,也可采用构造函数,前者更遵循面向对象的设计,后者需创建临时对象。

slove.set(400,300);	//set接口
solve = Vector(400,300);	//构造函数创建临时对象

(2)整数不可隐式转换为枚举类型

enum IDR_CODE_TYPE
{
	IDR_CODE_DISABLE = 0,       /**<  去使能所有码制  */
	IDR_CODE_ENABLE,            /**<  存在任意码制使能  */
};
IDR_CODE_TYPE mode = 1;	//报错,编译器不允许整数隐式类型转换为枚举
IDR_CODE_TYPE mode = (IDR_CODE_TYPE mode)1;	//C++通过。
enum IDR_CODE_TYPE mode = (enum IDR_CODE_TYPE mode)1;	//C通过,不可省略enum关键字

(3)对已重载的运算符进行重载
例如 “-”,可根据特征标,对一元操作进行类相减进行重载。也可对取反进行重载。
(4)实现说明,可采用增加存储数据的方法,便于查找。也可采用类型转换方法,便于修改和维护。
(5)rand和srand

rand();	//相当于调用srand(1)1次。
srand(time(0));	//time()接收time_t变量的地址,将时间放置该变量中并返回。将0用作地址参数,省略time_t变量的声明。ctime包含了time()的原型。

三、类的自动类型转换和强制类型转换
1、类的特定类型常量
(1)方法1,enum class
(2)方法2,static const int stn = 14;静态类型
2、接收1个参数的构造函数,可将类型与该参数相同的值,转换为类。

Stonewt (double lbs);
Stonewt myCat;
myCat = 19.6;	//隐式转换,采用上述构造函数构造临时对象,并赋值

3、

Stonewt (int stn, double lbs);	//两个参数的构造函数,不可隐式转换
Stonewt (int stn, double lbs = 0);	//第二个参数默认值,可进行隐式转换

4、关闭隐式转换

explicit Stonewt (double lbs);	//关闭隐式转换

5、显式转换

explicit Stonewt (double lbs);
Stonewt myCat;
myCat = (Stonewt)19.6;
myCat = Stonewt(19.6);

6、隐式转换——Stonewt << double
(1)对象与值类型互相赋值时
(2)值类型作为传参,传递给接收类类型的函数
(3)返回值被声明为类类型(Stonewt)的函数,在试图返回值类型(double)时
(4)上述情况下,使用可转换为double类型的内置类型时
最后一点,为int转double,再转为Stonewt
7、转换函数——double << Stonewt
(1)转换函数必须是类方法
(2)转换函数不能指定返回类型
(3)转换函数不能有参数

operator typeName()
operator double()

8、二义性

Stonewt poppins(9, 2.8);
//类声明中有如下函数原型
operator int();
operator double();
cout << poppins <<endl;	//产生二义性,不确定输出为int还是double
long gones = poppins;	//二义性,不确定用哪个

9、采用显式强制类型转换消除二义性

long gones = (int)poppins;
long gones = double(poppins);

10、C++98中关键字 explicit不可用于转换函数,C++11可以

explicit operator int() const;
explicit operator double() const;

11、总结
(1)只有一个参数的构造函数,用于将类型与该参数相同的值,转换为类类型。可用explicit作用于构造函数,使其仅可用于显式类型转换。
(2)转换函数,特殊类成员运算符函数,用于将类类型转换为其他类型。
转换函数无参数,无返回类型,类成员,名为operator typeName()。
12、转换函数和友元函数
重载加法
成员函数:

Stonewt Stonewt::operator+ (const Stonewt &st) const
{
	double pds = pounds + st.pounds;
	Stonewt sum(pounds);
	return sum;
}

友元函数

Stonewt operator+ (const Stonewt &st1, const Stonewt &st2)
{
	double pds = st1.pounds + st2.pounds;
	Stonewt sum(pounds);
	return sum;
}

实际应用

Stonewt a1(9,12);
Stonewt a2(12,8);
Stonewt a3;
a3 = a1 + a2;	//成员函数:a1.operator+(a2); 或 友元函数: operator+ (a1, a2);

提供Stonewt (double)构造函数

Stonewt b1(9,12);
double b2 = 12.8;
Stonewt b3;
b3 = b1 + b2;	//成员函数:b1.operator+(b2); 或 友元函数: operator+ (b1, b2);
//b2为double类型,将调用构造函数隐式转换为Stonewt类型
//此时若定义了operator double()转换函数,将造成混乱,会将b1转换为double,并执行double加法

仅友元函数可进行如下操作

Stonewt c1(9,12);
double c2 = 12.8;
Stonewt c3;
c3 = c2 + c1;	//友元函数: operator+ (c1, c2)
//Stonewt(double)将double类型的c2转换为Stonewt
//不可调用成员函数,c2为double类型

加法的实现总结,两种方法:
(1)友元函数+类型构造函数。
优:代码少,出错少。缺:每次调用都调用构造函数,时间内存开销大。
(2)加法重载为显式使用double类型函数的参数。
优:运行快。缺:代码量大。

Stonewt Stonewt::operator+ (double x);
Stonewt operator+ (double x, Stonewt &st);
b3 = b1 + b2;	//调用成员函数
c3 = c2 + c1;	//调用友元函数
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值