Skip to content

Latest commit

 

History

History
242 lines (185 loc) · 5.38 KB

05.md

File metadata and controls

242 lines (185 loc) · 5.38 KB

文章内容

一.友元概述

二.友元函数

三.友元类

四.类成员为另一个类的友元

友元函数和友元类

友元的作用举例来说--写一个神经网络,写完以后想写一个单元测试,和神经网络放在一个命名空间里。写的神经网络是一个类,里面有多个私有变量,而单元测试不可避免地要用到这些私有变量。如果这是在java里,我就只能再写上一堆访问器了;而在C++里,只用把这个单元测试函数声明成类的友元,就能随心所欲地访问私有变量,简直不要太痛快。

但同时也需要慎用friend关键字,它会破坏掉封装的隐藏性。

友元函数

如果一个函数被定义为一个类的友元函数,那么这个函数可以访问所有私有和受保护的数据。

要使函数成为类的友元函数,可以在类内部以private或public部分的形式声明它,并在声明之前加上关键字friend,如下所示。

class Temperature
{
    int celsius;
    public:
        Temperature():celsius(0);

        friend int temp( Temperature );   //声明友元函数
};

这里,temp是类Temperature的友元函数。因此,它可以访问类的所有私有成员和受保护成员。

#include <iostream>

using namespace std;

class Temperature
{
	int celsius;
	public:
		Temperature():celsius(0);

		friend int temp( Temperature );   
};

int temp( Temperature t )     // 友元函数定义
{
	t.celsius = 40;
	return t.celsius;
}

int main()
{
	Temperature tm;
	cout << "Temperature in celsius : " << temp( tm ) << endl;
	return 0;
}
//OUTPUT:Temperature in celsius : 40

声明了一个函数“temp”作为类“Temperature”的友元函数。在friend函数中,我们直接访问了类'Temperature'的私有成员摄摄氏度。 主函数的第一个语句创建了类'Temperature'的对象'tm',从而调用其构造函数,并为其数据成员摄氏度赋值0。 主函数的第二个语句调用temp函数,它为摄氏温度赋值40。

两个类的同一个f可以有同一个友元函数。

#include <iostream>

using namespace std;

class B;       //declaration of class B

class A
{
	int value;
	public:
		A():value(5){}

		friend int sum(A, B);     // 声明友元函数
};

class B
{
	int value;
	public:
		B():value(3);

		friend int sum(A, B);     // 声明友元函数
};

int sum( A v1, B v2 )             // 定义友元函数
{
	return (v1.value + v2.value);
}

int main()
{
	A a;
	B b;
	cout << "Sum : " << sum( a, b ) << endl;
	return 0;
}
//OUTPUT:Sum : 8

在本例中,将sum()声明为a和b类的friend函数。因此,该函数现在可以访问这两个类的私有成员和受保护成员。这两个类的对象都作为函数的参数传递。

注意,我们在定义类A之前声明了类B,因为在类A的主体中,friend函数接受参数'A'和'B'。

友元类

在学校里能使一个班成为另一个班的朋友。在这种情况下,类中声明为friend的所有成员函数将成为另一个类的friend函数。

class A
{
    friend class B;

};

class B
{

};

上面的代码中,B类被声明为a类的朋友。所以现在B类的所有成员函数都变成了A类的友元函数。

再来看一个例子

#include <iostream>

using namespace std;

class Square
{
	friend class Rectangle;      // 将Rectangle声明为友元类
	int side;
	public:
		Square ( int s )
		{
			side = s;
		}
};

class Rectangle
{
	int length;
	int breadth;
	public:
	int getArea()
	{
		return length * breadth;
	}
	void shape( Square a )
	{
		length = a.side;
		breadth = a.side;
	}
};

int main()
{
	Square square(5);
	Rectangle rectangle;
	rectangle.shape(square);
	cout << rectangle.getArea() << endl;
	return 0;
}
//OUTPUT:25

将Rectangle声明为Square的friend类。因此,现在Rectangle的所有函数都可以直接访问Square的任何私有成员。 在主函数中,第一个语句创建了类square的对象'square',从而调用它的构造函数并将5分配给它的数据成员端。 主函数中的第二条语句创建了类rectangle的对象'rectangle'。 在第三个语句中,'rectangle'调用函数shape(),它的参数是类Square的对象。在'shape()'函数中,'side' (Squa的私有数据成员)的值

类成员为另一个类的友元

还可以使一个类的函数成为另一个类的友元函数。这样做的方法与作为类的友元创建函数的方法是一样的。惟一的区别是,需要在声明中把class_name::写在类中函数名的前面,该类的友元函数是被声明的。friend函数仅在类中指定,其整个主体在类外声明。从下面给出的例子可以清楚地看出。

class A; // A再B之前声明

class B
{
    display( A a ); //只有指定的。没有具体实现
};

class A
{
    friend void B::display( A );
};

void B::display(A a) //在B中实现
{
}

下面是一个实际的例子

using namespace std;

class A; 

class B
{
    public:
        void display(A obj); 
};

class A
{
    int x;
    public:
        A()
        {
            x = 4;
        }
        friend void B::display(A);
};

void B::display(A obj)
{
    cout << obj.x << endl;
}

int main()
{
    A a;
    B b;
    b.display(a);
    return 0;
}
//OUTPUT:4
//需要使用gcc filename.cpp -lstdc++ -o文件名来运行这段代码