欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

c++中的多态机制——运算符重载

程序员文章站 2024-03-17 20:52:04
...


一:c++中的多态机制一般至少有四种实现方式:

1: 普通函数重载,参数类型不同(参数列表不同),返回值类型可以相同

2: 运算符重载:一般用于对我们自定义的类中的数据进行操作

3: virtual虚函数,一般是在类的继承中实现的。

4:使用模板:实现类的多态

二:c++重载机制:

函数返回类型不影响生成的符号名

函数名,参数列表(参数类型、数目)才是影响符号名的因数

例如:foo_int_int这样的名字包含了函数名、函数参数数量及类型信息,C++就是靠这种机制来实现函数重载的。例如,在C++中,函数void foo( int x, int y )与void foo( int x, float y )编译生成的符号是不相同的,前者为_foo,后者为_foo_int_float

为什么要对运算符进行重载:

三:为什么要对运算符进行重载

        C++预定义中的运算符的操作对象只局限于基本的内置数据类型,但是对于我们自定义的类型(类)是没有办法操作的。但是大多时候我们需要对我们自定义的类型进行类似操作,这个时候就需要我们对这么运算符进行重新定义,赋予其新的功能,以满足自身的需求。

重载运算符的两种形式:
重载运算符有两种方式,即:

重载为类的成员函数||重载为类的非成员函数。

重载为类的非成员函数的时候:

通常我们都将其声明为友元函数,因为大多数时候重载运算符要访问类的私有数据,(当然也可以设置为非友元非类的成员函数。但是非友元又不是类的成员函数是没有办法直接访问类的私有数据的),如果不声明为类的友元函数,而是通过在此函数中调用类的公有函数来访问私有数据会降低性能。所以一般都会设置为类的友元函数,这样我们就可以在此非成员函数中访问类中的数据了。

四:一个简单的时间类

MyTime.h

#pragma once
#ifndef MYTIME_H_
#define MYTIME_H_
class CMyTime
{
private:
int m_hours;
int m_minutes;
public:
CMyTime();
CMyTime(int h, int m = 0);
void AddHr(int h);  //小时更改
void AddMin(int m);//分钟更改
void Reset(int h = 0, int m = 0);  //重新设置时间
CMyTime operator+(const CMyTime &t) const;  //重载加法
CMyTime operator-(const CMyTime &t) const;  //重载减法
CMyTime operator*(double n) const;                //重载乘法
void Show() const;
~CMyTime();
};
#endif
#include "MyTime.h"
#include <iostream>

CMyTime::CMyTime()
{
m_hours = 0;
m_minutes = 0;
}


CMyTime::CMyTime(int h, int m)
{
m_hours = h;
m_minutes = m;
}


CMyTime::~CMyTime()
{
}


void CMyTime::AddHr(int h)                                             //小时更改
{
m_hours += h;
}


void CMyTime::AddMin(int m)                                             //分钟更改
{
m_minutes = m;
}


void CMyTime::Reset(int h, int m)                                           //重新设置时间
{
m_hours = h;
m_minutes = m;
}


CMyTime CMyTime::operator+(const CMyTime &t) const              //重载加法运算符函数
{
CMyTime sum;
sum.m_minutes = t.m_minutes + m_minutes;
sum.m_hours = t.m_hours + m_hours + sum.m_minutes / 60;
sum.m_minutes %= 60;
return sum; //返回局部变量会创建局部变量的副本,不能返回局部变量的引用,重载 = 运算符的时候返回的是一个引用,请参考博c++的String类
}


CMyTime CMyTime::operator-(const CMyTime &t) const         //重载为减法运算符函数
{
CMyTime diff;
int tot1, tot2;
tot1 = t.m_minutes + 60 * t.m_hours;
tot2 = m_minutes + 60 * t.m_hours;
diff.m_minutes = (tot2 - tot1) % 60;
diff.m_hours = (tot2 - tot1) / 60;
return diff;
}


CMyTime CMyTime::operator*(double n) const                 //重载为乘法运算符函数。
{
CMyTime result;
long totalMinutes = m_hours * 60 * n+ m_minutes *n;
result.m_minutes = totalMinutes % 60;
result.m_hours = totalMinutes / 60;
return result;
}


void CMyTime::Show() const
{
std::cout << m_hours << " hours "
<< m_minutes << " minutes\n";
}
main.cpp
// Study11-02.cpp : 定义控制台应用程序的入口点。
//

#include <iostream>
#include "MyTime.h"

int  main( )
{
using std::cout;
using std::endl;
CMyTime weeding(4, 35);
CMyTime waxing(2, 47);
CMyTime total;
CMyTime diff;
CMyTime adjusted;


cout << "weeding Time = ";
weeding.Show();
cout << endl;


cout << "waxing Time = ";
waxing.Show();
cout << endl;


cout << "total work Time = ";   //(1)
total = weeding + waxing;
total.Show();
cout << endl;


diff = weeding - waxing;
cout << "weeding Time - waxing Time = "; //(2)
diff.Show();
cout << endl;


adjusted = total *1.5;                     //(3)
cout << "adjusted work Time = ";
adjusted.Show();
cout << endl;


return 0;
}
c++中的多态机制——运算符重载

五 :重载的两个版本

接下来我们为了更好的了解重载运算符,来进行<<运算符的重载:

现在我们想让 cout<<adjusted; 这句话能直接执行输出,(显然这种输出方式如果不重载<<运算符是没有办法执行的。因为cout根本不知道输出adjusted的什么东西),对于<<的重载我们有两种版本:

第一种声明为成员函数

照葫芦画瓢:CMyTime operator<<(ostream &s); 那么这种生命方式会造成什么结果呢?答案是:输出会变成:adjusted<< cout;或许看起来很不好,但这确实是正确的。因为这等价于:adjusted.operator<<(cout);

第二种版本:(也是更好的版本):MyTIme.h 声明:friend void operator<<(ostream &os,const CMyTime &t);     MyTime.cpp实现:  void operator<<(ostream &os,const CMyTime &t){os << t.hours << t.minutes};这样就可以执行cout << adjusted 这条语句了。

那么最重要的问题来了,我们什么时候声明为成员函数,什么时候声明为非成员函数呢?

首先,我们要明白这句话:对于成员函数来说,一个操作数通过this指针隐式的传递,(即本身),另一个操作数作为函数的参数显示的传递;对于友元函数(非成员函数)两个操作数都是通过参数来传递的。

(1)一般来说,弹幕运算符重载为类的成员函数,双目运算符重载为类的友元函数(咳咳,一般情况下)

(2)双目运算符不能将 = 。 ()【】。-> 重载为类的友元函数。

(3)如果运算符的第一次操作数要求为隐式转换则必须为友元函数。

(4)当最左边的要求为类对象,而右边的是一个内置类型,则要为友元函数。