C++ Primer Plus 学习之 使用类

加油鸭


运算符重载

运算符重载可以分为成员函数重载和非成员函数重载,由于成员函数重载存在一定缺陷,可以用友元声明非成员函数重载。

  • 例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    //mytime0.h
    #ifndef MYTIME0_H_INCLUDED
    #define MYTIME0_H_INCLUDED
    class Time
    {
    private:
    int hours;
    int minutes;
    public:
    Time(){hours=minutes=0;}
    Time(int h,int m=0){hours=h+m/60;minutes=m%60;}
    void show()const{std::cout<<hours<<" hours, "<<minutes<<" minutes\n";}
    //operator
    Time operator+(const Time &t)const//返回类型不要使用引用
    {
    Time sum;
    sum.minutes=minutes+t.minutes;
    sum.hours=hours+t.hours;
    sum.hours=sum.hours+sum.minutes/60;
    sum.minutes%=60;
    return sum;
    }
    Time operator*(const int &v)const//另一种重载方式,非同类型重载
    {
    return Time(hours*v,minutes*v);
    }
    };
    #endif // MYTIME0_H_INCLUDED
    //main.cpp
    #include<bits/stdc++.h>
    #include"mytime0.h"
    using namespace std;
    int main()
    {
    Time thetime=Time(12,15);
    thetime.show();
    Time lxttime=Time(11,5);
    thetime=thetime+lxttime;
    thetime.show();
    }
  • 重载限制

    • 重载后的运算符必须至少一个操作数是用户定义的类型.
    • 使用运算符重载不能违反运算符原来的句法规则 : 操作数的个数 和 优先级
    • 不能创建新运算符
    • 有些运算符不能重载
    • 有些运算符只能通过成员函数重载 ,而不能通过非成员函数重载.
  • 在运算符表示法中,运算符左侧的对象是调用对象,运算符右边的对象最作为参数被传递的对象。

友元函数

  • 友元函数访问权限和成员函数相同。
  • 重载语法问题
    1
    2
    thetime=thetime*2;//allowed
    thetime=2*thetime;//not allowed

解决办法: 我们只能使用非成员函数解决改问题,但常规非成员函数不能访问私有成员,只有一类特殊的非成员函数可以访问类的私有成员-友元函数。

  • 友元函数声明
    • 原型放在类中,但不是类成员函数,不用使用::
    • 前加friend,定义不用加,可访问类的私有成员。
      1
      friend Time operator*(double m,const Time &t);
  • 友元函数定义

    • 不用加friend
    • 不用加 类名::
  • 常见的友元函数

    1
    2
    3
    4
    5
    ostream & operator<<(ostream & os,const c_name &obj)
    {
    os << ...;
    return os;
    }
  • 改进后的Time类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    #ifndef MYTIME0_H_INCLUDED
    #define MYTIME0_H_INCLUDED
    #include<iostream>
    class Time
    {
    private:
    int hours;
    int minutes;
    public:
    Time(){hours=minutes=0;}
    Time(int h,int m=0){hours=h+m/60;minutes=m%60;}
    void show()const{std::cout<<hours<<" hours, "<<minutes<<" minutes\n";}

    //operator
    Time operator+(const Time &t)const//返回类型不要使用引用
    {
    Time sum;
    sum.minutes=minutes+t.minutes;
    sum.hours=hours+t.hours;
    sum.hours=sum.hours+sum.minutes/60;
    sum.minutes%=60;
    return sum;
    }
    Time operator*(const int &v)const//另一种重载方式,非同类型重载
    {
    return Time(hours*v,minutes*v);
    }
    friend Time operator*(int v,const Time &t)
    {
    return t*v;
    }
    friend std::ostream &operator<<(std::ostream &os,const Time &t)
    {
    os<<t.hours<<" hours, "<<t.minutes<<" minutes\n";
    return os;
    }
    };
    #endif // MYTIME0_H_INCLUDED
    //main.cpp
    #include<bits/stdc++.h>
    #include"mytime0.h"
    using namespace std;
    int main()
    {
    Time thetime=Time(12,15);
    thetime=2*thetime;//allowed
    cout<<thetime<<endl;
    return 0;
    }

类的转换


其他类型转换成类

  • 只含有一个参数的构造函数可以作为转换函数,进行自动(隐式转换)。
  • 构造时应避免二义性。

    1
    2
    3
    Time(int h);//构造函数
    Time mytime;
    mytime=16;
  • explicit关键字: 有时候不需要这种自动特性,声明时使用该关键字即可。

    1
    2
    3
    4
    explicit Time(int h)
    Time mytime=16;//not allowed
    mytime=Time(16);//allowed
    mytime=(Time)16;//allowed

类转换成其他类型

  • 应避免二义性。
  • 有时候会出现错误,故在声明转换函数时加上explicit,并使用显式转换。
  • 或者另外声明一个成员函数来进行类型转换。
  • 声明

    1
    explicit operator int() const
  • 定义

    1
    2
    3
    4
    Time::explicit operator int()const
    {
    return hours;
    }