C++友元函数

  此文整理自C++_友元函数模板友元

  1. 引入友元函数原因

    在实现类之间数据共享时,减少系统开销,提高效率。

        具体来说:为了使其他类的成员函数直接访问该类的私有变量。

        即:允许外面的类或函数去访问类的私有变量和保护变量,从而使两个类共享同一函数。

        优点:能够提高效率,表达简单、清晰。

        缺点:友元函数破环了封装机制,尽量不使用友元函数,除非不得已的情况下才使用友元函数。

  2. 使用友元函数时机

        1)运算符重载的某些场合需要使用友元。

        2)两个类要共享数据的时候

  3. 如何使用友元函数

   3.1 友元函数的参数

     因为友元函数没有this指针,则参数要有三种情况:

        1)要访问非static成员时,需要对象做参数;--常用(友元函数常含有参数)

        2)要访问static成员或全局变量时,则不需要对象做参数

        3)如果做参数的对象是全局对象,则不需要对象做参数

   3.2 友元函数的位置

    因为友元函数是类外的函数,所以它的声明可以放在类的私有段或公有段且两者没有区别。

   3.3 友元函数的调用

    可以直接调用友元函数,不需要通过对象或指针。

   3.4 友元函数的分类

    根据这个函数的来源不同,可以分为三种方法:

  3.4.1 普通函数友元函数

        1)目的:使普通函数能够访问类的友元

        2)语法:

      声明位置:公有私有均可,常写为公有

      声明: friend + 普通函数声明

      实现位置:可以在类外或类中

      实现代码:与普通函数相同(不加不用friend和类::)

      调用:类似普通函数,直接调用

         3)示例代码:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class Example
 6 {
 7 public:
 8     Example(const int val = 0) : num(val){};
 9     virtual ~Example() {};
10     friend void display(const Example& exam);
11 
12 private:
13     int num;
14 
15 };
16 
17 void display(const Example& exam)
18 {
19     cout << exam.num << endl;
20 }
21 
22 void main()
23 {
24     Example example(10);
25     display(example);
26 }
View Code

  3.4.2 类Y的所有成员函数都为类X友元函数—友元类

        1)目的:使用单个声明使Y类的所有函数成为类X的友元

            它提供一种类之间合作的一种方式,使类Y的对象可以具有类X和类Y的功能

             具体来说:

                前提:A是B的友元(=》A中成员函数可以访问B中有所有成员,包括私有成员和公有成员)

                则:在A中,借助类B,可以直接使用“B . 私有变量”的形式访问私有变量

        2)语法:

      声明位置:公有私有均可,常写为私有(把类看成一个变量)

             声明: friend + 类名---不是对象啊

             调用:

        3)示例代码:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class Boy;
 6 class Girl
 7 {
 8 public:
 9     Girl(){ name = "Lucy"; age = 18; };
10     virtual ~Girl(){};
11 
12 private:
13     char * name;
14     int age;
15     friend Boy;   //声明类Boy是类Girl的友元  
16 
17 };
18 
19 class Boy
20 {
21 public:
22     Boy(){ name = "Jimmy"; age = 20; };
23     virtual ~Boy(){};
24     void display(Girl& girl);
25 
26 private:
27     char * name;
28     int age;
29 
30 };
31 
32 void Boy::display(Girl& girl) //函数disp()为类Boy的成员函数,也是类Girl的友元函数 
33 {
34     //正常情况,Boy的成员函数disp中直接访问Boy的私有变量
35     cout << "Boy's name is: " << name << ", age: " << age << "." << endl;
36 
37     //借助友元,在Boy的成员函数disp中,借助Girl的对象,直接访问Girl的私有变量
38     //而正常情况下,只允许在Girl的成员函数中访问Girl的私有变量
39     cout << "Girl's name is: " << girl.name << ", age: " << girl.age << "." << endl;
40 
41 }
42 
43 
44 int main()
45 {
46     Boy boy;
47     Girl girl;
48     boy.display(girl);  //b调用自己的成员函数,但是以girl为参数,友元机制体现在函数display中
49 
50     return 0;
51 }
View Code

  3.4.3 类Y的一个成员函数为类X的友元函数

        1)目的:使类Y的一个成员函数成为类X的友元

             具体而言:而在类Y的这个成员函数中,借助参数X,可以直接以X。私有变量的形式访问私有变量

        2)语法:

      声明位置:声明在公有中 (本身为函数)

      声明:friend + 成员函数的声明

      调用:先定义Y的对象y---使用y调用自己的成员函数---自己的成员函数中使用了友元机制

        3)示例代码:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 
 5 class Girl;
 6 class Boy
 7 {
 8 public:
 9     Boy(){ name = "Jimmy"; age = 20; };
10     virtual ~Boy(){};
11     void display(Girl& girl);
12 
13 private:
14     char * name;
15     int age;
16 
17 };
18 
19 class Girl
20 {
21 public:
22     Girl(){ name = "Lucy"; age = 18; };
23     virtual ~Girl(){};
24 
25 private:
26     char * name;
27     int age;
28     friend void Boy::display(Girl& girl);   //声明类Boy的成员函数是类Girl的友元函数
29 
30 };
31 
32 //函数display()为类Boy的成员函数,也是类Girl的友元函数 
33 void Boy::display(Girl& girl)
34 {
35     //正常情况,Boy的成员函数disp中直接访问Boy的私有变量
36     cout << "Boy's name is: " << name << ", age: " << age << "." << endl;
37 
38     //借助友元,在Boy的成员函数disp中,借助Girl的对象,直接访问Girl的私有变量
39     //而正常情况下,只允许在Girl的成员函数中访问Girl的私有变量
40     cout << "Girl's name is: " << girl.name << ", age: " << girl.age << "." << endl;
41 
42 }
43 
44 int main()
45 {
46     Boy boy;
47     Girl girl;
48     boy.display(girl);  //b调用自己的成员函数,但是以girl为参数,友元机制体现在函数display中
49 
50     return 0;
51 }
View Code

  4. 模板友元函数

  在微软官方网站,有一个例子是用来说明如何建立模板友元的。下边是

   4.1 模板友元函数

  例子:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 template <class T> class Array {
 5     T* array;
 6     int size;
 7 
 8 public:
 9     Array(int sz) : size(sz) {
10         array = new T[size];
11         memset(array, 0, size * sizeof(T));
12     }
13 
14     Array(const Array& a) {
15         size = a.size;
16         array = new T[size];
17         memcpy_s(array, a.array, sizeof(T));
18     }
19 
20     T& operator[](int i) {
21         return *(array + i);
22     }
23 
24     int Length() { return size; }
25 
26     void print() {
27         for (int i = 0; i < size; i++)
28             cout << *(array + i) << " ";
29 
30         cout << endl;
31     }
32 
33     template<class T>
34     friend Array<T>* combine(Array<T>& a1, Array<T>& a2);
35 };
36 
37 template<class T>
38 Array<T>* combine(Array<T>& a1, Array<T>& a2) {
39     Array<T>* a = new Array<T>(a1.size + a2.size);
40     for (int i = 0; i < a1.size; i++)
41         (*a)[i] = *(a1.array + i);
42 
43     for (int i = 0; i < a2.size; i++)
44         (*a)[i + a1.size] = *(a2.array + i);
45 
46     return a;
47 }
48 
49 int main() {
50     Array<char> alpha1(26);
51     for (int i = 0; i < alpha1.Length(); i++)
52         alpha1[i] = 'A' + i;
53 
54     alpha1.print();
55 
56     Array<char> alpha2(26);
57     for (int i = 0; i < alpha2.Length(); i++)
58         alpha2[i] = 'a' + i;
59 
60     alpha2.print();
61     Array<char>*alpha3 = combine(alpha1, alpha2);
62     alpha3->print();
63     delete alpha3;
64 }
template_friend 

  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
  a b c d e f g h i j k l m n o p q r s t u v w x y z
  A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z  

  这个例子中,比较值得注意的是在类中声明模板友元函数部分:

