c++学习笔记—使用类

运算符重载

运算符重载是一种形式的c++多态。运算符重载将重载的概念扩展到运算符上,允许c++运算符有多重含义。实际上,在c++中已经有运算符被重载,例如*运算符用于地址,将得到存储在这个地址上的值,当将他用于俩个数组时,得到就是它们的乘积。

c++允许将运算符重载扩展到用户定义的类型,例如,允许使用+将两个对象相加,编译器将根据操作数的数目和类型决定使用那种加法定义。重载运算符可以使代码看上去更加自然.

例如,一般将两个数组相加,在前面的做法是使用for循环,代码如下:

for (int i = 0; i < 20; i++)
    evening[i] = sam[i] + janet[i];

现在我们可以定义一个表示数组的类,并重载+运算符。就可以像下面这样直接将数组相加

evening = sam + janet;

注释:上面这行代码我们省略了具体实现细节, 主要是明确这个也是OOP的其中一个目标。

要重载运算符,需要使用运算符函数,这种函数格式较为特殊,格式如下:

operatorop(argument-list)

格式就是operator+op+(),其中op就是要重载的运算符,op必须是有效的c++运算符,不能虚构一个新的符号,例如operate@()就是错的,因为c++中没有@运算符。又如,operate[ ]()函数将重载[ ]运算符,其中[ ]运算符是数组索引运算符。

运算符重载实例:

示例:计算时间(将两个时间按分钟和小时相加,重载+运算符)

首先,头文件如下:

// mytime0.h -- Time class before operator overloading
#ifndef MYTIME0_H_
#define MYTIME0_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);   //重置时间
    const Time Sum(const Time & t) const;  ///将时间相加
    void Show() const;
};
#endif

实现细节:

// mytime0.cpp  -- implementing Time methods
#include <iostream>
#include "mytime0.h"

Time::Time()
{
    hours = minutes = 0;
}

Time::Time(int h, int m )
{
    hours = h;
    minutes = m;
}

void Time::AddMin(int m)
{
    minutes += m;
    hours += minutes / 60;
    minutes %= 60;
}

void Time::AddHr(int h)
{
    hours += h;
}

void Time::Reset(int h, int m)
{
    hours = h;
    minutes = m;
}

const Time Time::Sum(const Time & t) const
{
    Time sum;
    sum.minutes = minutes + t.minutes;
    sum.hours = hours + t.hours + sum.minutes / 60;
    sum.minutes %= 60;
    return sum;
}

void Time::Show() const
{
    std::cout << hours << " hours, " << minutes << " minutes";
}

重点来看下Sum()函数的代码,其中参数是引用,但是返回值不是引用,将参数声明为引用的目的是为了提高效率,此时若使用安置传递Time对象也可,但是传递引用,速度更快,使用的内存更少。

但是这里的返回值不能是引用,因为函数将创建一个新的Time对象(也就是sum)来表示另外两个Time对象的和。返回对象将创建文件的副本,而调用函数可以使用它。然而,如果返回类型时引用(Time &),则引用的将是sum对象。但是sum对象是局部变量,在函数结束时将被删除,因此引用将指向一个不存在的对象。使用返回类型Time意味着程序将在删除sum之前构造它的拷贝,调用函数将得到该拷贝。

警告不要返回指向局部变量或者临时对象的引用。函数执行完毕后,局部变量和临时对象将消失,引用指向不存在的数据。

对上面定义的类测试

// usetime0.cpp -- using the first draft of the Time class
// compile usetime0.cpp and mytime0.cpp together
#include <iostream>
#include "mytime0.h"

int main()
{
    using std::cout;
    using std::endl;
    Time planning;                      //使用默认构造函数创建对象planning
    Time coding(2, 40);               
    Time fixing(5, 55);
    Time total;

    cout << "planning time = ";
    planning.Show();
    cout << endl;

    cout << "coding time = ";
    coding.Show();
    cout << endl;

    cout << "fixing time = ";
    fixing.Show();
    cout << endl;

    total = coding.Sum(fixing);         //调用函数的对象是coding,显式地调用了fixing
    cout << "coding.Sum(fixing) = ";
    total.Show();
    cout << endl;
    // std::cin.get();
    return 0;
}

输出结果是:

