在程序设计中,加入类A想访问类B中的私有成员和私有函数时,为了保持程序的封装性,又让其有共享性,就用到了友元类和友元函数。
class A
{
friend class B ;
public :
void Display() { cout << x << endl ; } ;
private :
int x ;
} ;
//上面在类A声明了它的友元类是B,所以类B可以访问A中私有成员和私有函数
class B
{
public :
void Set ( int i ) { Aobject . x = i ; }
void Display () { Aobject . Display () ; }
//调用了类A的私有成员
private :
A Aobject ;//声明了类A的对象
} ;
void main()
{
B Bobject ;
Bobject . Set ( 100 ) ;
Bobject . Display () ;
system("pause");
}
友元函数应用比较多,常用的场合有:
1. 运算符重载的某些场合需要使用友元。
2. 两个类需要共享数据的时候。
class Test2
{
public:
//友元函数的特点是:有一个参数是友元类的指针或引用.
//友元函数是类外函数,所以声明放在公有段或者私有段没有区别。
friend int OpMem(Test2 *p, int a); //友元函数,中有类对象指针,通过它访问类中私有成员
Test2(int a, int b)
{
this->a = a;
this->b = b;
}
int getA()
{
return this->a;
}
protected:
private:
int a ;
int b;
};
int OpMem(Test2 *p, int a)
{
p->a = a;//获取类中私有成员
return 0;
}
void main()
{
Test2 t1(1, 2);
t1.getA();
OpMem(&t1, 10);//直接调用友元函数,毕竟友元函数不是成员函数
system("pause");
}
运算符重载是指:为了实现类的多态性(一个函数名有多重含义),运算符与类结合,产生新的含义。
怎么实现运算符的重载?
方式:类的成员函数 或 友元函数(类外的普通函数)
规则:不能重载的运算符有 . 和 .* 和 ?: 和 :: 和 sizeof
友元函数和成员函数的使用场合:一般情况下,建议一元运算符使用成员函数,二元运算符使用友元函数。
1、运算符的操作需要修改类对象的状态,则使用成员函数。如需要做左值操作数的运算符(如=,+=,++)
2、运算时,有数和对象的混合运算时,必须使用友元
3、二元运算符中,第一个操作数为非对象时,必须使用友元函数。如输入输出运算符<<和>>
具体规则如下:
运算符 | 建议使用 |
---|---|
所有一元操作符 | 成员函数 |
= 、()、[]、-> | 必须是成员函数 |
+=、-=、/=等带=的运算符 | 成员函数 |
+、-、*等二目运算符 | 友元函数 |
<<>> | 必须是友元函数 |
函数和返回值
+和-运算符重载
#include
using namespace std;
class PointTest
{
private:
double pointX;
public:
PointTest(int x1)
{
pointX=x1;
}
void PrintResult();
const PointTest operator +(const PointTest &obj);//使用成员函数重载运算符
friend const PointTest operator -(const PointTest &obja,const PointTest & objb);//友元函数
};
#pragma region 成员函数
const PointTest PointTest::operator+(const PointTest &obj)
{
return PointTest(this->pointX + obj.pointX);
}
void PointTest::PrintResult()
{
cout<<this->pointX<//system("pause");
getchar();
}
#pragma endregion
//友元函数重载+
const PointTest operator-(const PointTest &obja,const PointTest & objb)
{
return PointTest(obja.pointX-objb.pointX);
}
int main()
{
PointTest a(1);
PointTest b(2);
PointTest c = a+b;//调用成员函数
c.PrintResult();
c =c-b;
c.PrintResult();
a-1;//正确,先调用类型转换函数,把1变成对象,之后调用友元函数
a+1;//同上,但是参数必须是const类型,才编译通过
1-a;
//1+a;调用成员函数时,第一个操作数必须是对象,因为第一个操作数还有调用成员函数的功能
}
1、由于+ -都是出现在=号的右边,如c=a+b,即会返回一个右值,可以返回const型值
2、后几个表达式讨论的就是,数和对象混合运算符的情况,一般出现这种情况,常使用友元函数
单目运算符++ 、–
class Point
{
private:
int x;
public:
Point(int x1)
{ x=x1;}
Point operator++();//成员函数定义自增
const Point operator++(int x); //后缀可以返回一个const类型的值
friend Point operator--(Point& p);//友元函数定义--
friend const Point operator--(Point& p,int x);//后缀可以返回一个const类型的值
};
Point Point::operator++()//++obj
{
x++;
return *this;
}
const Point Point::operator++(int x)//obj++
{
Point temp = *this;
this->x++;
return temp;
}
Point operator--(Point& p)//--obj
{
p.x--;
return p;
//前缀形式(--obj)重载的时候没有虚参,通过引用返回*this 或 自身引用,也就是返回变化之后的数值
}
const Point operator--(Point& p,int x)//obj--
{
Point temp = p;
p.x--;
return temp;
// 后缀形式obj--重载的时候有一个int类型的虚参, 返回原状态的拷贝
}
int main()
{
Point b(2);
a++;//隐式调用成员函数operator++(0),后缀表达式
++a;//隐式调用成员函数operator++(),前缀表达式
b--;//隐式调用友元函数operator--(0),后缀表达式
--b;//隐式调用友元函数operator--(),前缀表达式
cout<operator ++(2);//显式调用成员函数operator ++(2),后缀表达式
cout<operator ++();//显式调用成员函数operator ++(),前缀表达式
cout<<operator --(b,2);//显式调用友元函数operator --(2),后缀表达式
cout<<operator --(b);//显式调用友元函数operator --前缀表达式
}
在前置++(++a)和后置++(a++)中,前后缀仅从函数名(operator++)无法区分,只能有参数区分,这里引入一个虚参数int x,x可以是任意整数。
重载运算符[]
在这里将讲到返回对象引用。
class Point
{
private:
int x[5];
public:
Point()
{
for (int i=0;i<5;i++)
{
x[i]=i;
}
}
int& operator[](int y); //声明的返回对象的引用
};
int& Point::operator[](int y)
{
static int t=0;
if (y<5)
{
return x[y];
}
else
{
cout<<"下标出界";
return t;
}
}
int main()
{
Point p;
int a = p[3];//此处为右值,可以为变量,也可以为引用。
a[2] = 3;//此处为对象成为左值,必须是对象引用,如果返回值为对象变量的时候,编译器不知道如何转化。
}
运算符[]中的重载方式:只能使用成员函数重载。
函数名:operator
参数表:一个参数,且仅有一个参数,该参数设定了下标值,通常为整型,但是也可以为字符串( 看成下标)。
返回值: 返回的值可以做左值,也可以做右值,则必须使用返回引用。
难点重载运算符<<,>>
这里写代码片class Point
{
private:
int x;
public:
Point(int x1)
{ x=x1;}
friend ostream& operator<<(ostream& cout,const Point& p);//使用友元函数重载<<输出运算符
friend istream& operator>>(istream& cin,Point& p);//使用友元函数重载>>输出运算符
};
//对于<<这种运算符,格式相对比较固定,返回类型还有参数。
ostream& operator<<(ostream& cout,const Point& p)
{
cout<return cout;
}
istream& operator>>(istream& cin,Point& p)
{
cin>>p.x;
return cin;
}
Point a(1);
Point b(2);
cin>>a>>b;
cout<
语法:
重载方式:只能使用友元函数重载 且 使用三个引用&
函数名:
输出流: operator<<(参数表)
输入流:operator>>(参数表)