C++运算符重载,友元
2017-03-31 09:54
288 查看
在介绍运算符重载之前,先看一下下面的代码,在实际编程中,我们一般如果要将两个数组相加,一般都会采用如下for循环的形式进行实现:
,这样是不是显得有点冗余,复杂,尤其是如果存在类对象需要相加,而且类中的成员变量又比较多的话,那就需要写很多条语句,显得很麻烦。但在C++中,可以定义一个表示数组的类,并使用重载+运算符,于是便可以有这样的语句:
everning=sam+janet;
理论的知识这里不讲,实例最具有说服力,最能让人理解运算符重载到底是什么。下面是c++ primer plus上的一个例子。
头文件:
源文件:
#include"operater_overloading.h"
void Time::AddMin(int m)
{
mins += m;
}
void Time::AddHours(int h)
{
hours += h;
}
Time Time::operator+(const Time& s) const
{
Time sum;
sum.mins = mins + s.mins;
sum.hours = hours + s.hours + sum.mins / 60;
sum.mins = sum.hours % 60;
return sum;
}
Time Time::operator-(const Time& s) const
{
Time diff;
int total1, total2;
total1 = hours * 60 + mins;
total2 = s.hours * 60 + s.mins;
diff.mins = (total1 - total2) % 60;
diff.hours = (total1 - total2) / 60;
return diff;
}
Time Time::operator*(double t) const
{
Time Result;
int totalMins;
totalMins = (hours * 60 + mins)*t;
Result.mins = totalMins % 60;
Result.hours = totalMins / 60;
return Result;
}
Time operator*(double m, const Time &T)
{
Time result;
int total = (T.hours * 60 + T.mins)*m;
result.hours = total / 60;
result.mins = total % 60;
return result;
}
std::ostream & operator<<(std::ostream & os, const Time & t)
{
os << t.hours << " hours," << t.mins << " mins";
return os;
}
主函数:
运行结果:
在上面的例子中,我取一条语句进行解释一下:Time operator+(const Time & S) const
第一个Time表示该重载运算符后返回的数据的类型是一个Time类,后面的加号表示重载的运算符是加号,该重载运算符中包含一个参数S,参数的类型为Time引用,最后面的一个const表示运算符重载返回的值不可修改。
总之,operator+()函数的名称使得函数表示法或运算符表示法来调用它,那如果有以下这种形式的运算,是否合法呢?
假设A,B,C,D都是Time类,那么如下运算形式是否正确呢?
Time A,B,C,D;
.....
D=A+B+C;
为了回答上面那个问题,我们将上面的那个语句转换为函数调用吧,由于c++是从左到右的结合的运算符,因此可以转换为下面的形式:
D=A.operator+(B+C);
然后,函数参数本身就被转换为一盒函数调用,结果如下:
D=A.operator+(B.operator+(C));
上述语句合法吗?是的,函数调用B.operator+(C)并返回一个Time类,然后将这个返回的类作为A.operator+()调用的参数,因此上述的方式是合法。
从上面的实例可以看出,使用一些运算符重载可以使得程序更加简洁,类之间可以直接实现四则运算操作,重载为成员函数时,总时隐含了一个参数,该参数是this指针。this指针是指向调用该成员函数对象的指针。
其实,运算符重载形式有两种,一是重载为类的成员函数,二是重载为类的友元函数。 上述实例中的运算符重载之后是类Time的成员函数,因此可以总结一下:
运算符重载为类的成员函数的一般语法形式为:
函数类型 operator 运算符(形参表)
{
函数体;
}
运算符重载就是赋予已有的运算符多重含义。通过重新定义运算符,使它能够用于特定类的对象执行特定的功能,这便增强了C++语言的扩充能力。
上面举得例子是运算符重载为类的成员函数,那么重载为友元函数是啥样子呢
其实细心的同学应该可以看到乘法的运算符重载是Time operator*(double t)const;那么要使用它的话,只能是这种形式:左侧为调用对象,右侧为调用对象的参数。
A=B*1.5;//等价于A=B.operator(1.5);
那么,如果如果存在这种形式:A=1.5*B ,这明显不能使用上面的乘法运算符重载,遇到这种情况该怎么办呢?重载为友元函数是时候登场了。首先介绍一下,如何创建友元。
创建友元函数的第一步是将其原型放在类的声明中,并在原型声明前面加上关键字friend,在上面的头文件中,其实已经声明了两个友元函数:
该原型意味着下面两点:
(1)虽然operator*()函数是在类的声明中声明的,但它不是类的成员函数,因此一定不能使用成员运算符来调用它;
(2)虽然operator*()函数不是成员函数,但他与成员函数的访问权限是相同的;
第二步是编写友元函数的定义。因为他不是成员函数,所以在定义的时候不要使用Time::限定符,另外在定义中也不要使用关键字friend,定义形式如下:
Time operator*(double m, const Time &T)
{
Time result;
int total = (T.hours * 60 + T.mins)*m;
result.hours = total / 60;
result.mins = total % 60;
return result;
}有了上述的声明和定义之后,语句A=1.5*B就可以调用刚才定义的非成员的友元函数:
A=operator*(1.5,B);
从上面的形式可以看出重载为友元函数定义格式一般是下面的这个样子:
重载为友元函数的运算符重载函数的定义格式如下:
friend <类型说明符> operator <运算符>(<参数表>)
{……}
上面的友元重载是:重载*运算符,其实还有比较常见的<<重载,这里就不介绍了,上面的例子中就包含了<<友元重载。
for(int i=0;i<20;i++) { everning[i]=sam[i]+janet[i];//遍历每个元素,然后将每个元素进行相加 }
,这样是不是显得有点冗余,复杂,尤其是如果存在类对象需要相加,而且类中的成员变量又比较多的话,那就需要写很多条语句,显得很麻烦。但在C++中,可以定义一个表示数组的类,并使用重载+运算符,于是便可以有这样的语句:
everning=sam+janet;
理论的知识这里不讲,实例最具有说服力,最能让人理解运算符重载到底是什么。下面是c++ primer plus上的一个例子。
头文件:
#ifndef OPERATOR_LOADING_H_ #define OPERATOR_LOADING_H_ #include<iostream> class Time { private: int mins; int hours; public: Time(){ mins = 0; hours = 0; }; Time(int hour, int min){ mins = min, hours = hour; }; void AddMin(int m); void AddHours(int h); void Reset(int m, int h){ mins = m; hours = h; }; Time operator+(const Time& s) const;//加法重载 Time operator-(const Time& s) const;//减法重载 Time operator*(double t) const;//乘法重载 friend Time operator*(double m, const Time& T);//友元重载 friend std::ostream & operator<<(std::ostream & os, const Time &t);//友元重载 protected: }; #endif
源文件:
#include"operater_overloading.h"
void Time::AddMin(int m)
{
mins += m;
}
void Time::AddHours(int h)
{
hours += h;
}
Time Time::operator+(const Time& s) const
{
Time sum;
sum.mins = mins + s.mins;
sum.hours = hours + s.hours + sum.mins / 60;
sum.mins = sum.hours % 60;
return sum;
}
Time Time::operator-(const Time& s) const
{
Time diff;
int total1, total2;
total1 = hours * 60 + mins;
total2 = s.hours * 60 + s.mins;
diff.mins = (total1 - total2) % 60;
diff.hours = (total1 - total2) / 60;
return diff;
}
Time Time::operator*(double t) const
{
Time Result;
int totalMins;
totalMins = (hours * 60 + mins)*t;
Result.mins = totalMins % 60;
Result.hours = totalMins / 60;
return Result;
}
Time operator*(double m, const Time &T)
{
Time result;
int total = (T.hours * 60 + T.mins)*m;
result.hours = total / 60;
result.mins = total % 60;
return result;
}
std::ostream & operator<<(std::ostream & os, const Time & t)
{
os << t.hours << " hours," << t.mins << " mins";
return os;
}
主函数:
#include"operater_overloading.h" int main() { using namespace std; Time aida(5, 30); Time soda(6, 42); cout << "aida: " << aida << "\n" << "soda: " << soda<<endl; Time temp; temp = aida + soda; cout << "aida + soda: " << temp << endl; temp = soda - aida; cout << "soda - aida: " << temp << endl; temp = aida*1.5; cout << "aida*1.5: " << temp << endl; cout << "10*aida: " << 10 * aida << endl; }
运行结果:
在上面的例子中,我取一条语句进行解释一下:Time operator+(const Time & S) const
第一个Time表示该重载运算符后返回的数据的类型是一个Time类,后面的加号表示重载的运算符是加号,该重载运算符中包含一个参数S,参数的类型为Time引用,最后面的一个const表示运算符重载返回的值不可修改。
总之,operator+()函数的名称使得函数表示法或运算符表示法来调用它,那如果有以下这种形式的运算,是否合法呢?
假设A,B,C,D都是Time类,那么如下运算形式是否正确呢?
Time A,B,C,D;
.....
D=A+B+C;
为了回答上面那个问题,我们将上面的那个语句转换为函数调用吧,由于c++是从左到右的结合的运算符,因此可以转换为下面的形式:
D=A.operator+(B+C);
然后,函数参数本身就被转换为一盒函数调用,结果如下:
D=A.operator+(B.operator+(C));
上述语句合法吗?是的,函数调用B.operator+(C)并返回一个Time类,然后将这个返回的类作为A.operator+()调用的参数,因此上述的方式是合法。
从上面的实例可以看出,使用一些运算符重载可以使得程序更加简洁,类之间可以直接实现四则运算操作,重载为成员函数时,总时隐含了一个参数,该参数是this指针。this指针是指向调用该成员函数对象的指针。
其实,运算符重载形式有两种,一是重载为类的成员函数,二是重载为类的友元函数。 上述实例中的运算符重载之后是类Time的成员函数,因此可以总结一下:
运算符重载为类的成员函数的一般语法形式为:
函数类型 operator 运算符(形参表)
{
函数体;
}
运算符重载就是赋予已有的运算符多重含义。通过重新定义运算符,使它能够用于特定类的对象执行特定的功能,这便增强了C++语言的扩充能力。
上面举得例子是运算符重载为类的成员函数,那么重载为友元函数是啥样子呢
其实细心的同学应该可以看到乘法的运算符重载是Time operator*(double t)const;那么要使用它的话,只能是这种形式:左侧为调用对象,右侧为调用对象的参数。
A=B*1.5;//等价于A=B.operator(1.5);
那么,如果如果存在这种形式:A=1.5*B ,这明显不能使用上面的乘法运算符重载,遇到这种情况该怎么办呢?重载为友元函数是时候登场了。首先介绍一下,如何创建友元。
创建友元函数的第一步是将其原型放在类的声明中,并在原型声明前面加上关键字friend,在上面的头文件中,其实已经声明了两个友元函数:
friend Time operator*(double m, const Time& T){ return T*m; }//友元重载 friend std::ostream & operator<<(std::ostream & os, const Time &t);//友元重载
该原型意味着下面两点:
(1)虽然operator*()函数是在类的声明中声明的,但它不是类的成员函数,因此一定不能使用成员运算符来调用它;
(2)虽然operator*()函数不是成员函数,但他与成员函数的访问权限是相同的;
第二步是编写友元函数的定义。因为他不是成员函数,所以在定义的时候不要使用Time::限定符,另外在定义中也不要使用关键字friend,定义形式如下:
Time operator*(double m, const Time &T)
{
Time result;
int total = (T.hours * 60 + T.mins)*m;
result.hours = total / 60;
result.mins = total % 60;
return result;
}有了上述的声明和定义之后,语句A=1.5*B就可以调用刚才定义的非成员的友元函数:
A=operator*(1.5,B);
从上面的形式可以看出重载为友元函数定义格式一般是下面的这个样子:
重载为友元函数的运算符重载函数的定义格式如下:
friend <类型说明符> operator <运算符>(<参数表>)
{……}
上面的友元重载是:重载*运算符,其实还有比较常见的<<重载,这里就不介绍了,上面的例子中就包含了<<友元重载。
相关文章推荐
- C++运算符重载(注意点),友元(使用和优缺点)
- C++运算符重载以及友元
- 关于C++运算符重载和友元的概念
- C++运算符重载 成员函数与友元函数详解
- c++中重载操作符表,可以帮助重载哪些操作符,以及到底是重载为类方法还是类的友元方法
- C++运算符优先级以及可否重载
- c++运算符重载(1)
- 模板类的友元重载(<>)
- C++运算符重载(成员函数以及友元函数实现)
- C++运算符重载 成员函数与友元函数
- C++运算符重载的规则
- C++运算符重载的方法详细解析
- C++运算符重载
- C++运算符重载小程序
- C++运算符重载讲解与经典实例
- C++运算符重载探讨
- C++运算符重载的妙用
- c++运算符的重载
- C++运算符重载讲解与经典实例
- C++运算符重载探讨