C++中friend的使用

In principle,private and protected members of a class cannot be accessed from outside the same class in which they are declared. However, this rule does not apply to"friends". A friend class in C++ can access the "private"and "protected" members of the class in which it is declared as a friend.

A friend can be a function, function template, or member function, or a class or class template, in which case the entire class and all of its members are friends.

One of the important concept of OOP is data hiding, i.e., a nonmember function cannot access an object's private or protected data. But, sometimes this restriction may force programmer to write long and complex codes. So, there is mechanism builtin C++ programming to access private or protected data from non-member function which is friend function and friend class.

If a function is defined as a friend function then, the private and protected data of class can be accessed from that function. The compiler knows a given function is a friend function by its keyword friend. The declaration of friend function should be made inside the body of class (can be anywhere inside class either in private public section) starting with keyword friend.

When a class is made a friend class, all the member functions of that class becomes friend function.

Friend functions have the following properties:

(1). Friend of the class can be member of some other class.

(2). Friend of one class can be friend of another class or all the classes in one program,such a friend is known as GLOBAL FRIEND.

(3). Friend can access the private or protected members of the class in which they are declared to be friend, but they can use the members for a specific object.

(4). Friends are non-members hence do not get “this” pointer.

(5). Friends,can be friend of more than one class, hence they can be used for message passing between the classes.

(6). Friend can be declared anywhere (in public, protected or private section) in the class.

友元函数并不能看做是类的成员函数,它只是个被声明为类友元的普通函数:

(1)、在类里声明一个普通函数,在前面加上friend修饰,那么这个函数就成了该类的友元,可以访问该类的一切成员。

(2)、一个普通函数可以是多个类的友元函数。

(3)、一个类的成员函数也可以是另一个类的友元,从而可以使得一个类的成员函数可以操作另一个类的数据成员。

(4)、整个类也可以是另一个类的友元,该友元也可以称作为友类。友类的每个成员函数都可以访问另一个类的所有成员。

友元声明中声明的函数被视为已使用extern关键字声明。

friend函数是一个不是类成员的函数,但它可以访问类的私有和受保护的成员。友元函数不被视为类成员,它们是获得了特殊访问权限的普通外部函数。友元不在类的范围内除非它们是另一个类的成员,否则不能使用成员选择运算符(.和->)调用它们。friend函数由授予访问权限的类声明。可将friend声明放置在类声明中的任何位置。它不受访问控制关键字的影响。

友元关系不是相互的,除非显示指定。友元关系不能继承。友元关系不可传递。

类的外部,也就是通过实例来访问私有(private)或保护(protected)成员,这是被禁止的。但从实用性来说,的确有时很需要在外部访问,C++增加了一种称之为“友元(friend)”函数的声明,将“特权”赋给一些函数(可以是全局函数,也可以是其它类的成员函数),使之能够访问该类的私有和保护成员。

友元函数必须在类里面声明,而且友元函数一定不是该类的成员函数。另外,友元函数的声明在派生类无效,除非派生类中再声明一次,当然类型转换为基类时,使用没有任何问题。

下面是从其他文章中copy的测试代码,详细内容介绍可以参考对应的reference:

#include "friend.hpp"

#include <sstream>
#include <iostream>

// reference: https://msdn.microsoft.com/zh-cn/library/465sdshe.aspx
class Point_ {
	friend void ChangePrivate(Point_ &);
public:
	Point_(void) : m_i(0) {}
	void PrintPrivate(void){ std::cout << m_i << std::endl; }

private:
	int m_i;
};

// friend 函数可以访问其接受为参数的 Point_ 对象的私有数据成员
void ChangePrivate(Point_ &i)
{
	i.m_i++;
}

int test_friend1()
{
	Point_ sPoint;
	sPoint.PrintPrivate(); // 0
	ChangePrivate(sPoint);
	sPoint.PrintPrivate(); // 1

	return 0;
}


class B_f;

class A_f {
public:
	int Func1(B_f& b);
private:
	int Func2(B_f& b);
};

class B_f {
private:
	int _b;

	// A::Func1 is a friend function to class B
	// so A::Func1 has access to all members of B
	// 类成员函数可以声明为其他类中的友元
	friend int A_f::Func1(B_f&);
};

int A_f::Func1(B_f& b) { return b._b; }   // OK
//int A_f::Func2(Bf_& b) { return b._b; }   // C2248

///
class YourClass {
	// friend 类是其所有成员函数都是类的友元函数的类,即,其成员函数具有对类的私有成员和受保护成员访问权限.
	// 友元关系不是相互的,除非显式指定。YourClass 的成员函数无法访问 YourOtherClass 的私有成员.
	// 友元关系不能继承,这意味着从 YourOtherClass 派生的类不能访问 YourClass 的私有成员.
	// 友元关系不可传递,因此 YourOtherClass 的友元类无法访问 YourClass 的私有成员。
	friend class YourOtherClass;  // Declare a friend class
public:
	YourClass() : topSecret(0){}
	void printMember() { std::cout << topSecret << std::endl; }
private:
	int topSecret;
};