planning time = 0 hours, 0 minutes
coding time = 2 hours, 40 minutes
fixing time = 5 hours, 55 minutes
coding.Sum(fixing) = 8 hours, 35 minutes

改进上面的类,添加加法运算符

首先头文件:

// mytime1.h -- Time class before operator overloading
#ifndef MYTIME1_H_
#define MYTIME1_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;
    void Show() const;
};
#endif

将sum()函数的名称改成operator+()就可以重载加法运算符。此时函数名就是operator+,也是由Time对象调用。

Time Time::operator+(const Time & t) const
{
    Time sum;
    sum.minutes = minutes + t.minutes;
    sum.hours = hours + t.hours + sum.minutes / 60;
    sum.minutes %= 60;
    return sum;
}

和sum()一样,operator+()也是由Time对象调用的,它将第二个Time对象作为参数,并返回一个Time对象。所以,可以像调用Sum()那样来调用operator+()方法。就像下面这样:

total = coding.operator+(fixing);

重载+运算符之后也可以像是使用运算表示法:

total = coding + fixing;

usetime1.cpp

// usetime1.cpp -- using the second draft of the Time class
// compile usetime1.cpp and mytime1.cpp together
#include <iostream>
#include "mytime1.h"

int main()
{
    using std::cout;
    using std::endl;
    Time planning;
    Time coding(2, 40);
    Time fixing(5, 55);
    Time total;

    cout << "planning time = ";
    planning.Show();
    cout << endl;
 
    cout << "coding time = ";
    coding.Show();
    cout << endl;
    
    cout << "fixing time = ";
    fixing.Show();
    cout << endl;

    total = coding + fixing;
    // operator notation
    cout << "coding + fixing = ";
    total.Show();
    cout << endl;

    Time morefixing(3, 28);
    cout << "more fixing time = ";
    morefixing.Show();
    cout << endl;
    total = morefixing.operator+(total);
    // function notation
    cout << "morefixing.operator+(total) = ";
    total.Show();
    cout << endl;
    // std::cin.get();
    return 0;
}

程序输出结果如下:

planning time = 0 hours, 0 minutes
coding time = 2 hours, 40 minutes
fixing time = 5 hours, 55 minutes
coding + fixing = 8 hours, 35 minutes
more fixing time = 3 hours, 28 minutes
morefixing.operator+(total) = 12 hours, 3 minutes

现在,operator+()函数可以使得可以使用函数表示法或者运算符来调用它,编译器将根据操作数的类型来确定+的含义,例如:t1、t2、t3和t4都是Time类型的对象,就可以想下面这样直接想加:

t4 = t1 + t2 + t3;

上面的语句的含义是:由于+是从左到右的运算符,所以语句首先会被转换成下面这样:

t4 = t1.operator+(t2 + t3);

进而转化成下面这样:

t4 = t1.operator+(t1.operator+(t3));

 重载限制:

运算符可以重载的条件是

(1)必须有一个操作数是用户定义的类型。目的是为了防止用户为标准类型重载运算符。例如,你不能将减法运算符重载为计算两个double值的和。

(2)使用运算符不能违反运算符原来的句法规则。例如不可以将求模运算符(%)重载成使用一个操作数;

(3)不能修改运算符的优先级。

(4)不能创建新运算符,例如operator**()函数来表示求幂。

(5)不能重载以下的运算符:

下面表中的所有的运算符都可以被重载:

 

表11.1中的大部分运=运算符都可以通过成员函数或者非成员函数进行重载。

但下面的所列出的符号只能通过成员函数进行重载:

其他重载运算符

在上面的类中重载-和重载*:

(1)首先将相应的函数原型添加到头文件中:

Time operator-(const Time & t) const;

Time operator*(const Time & t) const;

在相应的实现文件中添加:

Time Time::operator-(const Time & t) const
{
    Time diff;
    int tot1, tot2;
    tot1 = t.minutes + 60 * t.hours;
    tot2 = minutes + 60 * hours;
    diff.minutes = (tot2 - tot1) % 60;
    diff.hours = (tot2 - tot1) / 60;
    return diff;
}

Time Time::operator*(double mult) const
{
    Time result;
    long totalminutes = hours * mult * 60 + minutes * mult;
    result.hours = totalminutes / 60;
    result.minutes = totalminutes % 60;
    return result;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值