C++重载(主要介绍使用友元函数重载)

重载限制

多数C++运算符都可以用下面的方式重载。重载的运算符不必是成员函数,但必须至少有一个操作数是用户自定义的类型。下面详细介绍C++对用户定义的运算符重载的限制。

1 重载后的运算符必须至少有一个操作数是用户自定义的类型,这将防止用户为标准类型重载运算符。因此,不能将减法运算符(-)重载为double值的和,而不是它们的差。虽然这种限制将对创造性有所影响,但可以确保程序正常运行。

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

同样,不能修改运算符的优先级。因此,如果将加号运算符重载成将两个类相加,则新的运算符与原来的加号具有相同的优先级。

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

4 不能重载下面的运算符

  • sizeof:sizeof运算符
  • .:成员运算符
  • .*:成员指针运算符
  • :: :作用域解析运算符
  • ?::条件运算符
  • typeid:一个RTTI运算符
  • const_cast:强制类型转换运算符
  • dynamic_cast:强制类型转换运算符
  • reinterpret_cast:强制类型转换运算符
  • static_cast:强制类型转换运算符

然而,下表中的所有运算符都可以被重载

5 下表中的大多数运算符都可以通过成员或非成员函数进行重载,但下面的运算符值能通过成员函数进行重载

  • =:赋值运算符
  • ():函数调用运算符
  • []:下标运算符
  • ->:通过指针访问类成员的运算符

可重载的运算符

除了这些正式限制之外,还应在重载运算符时遵循一些限制。例如,不要将*运算符重载成交换两个对象的数据成员。

友元

C++控制对类对象私有部分的访问。通常,公有类方法提供唯一的访问途径,这种限制太严格,以至于不适合特定的编程问题。在这种情况下,C++提供了另外一种形式的访问权限:友元。

友元有3种:

  • 友元函数
  • 友元类
  • 友元成员函数

通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。

对于一个二元运算符,如果使用一个类对象和一个double类型进行操作

例如:

A=B*2.75

将被转换为下面的成员函数调用:

A=B.operator*(2.75);

但下面的语句又如何呢?

A=2.75*B;

从概念上讲,这两个表达式应该相同,但是第二个表达式不对应于成员函数,因为2.75不是类对象。记住,左侧的操作数应是调用对象,但2.75不是对象。因此,编译器不能使用成员函数调用替换该表达式。

解决这个难题的一种方式是——费成员函数(记住,大多数运算符都可以通过成员或非成员函数来重载)。非成员函数不是由对象调用的,它使用的所有值(包括对象)都是显示参数。这样,编译器能够将下面的表达式:

A=2.75*B;

与下面的非成员函数调用匹配:

A=operator*(2.75,B);

该函数的原型如下:

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

对于非成员重载运算符函数来来说,运算符表达式左边的操作数对应于运算符函数的第一个参数,运算符表达式右边的操作数对应于运算符函数的第二个参数。而原来的成员函数则按相反的顺序处理操作数,也就是说,double值乘以class1值。

使用非成员函数可以按所需的顺序获得操作数(先double,然后是class1),但引发了一个新问题:非成员函数不能直接访问类的私有数据,至少常规非成员函数不能访问。然而,有一类特殊的非成员函数可以访问类的私有成员,它们被称为友元函数。

创建友元

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

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

该原型意味着下面两点:

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

第二步的编写函数定义。因为它不是成员函数,所以不要使用成员限定符::。另外,不要再定义中使用关键字friend。定义应该如下:

class1 operator*(double m,const class1 &t)

{}

有了上述声明和定义后,下面的语句:

A=2.75*B;

将转换为如下语句,从而调用刚才定义的非成员友元函数:

A=operator*(2.75,B);

总之,类的友元函数是非成员函数,其访问权限与成员函数相同。

实际上,按下面的方式对定义进行修改(交换乘法操作数的顺序),可以将这个友元函数编写为非友元函数:

class1 operator*(double m,const class1 &t)

{

  return t*m;//use t.operator*(m)

}

这个版本将class1对象t作为一个整体使用,让成员函数类处理私有值,因此不必是友元。然而,将该版本作为友元也是一个好主意。最重要的是,它将作为正式类接口的组成部分。其次,如果以后发现需要函数直接访问私有数据,则只要修改函数定义即可,而不必修改类原型。

提示:如果要为类重载运算符,并将非类的项作为其第一个操作数,则可以使用友元函数来反转操作数的顺序。。

C++重载(主要介绍使用友元函数重载),布布扣,bubuko.com

