1. 友元的概念引入
C++的最重要的特点之一就是封装性和继承性。对于类的封装性来说,就是类的私有成员和保护成员只能在设计类时它所定义的函数内使用,即私有成员和保护成员只能通过该类的成员函数来访问。
当我们需要在类的外部访问该类的私有成员和保护成员时,就可以利用友元(friend)来实现这一操作。
2.友元的分类
2.1类的非成员函数友元
类的非成员函数友元:
表示友元函数不是当前类的成员函数,而是独立于当前类的外部函数,但是他可以访问该类的所有成员(私有成员,保护成员,公有成员)。
注意:
(1)非成员函数友元虽然可以访问类的私有成员和保护成员,但是他不是该类的成员函数。所以,在外部定义友元函数时,需要在函数名前加上"类名::"。
(2)因为非成员函数友元不是类的成员函数,没有this指针来访问对象的数据成员,不能直接访问对象的数据成员,他必须通过作为入口参数传递进来的对象(引用)来访问该对象的数据成员。例如:void fun(Object &obj)中的形参obj是Object类的对象的引用。
这里给出代码示例和测试结果:
//类的非成员函数友元
class Object
{
int value;
public:
Object(int x = 0):value(x){ }//构造函数
~Object(){}//析构函数
void Print()
{
cout << "value:" << value << endl;
}
friend void fun(Object& obj);//函数友元
//friend void fun是外部函数
};
class Test :public Object
{
private:
int num;
};
void fun(Object &obj)
{
obj.value = 100;//设计该函数为友元函数
cout << "fun::value:" << obj.value << endl;
}
int main()
{
Object obj(10);
obj.Print();
fun(obj);
return 0;
}
2.2类的成员函数友元
类的成员函数友元:
表示友元函数在类中声明,不仅可以访问自己所在类对象中的私有成员和公有成员,还可以访问friend声明语句所在类对象中的所有成员。
注意:
(1)一个类的成员函数作为另一个类的友元函数,必须先定义这个类。
这里给出代码示例和测试结果
//类的成员函数友元
class Base;
class Object
{
int value;
public:
Object(int x = 0) :value(x) {}
~Object() {}
void Print()
{
cout << "Object::value " << value << endl;
}
void func(Base& base);
};
class Base :public Object
{
private:
int num;
public:
Base(int x=0):num(x){}
void Print()
{
cout << "Base::num " << num << endl;
}
friend void Object::func(Base& base);
};
void Object::func(Base& base)
{
value = 200;
base.num = 100;
cout << "func::Object:value " << value << endl;
cout << "func::Base:num " << base.num << endl;
}
int main()
{
Object obj(10);
Base base(0);
obj.Print();
base.Print();
obj.func(base);
return 0;
}
2.3类友元
一个类也可以作为另一个类的友元,称为类友元。类友元的说明方法是在另一个类声明中加入语句。这条语句可以放在公有部分也可以放在私有部分。
本示例中 friend class Object; 意思是:声明类Object为类Base的友元类。
这里给出代码示例和测试结果
//类友元
class Base;
class Object
{
int value;
public:
Object(int x = 0) :value(x) {}
~Object() {}
void Print()
{
cout << "Object::value " << value << endl;
}
void func(Base& base);
};
class Base :public Object
{
friend class Object;//Object对象里面的所有方法都能访问Base里面的私有属性
private:
int num;
public:
Base(int x = 0) :num(x) {}
void Print()
{
cout << "Base::num " << num << endl;
}
};
void Object::func(Base& base)
{
base.num = 100;
value = 200;
cout << "Object::func: num " << base.num << endl;
cout << "Object::func:value " << value << endl;
}
int main()
{
Object obj(10);
Base base(0);
obj.Print();
base.Print();
obj.func(base);
return 0;
}
3.友元的特点
不具有自反性(是单向的,fun是Object的友元,但是Object不是fun的友元)
不具有继承性
不具有传递性
友元说明
友元是对类的封装性的补充,利用这一点,一个类可以赋予某些函数访问它的私有成员和保护成员的特权。
声明了一个类的友元函数,就可以用这个函数直接访问该类的私有成员和保护成员,从而提高程序运行的效率。
如果没有友元,外部函数访问类的私有数据,必须通过调用公有的成员函数,这会降低程序的运行效率。
友元提供了不同类的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制。尤其是当一个函数需要访问多个类时,友元函数非常有用,普通的成员函数只能访问其所属的类,但是多个类的友元函数能够访问相关的所有类的数据。