class YourOtherClass {
public:
	void change(YourClass& yc, int x){ yc.topSecret = x; }
};

int test_friend2()
{
	YourClass yc1;
	YourOtherClass yoc1;
	yc1.printMember(); // 0
	yoc1.change(yc1, 5);
	yc1.printMember(); // 5

	return 0;
}

///
// reference: http://en.cppreference.com/w/cpp/language/friend
template<typename T>
class Foo {
public:
	Foo(const T& val) : data(val) {}
private:
	T data;

	// generates a non-template operator<< for this T
	friend std::ostream& operator<<(std::ostream& os, const Foo& obj)
	{
		return os << obj.data;
	}
};

int test_friend3()
{
	Foo<double> obj(1.23);
	std::cout << obj << '\n'; // 1.23

	return 0;
}

///
template<typename T>
class Foo_; // forward declare to make function declaration possible

template<typename T> // declaration
std::ostream& operator<<(std::ostream&, const Foo_<T>&);

template<typename T>
class Foo_ {
public:
	Foo_(const T& val) : data(val) {}
private:
	T data;

	// refers to a full specialization for this particular T 
	friend std::ostream& operator<< <> (std::ostream&, const Foo_&);
	// note: this relies on template argument deduction in declarations
	// can also specify the template argument with operator<< <T>"
};

// definition
template<typename T>
std::ostream& operator<<(std::ostream& os, const Foo_<T>& obj)
{
	return os << obj.data;
}

int test_friend4()
{
	Foo_<double> obj(1.23);
	std::cout << obj << '\n'; // 1.23

	return 0;
}

///
class MyClass {
	int i;

	friend std::ostream& operator<<(std::ostream& out, const MyClass& o);
	friend std::istream& operator>>(std::istream& in, MyClass& o);
public:
	MyClass(int i = 0) : i(i) {}
};

std::ostream& operator<<(std::ostream& out, const MyClass& mc)
{
	return out << mc.i;
}

std::istream& operator>>(std::istream& in, MyClass& mc)
{
	return in >> mc.i;
}

int test_friend5()
{
	MyClass mc(7);
	std::cout << mc << '\n'; // 7
	std::istringstream("100") >> mc;
	std::cout << mc << '\n'; // 100

	return 0;
}

///
// reference: http://www.cplusplus.com/doc/tutorial/inheritance/
class Rectangle {
	int width, height;
public:
	Rectangle() {}
	Rectangle(int x, int y) : width(x), height(y) {}
	int area() { return width * height; }
	friend Rectangle duplicate(const Rectangle&);
};

Rectangle duplicate(const Rectangle& param)
{
	Rectangle res;
	res.width = param.width * 2;
	res.height = param.height * 2;
	return res;
}

int test_friend6()
{
	Rectangle foo;
	Rectangle bar(2, 3);
	foo = duplicate(bar);
	std::cout << foo.area() << '\n'; // 24

	return 0;
}


class Square_;

class Rectangle_ {
	int width, height;
public:
	int area()
	{
		return (width * height);
	}
	void convert(Square_ a);
};

class Square_ {
	friend class Rectangle_;
private:
	int side;
public:
	Square_(int a) : side(a) {}
};

void Rectangle_::convert(Square_ a) {
	width = a.side;
	height = a.side;
}

int test_friend7()
{
	Rectangle_ rect;
	Square_ sqr(4);
	rect.convert(sqr);
	std::cout << rect.area(); // 16

	return 0;
}

///
// reference: http://www.tutorialspoint.com/cplusplus/cpp_friend_functions.htm
class Box
{
	double width;
public:
	friend void printWidth(Box box);
	void setWidth(double wid);
};

// Member function definition
void Box::setWidth(double wid)
{
	width = wid;
}

// Note: printWidth() is not a member function of any class.
void printWidth(Box box)
{
	/* Because printWidth() is a friend of Box, it can
	directly access any member of this class */
	std::cout << "Width of box : " << box.width << std::endl;
}

int test_friend8()
{
	Box box;

	// set box width with member function
	box.setWidth(10.0);

	// Use friend function to print the wdith.
	printWidth(box); // 10.0

	return 0;
}

/
// reference: http://www.programiz.com/cpp-programming/friend-function-class
class Distance
{
private:
	int meter;
public:
	Distance() : meter(0){ }
	friend int func(Distance);  //friend function
};

int func(Distance d)            //function definition
{
	d.meter = 5;         //accessing private data from non-member function
	return d.meter;
}

int test_friend9()
{
	Distance D;
	std::cout << "Distace: " << func(D); // 5
	return 0;
}

///
class B;     // forward declaration

