【C++】友元函数相关

前言:C++中对类对象私有部分的访问是被限制了的,一般来说,类的公有类方法是唯一的访问途径,但是这样的限制会影响某些特定情况下的编程(比如重载操作符时)。在这种情况下,C++提供了另一种形式的访问权限:友元。友元分为:友元函数,友元类,友元成员函数。这里先介绍友元函数,其他两种将放在另一篇博客中介绍。

一:为何需要友元
友元提供了另一种访问类对象私有部分的访问权限,通过让函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。而这在某些特殊情况下是很有帮助的,比如在重载操作符时。
在使用成员函数重载操作符时,操作符左边的对象为调用对象,意味着重载的操作符左边必须为用户定义的对象。这意味着用户必须按照:对象,操作符,其他类型数据的顺序使用重载后的操作符,限制了操作符的使用场景。
当然还有另一种选择,即使用非成员函数。非成员函数不通过对象调用,所使用的全部参数都是显式参数。这就允许了使用交换后的顺序使用重载后的操作符。但问题是非成员函数无法直接访问类的私有数据,所以可以直接访问类的私有数据的特殊非成员函数——友元函数,就体现了自身的价值。

二:如何创建友元函数
①将友元函数的原型放在类声明中,并在其前面加上关键字friend;
即:friend className operator op(argument-list);
②在类实现文件中定义友元函数,但需要注意的是因为友元函数不是成员函数,所以不要使用::限定符;同时不要在定义时使用关键字friend;
③虽然友元函数在类声明中声明,并具有和成员函数相同的访问权限,但是其不是成员函数,不能用成员函数操作符(.)来调用;

三:友元函数范例
操作符<<已经被重载过,既表示位左移,又和cout合用表示输出。而在C++中,操作符<<又常常被重载以输出类的信息,接下来将用一个范例,表示友元函数的用法以及操作符<<的重载。

//Complex.h
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include <iostream>
class Complex
{
private:
	int real; //实部
	int imaginary ; //虚部
public:
	Complex(); //默认构造函数
	Complex(int re,int im); //显式构造函数
	Complex operator*(int n)const;
	friend Complex operator*(int n,Complex & co); //声明友元函数 
	friend void operator<<(std::ostream & os, const Complex & c); //由于cout<<class这个形式使用两个对象,
	                                                        //第一个对象是ostream对象(cout),故这里使用ostream类引用os 
};
#endif

//Complex.cpp
#include <iostream>
#include "Complex.h"

Complex::Complex()
{
	real = imaginary = 0;
}

Complex::Complex(int re,int im)
{
	real = re;
	imaginary = im;
}

Complex Complex::operator*(int n)const
{
	Complex c; 
	c.real = real * n;  
	c.imaginary = imaginary * n;
	return c; 	
}
//接下来的两个友元函数均不要使用限定符::
Complex operator*(int n,Complex & co)
{
	Complex c; 
	c.real = co.real * n;  
	c.imaginary = co.imaginary * n;
	return c; 
}

void operator<<(std::ostream & os, const Complex & c)
{
	os<<c.real<<" + "<<c.imaginary<<"i"<<std::endl;
}

//User.cpp
#include <iostream>
#include "Complex.h"

int main(){
	using std::cout;
	Complex number1(1,2); //使用显式构造函数 
	cout<<number1;  //使用重载后的操作符<<输出
	number1 = 4 * number1;//使用友元函数进行乘法
	cout<<number1;
	number1 = number1 * 4;
	cout<<number1;
	return 0;
}

运行程序以后,结果正确:
在这里插入图片描述
上述代码已经显示了友元函数的定义和使用方法,但是操作符<<的重载却留有一点疑问,那就是cout能不能连续多次输出呢?在User.cpp文件中修改代码:

#include <iostream>
#include "Complex.h"

int main(){
	using std::cout;
	Complex number1(1,2); //使用显式构造函数 
	Complex number2; //使用默认构造函数 
	cout<<number1;
	number1 = 4 * number1;
	cout<<number1;
	number2 = number1 * 4;
	cout<<"number1 = "<<number1<<" number2 = "<<number2;
	return 0;
}

运行代码,发出报错:
在这里插入图片描述
找到报错点,发现问题在:
在这里插入图片描述
究其原因,是因为友元函数的返回值类型是void,而下一次操作符<<调用时应该使用的是ostream对象,所以更改原程序:

//Complex.h
#ifndef COMPLEX_H_
#define COMPLEX_H_
#include <iostream>
class Complex
{
private:
	int real; //实部
	int imaginary ; //虚部
public:
	Complex(); //默认构造函数
	Complex(int re,int im); //显式构造函数
	Complex operator*(int n)const;
	friend Complex operator*(int n,Complex & co); //声明友元函数 
	friend std::ostream & operator<<(std::ostream & os, const Complex & c); //由于cout<<class这个形式使用两个对象,
	                                                        //第一个对象是ostream对象(cout),故这里使用ostream类引用os 
};
#endif


//Complex.cpp
#include <iostream>
#include "Complex.h"

Complex::Complex()
{
	real = imaginary = 0;
}

Complex::Complex(int re,int im)
{
	real = re;
	imaginary = im;
}

Complex Complex::operator*(int n)const
{
	Complex c; 
	c.real = real * n;  
	c.imaginary = imaginary * n;
	return c; 	
}

Complex operator*(int n,Complex & co)
{
	Complex c; 
	c.real = co.real * n;  
	c.imaginary = co.imaginary * n;
	return c; 
}

std::ostream & operator<<(std::ostream & os, const Complex & c)
{
	os<<c.real<<" + "<<c.imaginary<<"i"<<std::endl;
	return os;
}

//User.cpp
#include <iostream>
#include "Complex.h"

int main(){
	using std::cout;
	Complex number1(1,2); //使用显式构造函数 
	Complex number2; //使用默认构造函数 
	cout<<number1;
	number1 = 4 * number1;
	cout<<number1;
	number2 = number1 * 4;
	cout<<"number1 = "<<number1<<"number2 = "<<number2;
	return 0;
}

运行程序,结果正确:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值