1 template<class T>
2 friend Array<T>* combine(Array<T>& a1, Array<T>& a2);

  template<class T>这一句不可丢。友元函数的定义为:

template<class T>
Array<T>* combine(Array<T>& a1, Array<T>& a2) {
    Array<T>* a = new Array<T>(a1.size + a2.size);
    for (int i = 0; i < a1.size; i++)
        (*a)[i] = *(a1.array + i);

    for (int i = 0; i < a2.size; i++)
        (*a)[i + a1.size] = *(a2.array + i);

    return a;
}

   4.2 模板友元类

  例子:

 1 // template_friend3.cpp
 2 // compile with: /EHsc
 3 #include <iostream>
 4 using namespace std;
 5 
 6 template <class T>
 7 class X
 8 {
 9 private:
10     T* data;
11     void InitData(int seed) { data = new T(seed); }
12 public:
13     void print() { cout << *data << endl; }
14     template <class U> friend class Factory;
15 };
16 
17 template <class U>
18 class Factory
19 {
20 public:
21     U* GetNewObject(int seed)
22     {
23         U* pu = new U;
24         pu->InitData(seed);
25         return pu;
26     }
27 };
28 
29 int main()
30 {
31     Factory< X<int> > XintFactory;
32     X<int>* x1 = XintFactory.GetNewObject(65);
33     X<int>* x2 = XintFactory.GetNewObject(97);
34 
35     Factory< X<char> > XcharFactory;
36     X<char>* x3 = XcharFactory.GetNewObject(65);
37     X<char>* x4 = XcharFactory.GetNewObject(97);
38     x1->print();
39     x2->print();
40     x3->print();
41     x4->print();
42 }
template_friend2

  65
  97
  A
  a

  5. 其他知识点

    1)友元函数和类的成员函数的区别:成员函数有this指针,而友元函数没有this指针。

    2)A是B的友元《=》A是B的朋友《=》借助B的对象,在A中可以直接通过“B.成员变量”(可以是公有,也可以为私有变量) 的方式访问B。

原文地址:https://www.cnblogs.com/xiehongfeng100/p/4044291.html