设为首页 加入收藏

TOP

C++ Primer Plus的若干收获--(十)(一)
2015-07-20 18:02:03 来源: 作者: 【 】 浏览:4
Tags:Primer Plus 若干 收获

明天就要回学校了,本来回家之前是有一片宏图伟志的,无奈只能抱着这可怜的十篇博客回学校了。自己马上就要大三,大学的下一半马上就要开始了,我的未来还有什么在等待着我呢,好期待!!!

10.1 友元

我们知道C++控制对类对象私有部分的访问。通常,公有类方法是唯一的途径,但是除此之外C++还提供了另外一种机制:友元。友元有三种友元函数,友元类与友元成员函数。在介绍如何成为友元前,先介绍一下为何需要友元。在为类重载二元运算符是常常需要友元。将之前的Time对象乘以实数就是这种情况。

我们之前重载了+
Time A,B;
A=B*2.75;//由上篇我们知道这是可行的

B=2.75*A;

但是,下面这行的的代码是不对的。我们知道,遇到重载的操作符时,左侧的操作数是调用对象,但是2.75不是对象,因此编译器不能通过使用成员函数调用来替换该表达式。解决这个问题的方式就是使用非成员函数。非成员函数不是对象调用的,它使用的所有值都是显式参数。这样我们只要定义了如下的函数即可

Time operator*(double m,const Time& t);


但是这样使用又会引发新的问题:非成员函数不能直接访问类的私有数据,至少常规非成员函数不能访问。这时,我们就需要友元函数了。

10.2 创建友元

创建友元函数的第一步是将其原型放在类的声明中,并在之前加上friend关键字

friend Time operator*(double m,const Time& t);


该原型意味着两点:

虽然operator*()函数式在类声明中声明的,但它不是成员函数,不能用成员运算符来调用;虽然operator*()函数不是成员函数,但是它的访问权限与成员函数相同。

完整的函数定义则不再需要friend。再有了定义和声明之后下面的语句就可以实现了

A=2.75*B;


10.3 重载<<运算符

(1)<<重载的第一个版本

要使Time类知道使用cout,必须使用友元函数。因为下面这样的语句使用两个对象,其中第一个是ostream类对象

cout<
  

   

但是如果使用Time成员函数的方法来重载,Time对象将是第一个操作数,而有这样的代码

trip<
    

     

因此我们需要友元来重载这样的运算符

void operator<<(ostream& os,const Time & t)
{
  os<
      

       


(2)<<的第二个重载版本

之前的版本解决了cout<

cout<<"Trip time:"<
        

         

之所以不能这样做我们要先了解cout的一点知识。

cout<
          

           


正如iostream定义的那样,<<运算符要求左边第一个是ostream对象。显然表达式cout<

ostream& operator<<(ostream& os,const Time &t)
{
  os<
            

             


10.4 改进后的Time类

ifndef MYTH0_H_
#definr MYTH0_H_

class Time
{
private:
    int hours;
    int minutes;
public:
    Time();
    Time(int h,int m=0);
    void AddMin(int m);
    void AddHr(int h);
    void Reset(int h=0,int m=0);
    Time operator+(const Time& t) const;
    Time operator-(const Time& t) const;
    Time operator*(const Time &t) const;
    friend Time operator*(double m,const Time & t) {return t*m;}
    friend std::ostream& operator<<(std::ostream& os,const Time &t);

    void show() const;
};
#endif // MYTH0_H_

10.5 类型转换

在讨论类的类型转换之前,我们先来复习C++时如何处理内置的类型转换的。

longble count=8;
double time=11;
int side=3.33;


上述的赋值代码均是可行的,因为在C++看来,各种数值类型都表示相同的东西――一个数字,同时c++包含用于转换的内置规则。但是C++不会自动转换不兼容的类型。

int *p=10;//invalid


为了更好地说明C++的有关类的转换机制,我们先看下如下的类

ifndef STONEWT_H
using std::cout;
#define STONEWT_H


class Stonewt
{
    public:
        Stonewt(double lbs,int stn);
        {
            stone=stn;
            pds_left=lbs;
            pounds=stn*Lbs_per_stn;
        }
        
        Stonewt(double lbs)
        {
            stone=int(lbs)/Lbs_per_stn;//integer divition
            pds_left=int(lbs)%Lbs_per_stn+lbs-int(lbs);
            pounds=lbs;
        }
        
        stonewt() {stone=pounds=pds_left=0;};
        virtual ~Stonewt() {};
        void show_lbs() const {cout<
              

               


有了这个类,我们在看一下如下的代码

Stonewt myCat;
myCat=19.6;//use Stonewt(double) to convert 19.6 to Stonewt

程序将使用构造函数Stone(double)来创建一个临时的Stonewt对象,并将19.6作为一个初始化值。随后,采用逐成员赋值方式来将该对象的内容复制到myCat对象中。这一过程称为隐式转换。只有接受一个参数的构造函数才能称为转换函数。下面的构造函数就不行

Stonewt(double lbs,int stn);
       

但是,如果第二个参数提供默认值就可以

Stonewt(double lbs=0,int stn);//int-to-Stonewt conversion       

将构造函数用作自动类型转换似乎是一项不错的特性,但是随着C++的深入,我们也会发现其带来的问题。因为这会导致意外的类型转换。因此,C++提供了关键字explicit用于关闭这种自动的特性。

explicit Stonewt(double lbs);

Stonewt=myCat;
myCat=19.6;//not valid
myCat=Stonewt(19.6);//ok,an explicit convertion
myCat=(Stonewt)19.6;//ok,old form for type cast
        

那么编译器在什么时候将使用Stonewt(double)函数呢?如果在声明中使用了关键字explicit,则其将仅仅用于显示的类型转换,否则还可以使用如下的隐式转换:

将Stonewt对象初始化为double值时。 将double值赋给Stonewt参数的函数时。 将double值传递给接受Stonewt参数的函数时。 返回值被声明为stonewt的函数试图返回double值时。 在上述任一种情况下,使用可转换为double类型的内置类型。

最后一句的意思也就是说这种情况。函数原型化提供的参数匹配过程,允许使用Stonewt(double)构造函数来转换其他的数值类型。

Stonewt Jumbo(7000);
Jumbo=7300;//uses Stonewt(double),converting int to double


类这部分比较多,而且不太好总结。估计进度会比较慢,要用比较多的笔墨来写了。不过没关系,我还是挺喜欢这块的。下篇仍然会接

首页 上一页 1 2 下一页 尾页 1/2/2
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇HDU 1789 Doing Homework again 下一篇HDUJ 1114 Piggy-Bank

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: