友元
我们知道在C++中有三大特性,就是封装,继承,多态。对于一个类来说,我们实现了一个类的封装和隐藏。在我们平时的时候,都会将类的数据成员进行私有化,提供一个接口负责外界对私有的数据成员进行访问。但是,当我们定义了一些不属于类的成员函数,但是呢,这些函数却要频繁的被调用,来修改我们的成员变量,这时候我们就可以将这些函数定义为友元函数,以此来达到效果。
友元分为友元函数和友元类。
友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类。
注意:友元一定是发生在不同类对象之间的。(对于运算符重载来说,MyString::MyString(const MyString & other) ,在同类中是可以直接访问对方的私有成员的)
友元函数
1.友元函数的定义:
友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它 不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字 friend。简单来说,你有一个好朋友,你的这个朋友可以看见你家的所有东西。
其格式如下: friend 类型 函数名(形式参数);
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
2.全局函数作为友元函数:
class A{
public:
A(int _x=1, int _y=1) :x(_x), y(_y){}
void print()
{
cout << "x=" << x << endl;
cout << "y=" << y << endl;
}
friend int product(A&a, A&b);
private:
int x;
int y;
};
int product(A&a, A&b)
{
int tmp;
tmp= a.x*b.x;
tmp += a.y*b.y;
return tmp;
}
int main()
{
A a(2, 3);
A b(6, 3);
a.print();
b.print();
cout << product(a, b) << endl;
return 0;
}
通过上面的代码,我们先定义了一个A类,这个类中定义了两个成员变量,分别是x和y。我们定义了一个全局函数,用来计算两个A类生成对象的乘积的值。这个时候,这个函数将会不断的频繁访问我们的类成员,因此,我们就将其声明为类A的友元函数,这个时候,就可以访问到类A的私有成员。
3.类成员函数作为友元函数
class A;
class B{
public:
int product(A&a, A&b);
};
class A{
public:
A(int _x=1, int _y=1) :x(_x), y(_y){}
void print()
{
cout << "x=" << x << endl;
cout << "y=" << y << endl;
}
friend int B::product(A&a, A&b);
private:
int x;
int y;
};
int B::product(A&a, A&b)
{
int tmp;
tmp = a.x*b.x;
tmp += a.y*b.y;
return tmp;
}
int main()
{
A a(2, 3);
A b(6, 3);
a.print();
b.print();
B tmp;
cout << tmp.product(a, b) << endl;
return 0;
}
对于上面功能,这个时候,我们使用了类的对象函数,作为了类的友元函数,也可以实现这个功能。 但是在这个之前,我们要补充一个知识,就是前向声明。
前向声明,是一种不完全型(forward declaration)声明,即只需提供类名(无需提供 类实现)即可。正因为是(incomplete type)功能也很有限:
(1)不能定义类的对象。
(2)可以用于定义指向这个类型的指针或引用。
(3)用于声明(不是定义),使用该类型作为形参类型或者函数的返回值类型。
在上诉的代码中,我们可以看见,我们首先前向声明了一个类A,因为在B类中,成员方法的参数中使用了这个类的引用。但是在类B中,我们不能将这个成员方法实现。因为呢,虽然我们在前面声明了一个类A,但是我们并没有实现,因此,我们并不能知道A类中具体的实现,因此,我们需要将我们的类B中 A的友元函数在类A实现之后,在进行实现。
友元类
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包 括私有成员和保护成员)。
当希望一个类可以存取另一个类的私有成员时,可以将该类声明为另一类的友元类。定义 友元类的语句格式如下:
friend class 类名;
其中:friend 和 class 是关键字,类名必须是程序中的一个已定义过的类。
例如,以下语句说明类 B 是类 A 的友元类:
class A
{ …
public: friend class B;
… };
经过以上说明后,类 B 的所有成员函数都是类 A 的友元函数,能存取类 A 的私有成员和 保护成员。
class A{
public:
A(int _x=1, int _y=1) :x(_x), y(_y){}
friend class B;
private:
int x;
int y;
};
class B{
public:
A a;
void print()
{
cout << "x=" << a.x << endl;
cout << "y=" << a.y << endl;
}
int product(A&a, A&b)
{
int tmp;
tmp = a.x*b.x;
tmp += a.y*b.y;
return tmp;
}
};
int main()
{
A a(2, 3);
A b(6, 3);
B tmp;
cout << tmp.product(a, b) << endl;
tmp.print();
return 0;
}
在上面的代码中,我们将类B设置为类A的友元函数,对于B类中成员方法都可以访问类A中的成员变量。
论友元
1.友元函数的位置:
友元声明以关键字 friend 开始,它只能出现在类定义中。因为友元不是授权类的成员, 所以它不受其所在类的声明区域 public private 和 protected 的影响。通常我们选择把所有友元 声明组织在一起并放在类头之后。
2.友元的利弊
友元不是类成员但是它可以访问类中的私有成员。友元的作用在于提高程序的运行效率, 但是,它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员。不过,类的访 问权限确实在某些应用场合显得有些呆板,从而容忍了友元这一特别语法现象。
3.注意事项
(1) 友元关系不能被继承。
(2) 友元关系是单向的,不具有交换性。若类 B 是类 A 的友元,类 A 不一定是类 B的 友元,要看在类中是否有相应的声明。
(3) 友元关系不具有传递性。若类 B 是类 A 的友元,类 C 是 B 的友元,类 C 不一定是 类 A 的友元,同样要看类中是否有相应的申明