时间: 2024-10-25 22:36:12

C++重载(主要介绍使用友元函数重载)的相关文章

友元函数实现操作符重载的应用场景-友元函数实现左移右移操作符重载

先定义一个测试类Complex,其中用成员函数的方法重载了+.-.前置++.前置--.后置++.后置--这6个运算符,当然,这6个操作符也可以用友元函数方式重载,但习惯上这些都直接用成员函数方式重载. demo #include <iostream> using namespace std; class Complex { public: Complex(int a = 0, int b = 0) { this->a = a; this->b = b; } ~Complex();

从一个二级题来看成员函数重载运算符和友元函数重载运算符

先上题:下列运算符都可以被友元函数重载的是: A)=,+,-,\ B)[],+,(),new C)->,+,*,>> D)<<,>>,+,* 正确答案为D 我们知道,在运算符重载,友元函数运算符重载函数与成员运算符重载函数的区别是:友元函数没有this指针,而成员函数有,因此,在两个操作数的重载中友元函数有两个参数,而成员函数只有一个. 因此,我们可以总结如下: 1.对双目运算符而言,成员函数重载运算符的函数参数表中只有一个参数,而用友元函数重载运算符函数参数表中

等号操作符重载为什么不能用友元函数大揭秘,以及函数没有等到重载的时候赋值会出现什么现象(盲点)

先看下面程序结果输出什么? 1 #include <iostream> 2 using namespace std; 3 4 class A 5 { 6 private: 7 int x; 8 public: 9 A(){ 10 x=99; 11 cout<<"看看这里是否会被调用"<<endl; 12 } 13 }; 14 15 int main() 16 { 17 A a; 18 a = 7; 19 } 这里面,会报错,显示没有等号匹配现象.只有

思考: 对于一个要重载的运算符而言,什么样的运算符应该用类成员函数重载,什么情况应该用友元函数重载??

还是用一个例子来说明吧 1 #define unsigned int UINT32 2 3 class RMB 4 { 5 public: 6 RMB(UINT32 d, UINT32 c); 7 friend RMB operator +(RMB&, RMB&); 8 friend RMB& operator ++(RMB&); 9 void display() 10 { 11 cout<<(yuan + jf / 100.0)<<endl; 12

为什么operator&lt;&lt;&gt;&gt;运算符重载一定要为友元函数呢?

如果是重载双目操作符(即为类的成员函数),就只要设置一个参数作为右侧运算量,而左侧运算量就是对象本身...... 而 >>  或<< 左侧运算量是 cin或cout 而不是对象本身,所以不满足后面一点........就只能申明为友元函数了... 如果一定要声明为成员函数,只能成为如下的形式: ostream & operator<<(ostream &output) { return output; } 所以在运用这个<<运算符时就变为这种形

函数重载(续)==》函数重载和函数指针在一起

函数重载与函数指针(这一块很重要,后续要继续学习): 当使用重载函数名对函数指针赋值时 根据重载规则挑选与函数指针参数列表一致的候选者 严格匹配候选者的函数类型与函数指针的函数类型 #include <iostream> using namespace std; void myFunc(int a) {     printf("a:%d\n",a); } void myFunc(char *p) {     printf("p:%s\n",p); } v

C++友元函数重载&quot;++&quot;和&quot;--&quot;运算符

代码: 1 #include <iostream> 2 #include <cstring> 3 4 using namespace std; 5 6 class one{ 7 public: 8 one(int i); 9 void print(); 10 friend one operator++(one&); 11 friend one operator++(one&,int); 12 13 private: 14 int i; 15 }; 16 17 one

运算符重载三种形式(成员函数,友元函数,普通函数)详解

首先,介绍三种重载方式: 1 //作为成员函数重载(常见) 2 class Person{ 3 Private: 4 string name; 5 int age; 6 public: 7 Person(const char* name, int age):name(name),age(age){} 8 bool operator<(const Person& b); 9 10 }; 11 bool Person::operator<(const Person& b) 12 {

C++:运算符重载函数之友元运算符重载

5.2.2 友元运算符重载函数 运算符重载函数一般采用两种形式定义: 一是定义为它将要操作的类的成员函数(简称运算符重载函数): 二是定义为类的友元函数(简称为友元运算符重载函数). 1.定义友元运算符重载函数的语法如下: 在类的内部: friend 函数类型 operator运算符(形参表) { 函数体 } 在类的内部声明,在类外定义: class X{ ... friend 函数类型 operator运算符(形参表): }; 函数类型 X::operator运算符(形参表) { 函数体 }