c++友元函数一些见解
1、为什么要引入友元函数:在实现类之间数据共享时,减少系统开销,提高效率
具体来说:为了使其他类的成员函数直接访问该类的私有变量
即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数
优点:能够提高效率,表达简单、清晰
缺点:友元函数破环了封装机制,尽量不使用成员函数,除非不得已的情况下才使用友元函数。
2、什么时候使用友元函数:
1)运算符重载的某些场合需要使用友元。
2)两个类要共享数据的时候
3、怎么使用友元函数:
友元函数的参数:
因为友元函数没有this指针,则参数要有三种情况:
1、 要访问非static成员时,需要对象做参数;--常用(友元函数常含有参数)
2、 要访问static成员或全局变量时,则不需要对象做参数
3、 如果做参数的对象是全局对象,则不需要对象做参数
友元函数的位置:
因为友元函数是类外的函数,所以它的声明可以放在类的私有段或公有段且没有区别。
友元函数的调用:
可以直接调用友元函数,不需要通过对象或指针
- 普通的友元函数
#include<iostream>
using namespace std;
class Date
{
friend ostream& operator<<(ostream& _cout, const Date& d);
public:
Date(int year, int mouth, int day)
:_year(year)
, _mouth(mouth)
, _day(day)
{}
private:
int _year;
int _mouth;
int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << ":" << d._mouth << ":" << d._day << endl;
return _cout;
}
int main()
{
Date d(2018, 11, 2);
cout << d << endl;
return 0;
}
- 上面的代码我重载了 << 运算符。这里必须放在类外来定义,如果放在类中来定义的话,我的主函数中 cout<< d<< endl 只能这样写了:d<<cout<<endl;
- 为什么呢?来看看下面代码。
- 我的定义写在类中,那么会出现什么情况呢?操作符 << 只需要传两个参数,那么在类中这样定义就会传了三个参数,不要this 指针哦。有人说,那不传 ostream& _cout 不就好了,啊哈,行啊,那么第一个参数就是const Date& d。最后调用的就要是 d<<cout;这样子了。所以友元函数是必须的。
class Date
{
ostream& operator<<(ostream& _cout, const Date& d)
{
_cout << d._year << ":" << d._mouth << ":" << d._day << endl;
return _cout;
}
public:
Date(int year, int mouth, int day)
:_year(year)
, _mouth(mouth)
, _day(day)
{}
private:
int _year;
int _mouth;
int _day;
};
总结:友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
问题1:友元函数能不能用const修饰?
回答:不能,在类中,const 修饰函数是修饰函数的什么?当然是类函数中的this指针了,那么友元函数有没有this指针呢?当然没有this指针了,所以友元函数不能用const修饰。
友元函数可访问类的私有成员,是不是类的成员函数?
回答:不是,可以这样理解,友元函数是类的好朋友,那么类中的私有成员我允许我的朋友来访问。
友元函数需要放在类的那里来声明呢?public?private?还是?
回答:友元函数可以在类定义的任何地方声明,不受类访问限定符限制
函数A是类A的友元函数,那么函数还能是类B 的友元函数呢?
回答:你肯定不止一个朋友吧。一个函数可以是多个类的友元函数。
除了友元函数,还有友元类。
c++.h
#include<iostream>
using namespace std;
class Date
{
friend class Time;
public:
Date(int,int,int);
void Print();
private:
int _year;
int _mouth;
int _day;
};
class Time
{
friend class Date;
public:
Time(int ,int ,int);
void Print();
private:
int _hour;
int _minut;
int _second;
};
c++.cpp
#include<iostream>
#include"c++.h"
using namespace std;
Date::Date(int year = 1990, int mouth = 1, int day = 1)
:_year(year)
, _mouth(mouth)
, _day(day)
{}
void Date::Print()
{
Time t(11,101,10);
cout << _year << "-" << _mouth << "-" << _day << t._hour << "-" << t._minut << "-" << t._second << endl;
}
Time::Time(int hour = 11, int minut = 10, int second = 10)
:_hour(hour)
, _minut(minut)
, _second(second)
{}
void Time::Print()
{
Date d(100, 101, 102);
cout << d._year << "-" << d._mouth << "-" << d._day << _hour << "-" << _minut << "-" << _second << endl;
}
void Func()
{
Date d(100,101,102);
d.Print();
Time t(10,11,12);
t.Print();
}
int main()
{
Func();
return 0;
}
- 这个要看清楚友元函数必须要在头文件中声明,在另一个文件中来定义。为什么?你自己放在一个文件中你就知道了,我说不清楚。
- 上面的例子是个友元类,友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
注意:
- 友元的优缺点
- 优点:提高了程序运行效率
- 缺点:破坏了类的封装性和隐藏性
- 友元关系是单向的,不具有交换性。
- 比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time 类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
- 友元关系不能传递 如果B是A的友元,C是B的友元,则不能说明C时A的友元。