本文主要介绍面向对象编程的友元的使用,以及友元的特性和分类,提供C++代码。
面向对象编程(OOP)的三大特性中的封装,是通过类实现对数据的隐藏和封装。一般定义类的成员变量为私有成员,成员函数为公有函数,通过公有函数作为类的接口实现与外部交互。一些情况下,类外的某些函数需要频繁访问类的成员变量,因此引入了友元的概念,将类外的函数定义为该类的友元函数,从而实现对该类私有成员的访问。由此,还引入友元类,就是一个类是另一个类的友元类,友元类可以访问另一个类的所有成员。友元函数和友元类称为友元。
友元的作用是提高了程序的运行效率(减少了类型检查和安全检查的耗时),但是友元破坏了类的封装和隐藏性,让非类成员函数可以类的私有成员。
友元是C++语言中的一种关系,友元关系发生在函数与类之间或者类与类之间。友元关系是单向的,不能传递。
与类有友元关系的函数称为友元函数,与类有友元关系的类称为友元类。
(1)在被访问类中以friend关键字修饰友元类或者友元函数
(2)友元不属于该类,且不受该类的访问限制,可以直接访问具体类的所有成员
(3)友元关系不能被继承
(4)友元关系是单向的,不具有交换性,只能是一个函数访问一个类的所有成员,或者一个类允许访问另一个类的所有成员,反之不行
(5)友元关系不具有传递性
友元的本质是提供不属于该类成员,包括全局函数、其他类的成员函数、其他类,访问本类所有成员和成员属性的属性。
全局函数拥有访问一个类所有成员的能力,需要在被访问类中用关键字friend声明f被访问类的友元函数。一个类可以拥有多个友元函数。一个函数也可以是多个类的友元函数。
代码如下:
#include
#include
using namespace std;
class A
{
private:
string name_;
int age_;
public:
A(const string name,const int age) : name_(name), age_(age) {cout << "A构造函数 初始化参数" << endl;};
virtual ~A()
{
cout << "A析构函数 " << endl;
}
void func()
{
std::cout << "A's func()" << std::endl;
}
friend void get_members_global(A & a); // 友元全局函数,可以访问A的私有成员变量和所有的公有成员
};
// 全局函数作为友元函数
void get_members_global(A & a)
{
cout << a.name_ << " is " << a.age_ << " years old " << endl;
a.func();
}
int main()
{
A a("Hubery",45);
cout << "***************************全局函数作为友元函数***************************" << endl;
get_members_global(a);
return 0;
}
运行结果:
类成员函数作为类的友元声明时只需在友元的名称前加上关键字friend,其格式如下:
friend 类型 类名::函数名(形式参数);
一个函数可以是多个类的友元函数,只需要在各个类中分别声明。
代码如下:
#include
#include
using namespace std;
class A;
class C
{
public:
//类的成员函数作为友元函数
void get_members_member(A &a);
C()
{
cout << "C构造函数" << endl;
}
~C()
{
cout << "C析构函数" << endl;
}
};
class A
{
private:
string name_;
int age_;
public:
A(const string name,const int age) : name_(name), age_(age) {cout << "A构造函数 初始化参数" << endl;};
virtual ~A()
{
cout << "A析构函数 " << endl;
}
void func()
{
std::cout << "A's func()" << std::endl;
}
friend void C::get_members_member(A &a); // C的成员函数做友元函数,可以访问所有成员
};
// 类的成员函数作为友元函数
void C::get_members_member(A &a)
{
cout << a.name_ << " is " << a.age_ << " years old " << endl;
a.func();
}
int main()
{
A a("Hubery",45);
C c;
cout << "***************************类的成员函数作为友元函数***************************" << endl;
c.get_members_member(a);
return 0;
}
运行结果:
这里用到类的前向声明。前向声明,是一种不完全型(forward declaration)声明,即只需提供类名(无需提供类实现)即可。前向声明功能有限:
(1)不能定义类的对象。
(2)可以用于定义指向这个类型的指针或引用。
(3)用于声明(不是定义)使用该类型作为形参或者返回类型的函数。
友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。当希望一个类可以访问另一个类的私有成员、保护成员时,可以将该类声明为另一类的友元类。
定义友元类的语句格式如下:
friend class 类名;
friend和class是关键字,类名必须是程序中的一个已定义的类。
代码如下:
#include
#include
using namespace std;
class B; // 前向声明
class A
{
private:
string name_;
int age_;
public:
A(const string name,const int age) : name_(name), age_(age) {cout << "A构造函数 初始化参数" << endl;};
virtual ~A()
{
cout << "A析构函数 " << endl;
}
void func()
{
std::cout << "A's func()" << std::endl;
}
friend class B; // 声明B为A的友元类,B中成员函数可以访问A中所有的成员
};
class B
{
private:
string name_;
int age_;
public:
B(const string name,const int age) : name_(name), age_(age) {cout << "B构造函数 初始化参数" << endl;};
virtual ~B()
{
cout << "B析构函数 " << endl;
}
void func()
{
std::cout << "B's func()" << std::endl;
};
// 友元类
void get_members_class(A & a)
{
cout << a.name_ << " is " << a.age_ << " years old " << endl;
a.func();
};
};
int main()
{
A a("Hubery",45);
B b("Tom",24);
cout << "***************************友元类***************************" << endl;
b.get_members_class(a);
return 0;
}
运行结果: