C++学习笔记(第11章->使用类)

来源:互联网 发布:windows程序设计如何 编辑:程序博客网 时间:2024/06/02 05:29

本章节首先讲解操作符重载,它允许将标准C++操作符用于类对象;其次介绍友元,这机制使得非成员函数可以访问私有数据;最后是自动类型转换。

1.操作符重载

(1)重载后的操作符必须至少有一个操作数是用户定义的类型,防止用户为标准类型重载操作符。
(2)使用操作符不能违反操作符原来的句法规则,也不能改变操作符的优先级。
(3)不能定义新的操作符。
(4)大多数操作符可以通过成员或非成员函数进行重载,但下面操作符只能通过成员函数进行重载:
A.  =   赋值操作符。
B. ( )   函数调用操作符。
C. [ ]   下标操作符。
D. ->   指针访问类成员操作符。
下面,写个重载造作福的例子语法:
Time operator -  (const Time & t)const;Time operator * (const Time & t)const;

2.友元简介

友元有三种:
(1)友元函数
(2)友元类
(3)友元成员函数
通过让函数成为友元,可以赋予该函数与类成员函数相同的访问权相。
上面例子中,左侧的操作数是调用对象,也就是说:
Time A,B;A = B*2.75;//allowA = 2.75*B;//not allow,because 2.75 not Time 
为了解决这个问题,使用非成员函数。
Time operator*(double m, const Time & t);
但是非成员函数不能访问私有数据,那么必须声明为友元,才可以访问。
friend Time operator*(double m, const Time & t);//定义的时候不需要friend
A.虽然operator * () 函数是在类声明中声明的,但它不是成员函数,因此不能使用成员操作符来调用。
B.虽然operator * ()函数不是成员函数,但它与成员函数访问权限相同。

2.1常用友元:重载<<操作符

(1)第一种版本
使Time类知道使用cout,必须使用友元函数。下面语句:
Time trip;cout<<trip;
使用两个对象,第一个是ostream类对象(cout),一个是Time对象。如果使用成员函数来重载<<操作符,Time对象将是第一个操作数。意味着必须如下:
trip<<cout;
 这将使人迷惑。但通过友元函数,可以像下面这样重载:
void operator<<(ostream & os, const Time & t){    os<<t.hours<<t.minutes;}
(2)第二种版本
前面第一个版本存在问题,不允许输出拼接,而通常应该是可以拼接的。应该重载的时候,把ostream对象返回。
ostream & operator<<(ostream & os, const Time & t){    os<<t.hours<<t.minutes;    return os;}
cout<<trip = operator<<(cout, trip)
所以,一般来说,要重载<<操作符来显示c_name对象,可以使用一个友元函数,定义如下:
ostream & operator<<(ostream & os, const c_name &obj){   os<<...;   return os;}
另外,只有在类声明中的原型中才能使用friend关键字。除非函数定义也是原型,否则 不能在函数定义中使用该关键字。

3.重在操作符:作为成员函数还是非成员函数

对很多操作符来说,可以选择使用成员函数或非成员函数来实现操作符重载。一般来说,非成员函数应是友元函数,这样他才能直接访问类的私有数据。
Time operator+(const Time & t)const;friend Time operator+(const Time & t1, const Time & t2);
对于成员版本来说,一个操作数通过this指针隐式的传递。对于友元版本来书,两个操作数都作为参数来传递。
记住:非成员版本的重载操作符函数所需形参数目与操作符使用的操作数数目相同;而成员版本所需的参数数目少一个,因为其中的一个操作数是被隐式地传递的调用对象。

4.类的自动转换和强制类型转换

4.1自动转换

内置类型:将一个标准类型变量的值赋给另一个标准类型的变量时,如果这两种类型兼容,则C++将这个值转换为接收变量的类型.
long count = 8;//int converse longdouble time = 11;int converted doubleint *p = 10//error,not allowint *p = (int *)10;//allow,p address is 10
可以将类定义成与基本类型或另一个类相关,使得从一种类型转换为另一种类型是有意义的.
#ifndef _STONE_H_#define _STONE_H_class Stone{public:Stone();~Stone();Stone(double lba);Stone(int stn, double lbs);void show_lbs()const;void shoe_stn()const;private:enum{Lbs_per_stn = 14};int stone;double pds_left;double pounds;};#include<iostream>#include"stone.h"using std::cout;Stone::Stone(double lbs){stone = int (lbs) / Lbs_per_stn;pds_left = int (lbs) % Lbs_per_stn + lbs - int(labs);pounds = lbs;}Stone::Stone(int stn, double lbs){stone = stn;pds_left = lbs;pounds = stn * Lbs_per_stn + lbs;}Stone::Stone(){stone = pounds = pds_left = 0;}Stone::~Stone(){}void Stone::show_lbs()const{cout<<pounds<<"pounds\n";}void Stone::shoe_stn()const{cout<<stone<<"stone, "<<pds_left<<"pounds\n";}#endif
C++中,接受一个参数的构造函数为将类型与该参数相同的值转换为类提供了蓝图。因此下面构造函数:
Stone(double lbs);//template for double-to-Stone conversion
用于将double类型的值转换为Stone类型。也就是说,可以这样编写代码:
Stone s;s = 19.6;
程序将使用构造函数Stone(double lbs)来创建一个临时的Stone对象,并将19.6作为初始值。这一过程称为隐式转换,自动进行的。
注意:只有接受一个参数的构造函数才能作为转换函数。
当然,我们可以使用explict关键字来关闭这种自动转换的特性,使之只能只用显示转换。
explict Stone(double lbs);Stone s;s = 19.6;//not allow;s = Stone(19.6);//allows = (Stone)19.6;//allow

4.2强制类型转换

构造函数只用于从某种类型向类类型转换,要进行相反的转换,必须使用特殊的C++操作符函数---转换函数。
转换函数是用户定义的强制类型转换,可以像使用强制类型转换那样使用那他们。
句法如下:
operator typename();//operator int();
typename为要转换的类型,需要通过类对象来调用,从而告知函数要转换的值,因此函数不需要参数。
(1)转换函数必须是类方法;
(2)转换函数不能指定返回的类型;
(3)转换函数不能有参数;
用上面的例子,加多两个成员函数:
operator int()const;operator double()const;Stone::operator int()const{   return int (punds+0.5);}Stone::operator double()const{    return pounds;}
#include<iostream>#include"stone.h"int main(){using std::cout;Stone popins(9, 2.8);double pd = popins;//implict conversioncout<<"convert to double ==>";cout<<"popons:"<<pd<<" pounds";cout<<"conver to int ==>";cout<<"popins: "<<double(popins)<<"pounds.\n";while(1);return 0;}
假设最后一条输出语句,没有转换为double,那么编译器将产生二义性,他不知道是匹配int,还是double.
隐式转换函数也可能存在问题,在你不希望进行转换时,也可能进行了转换:
int ar[20];...Stone temp(14,4);...int Temp = 1;cout<<ar[temp];//used temp instead Temp,
这种情况下并不会报错,但与本意将不符。
所以,应该谨慎的使用隐式转换函数,通常,最好选择尽在被需要显示调用时才会执行的函数。
总而言这,C++为类提供了下面的类型转换:
(1)只有一个参数的类构造函数用于将类型与该参数相同的值转换为类类型。
(2)被称为转换函数的特殊类成员操作符函数,用于将类对象转换为其他类型。
0 0
原创粉丝点击