class A {
private:
	int data;
public:
	A() : data(12){ }
	friend int func(A, B);   //friend function Declaration
};

class B {
private:
	int data;
public:
	B() : data(1){ }
	friend int func(A, B);  //friend function Declaration
};

int func(A d1, B d2)
/*Function func() is the friend function of both classes A and B. So, the private data of both class can be accessed from this function.*/
{
	return (d1.data + d2.data);
}

int test_friend10()
{
	A a;
	B b;
	std::cout << "Data: " << func(a, b); // 13

	return 0;
}

///
// reference: https://www.codingunit.com/cplusplus-tutorial-friend-function-and-friend-class
//Must be known to TWO before declaration of ONE.
class ONE;

class TWO
{
public:
	void print(ONE& x);
};

class ONE
{
	int a, b;
	friend void TWO::print(ONE& x);
public:
	ONE() : a(1), b(2) { }
};

void TWO::print(ONE& x)
{
	std::cout << "a is " << x.a << std::endl; // a is 1
	std::cout << "b is " << x.b << std::endl; // b is 2
}

int test_friend11()
{
	ONE xobj;
	TWO yobj;
	yobj.print(xobj);

	return 0;
}

//
class MyClass_
{
	// Declare a friend class
	friend class SecondClass;

public:
	MyClass_() : Secret(0){}
	void printMember()
	{
		std::cout << Secret << std::endl;
	}
private:
	int Secret;
};

class SecondClass
{
public:
	void change(MyClass_& yourclass, int x)
	{
		yourclass.Secret = x;
	}
};

int test_friend12()
{
	MyClass_ my_class;
	SecondClass sec_class;
	my_class.printMember(); // 0
	sec_class.change(my_class, 5);
	my_class.printMember(); // 5

	return 0;
}

///
// reference: http://www.learncpp.com/cpp-tutorial/813-friend-functions-and-classes/
// A function can be a friend of more than one class at the same time.
class Humidity;

class Temperature
{
private:
	int m_temp;
public:
	Temperature(int temp = 0) { m_temp = temp; }

	void setTemperature(int temp) { m_temp = temp; }

	friend void printWeather(const Temperature &temperature, const Humidity &humidity);
};

class Humidity
{
private:
	int m_humidity;
public:
	Humidity(int humidity = 0) { m_humidity = humidity; }

	void setHumidity(int humidity) { m_humidity = humidity; }

	friend void printWeather(const Temperature &temperature, const Humidity &humidity);
};

void printWeather(const Temperature &temperature, const Humidity &humidity)
{
	std::cout << "The temperature is " << temperature.m_temp <<      // 12
		" and the humidity is " << humidity.m_humidity << '\n'; // 10
}

int test_friend13()
{
	Humidity hum(10);
	Temperature temp(12);

	printWeather(temp, hum);

	return 0;
}


class Storage
{
private:
	int m_nValue;
	double m_dValue;
public:
	Storage(int nValue, double dValue)
	{
		m_nValue = nValue;
		m_dValue = dValue;
	}

	// Make the Display class a friend of Storage
	friend class Display;
};

class Display
{
private:
	bool m_displayIntFirst;

public:
	Display(bool displayIntFirst) { m_displayIntFirst = displayIntFirst; }

	void displayItem(Storage &storage)
	{
		if (m_displayIntFirst)
			std::cout << storage.m_nValue << " " << storage.m_dValue << '\n';
		else // display double first
			std::cout << storage.m_dValue << " " << storage.m_nValue << '\n';// 6.7 5
	}
};

int test_friend14()
{
	Storage storage(5, 6.7);
	Display display(false);

	display.displayItem(storage);

	return 0;
}

/
class Storage_; // forward declaration for class Storage

class Display_
{
private:
	bool m_displayIntFirst;

public:
	Display_(bool displayIntFirst) { m_displayIntFirst = displayIntFirst; }

	void displayItem(Storage_ &storage); // forward declaration above needed for this declaration line
};

class Storage_
{
private:
	int m_nValue;
	double m_dValue;
public:
	Storage_(int nValue, double dValue)
	{
		m_nValue = nValue;
		m_dValue = dValue;
	}

	// Make the Display class a friend of Storage (requires seeing the full declaration of class Display, as above)
	friend void Display_::displayItem(Storage_& storage);
};

// Now we can define Display::displayItem, which needs to have seen the full declaration of class Storage
void Display_::displayItem(Storage_ &storage)
{
	if (m_displayIntFirst)
		std::cout << storage.m_nValue << " " << storage.m_dValue << '\n';
	else // display double first
		std::cout << storage.m_dValue << " " << storage.m_nValue << '\n'; // 6.7 5
}

int test_friend15()
{
	Storage_ storage(5, 6.7);
	Display_ display(false);

	display.displayItem(storage);

	return 0;
}

GitHubhttps://github.com/fengbingchun/Messy_Test

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值