C++的友元函数和友元类(一)

1. 友元函数的总结

a. 友元函数不是本类的成员函数,是一个外部函数

b. 友元函数的标志是在类的内部添加的外部函数声明加上friend关键字

c. 友元函数对在类内声明的位置不要求, 在public, private和protected中都可以

d. 一个类的外部函数成为友元后,访问权限被扩展了(外部函数原先只能访问类中的public部分,友元化后可以访问public, protected, private),等同于类内部的成员函数

e. 友元函数是单向的,反过来不行,友元函数是访问类内的变量的,类内部不能反过来访问友元函数内的变量

f. 友元函数就好像在类的封装和访问权限保护上打了个“洞”,所以是对面向对象的一种破坏,所以不能滥用(影响访问权限存在的意义)

C++的友元函数和友元类(一)
 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Person
 7 {
 8 private:
 9     int age;
10 protected:
11     int height;
12 public:    
13     string name;
14     
15     Person(){}; // 空构造函数(函数构造,函数体都写在里面了)
16     Person(int age, int height, string name); //构造函数
17     friend void disp_info(Person& pn);//这里不声明友元函数,后面访问private和protected报错
18 };
19 
20 Person::Person(int age, int height, string name)
21 {
22     this->age = age;
23     this->height = height;
24     this->name = name;
25 }
26 
27 void disp_info(Person& pn)
28 {
29     cout << "name = " << pn.name << endl;
30     cout << "age = " << pn.age << endl;
31     cout << "name = " << pn.height << endl;
32 }
33 
34 int main(void)
35 {
36     Person p1(33, 173, "Nancy");
37     disp_info(p1);
38     
39     return 0;
40 }
41 
42 /*
43 输出结果:
44 name = Nancy
45 age = 33
46 name = 173
47 */
友元函数示例

 

2. 友元函数的2种实现

2.1. 友元函数的2种实现

(1)友元函数是外部函数

(2)友元函数是另一个类中的成员函数(也叫友元成员,友元成员方法,友元成员函数)

 

2.2. 类的前置声明

a. 两个类互相引用时会出现未定义的错误,这时可以用类的前置声明来解决

b. 前置声明中不包括类的详细信息,所以编译器无法得到前置声明类的size,成员等详细信息

c. 不能试图通过前置声明解决类成员的调用

C++的友元函数和友元类(一)
 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Animal;
 7 
 8 class Person
 9 {
10 private:
11     int age;
12 protected:
13     int height;
14 public:    
15     string name;
16     
17     Person(){}; // 空构造函数(函数构造,函数体都写在里面了)
18     Person(int age, int height, string name); //构造函数
19     friend void Animal :: animal(Person& pn);
20 };
21 
22 class Animal
23 {
24 public:
25     void animal(Person& pn);
26 };
27 
28 void Animal :: animal(Person& pn)
29 {
30     cout << "Person name = " << pn.name << endl;
31     cout << "Person age = " << pn.age << endl;
32     cout << "Person height = " << pn.height << endl;
33 }
34 
35 Person::Person(int age, int height, string name)
36 {
37     this->age = age;
38     this->height = height;
39     this->name = name;
40 }
41 
42 int main(void)
43 {
44     Person p1(33, 173, "Nancy");
45     Animal a1;
46     a1.animal(p1);
47     
48     return 0;
49 }
50 
51 /*
52 输出结果:
53 报错
54 invalid use of incomplete type ‘class Animal’
55 */
类的前置声明错误用法

 

d. 不能试图通过前置声明来定义类的对象,只能改为定义类对象的指针

C++的友元函数和友元类(一)
 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 //class Animal;
 7 class Person;
 8 
 9 class Animal
10 {
11 public:
12     void animal(Person& pn);
13 };
14 
15 class Person
16 {
17 private:
18     int age;
19 protected:
20     int height;
21 public:    
22     string name;
23     
24     Person(){}; // 空构造函数(函数构造,函数体都写在里面了)
25     Person(int age, int height, string name); //构造函数
26     friend void Animal :: animal(Person& pn);
27 };
28 
29 
30 
31 void Animal :: animal(Person& pn)
32 {
33     cout << "Person name = " << pn.name << endl;
34     cout << "Person age = " << pn.age << endl;
35     cout << "Person height = " << pn.height << endl;
36 }
37 
38 Person::Person(int age, int height, string name)
39 {
40     this->age = age;
41     this->height = height;
42     this->name = name;
43 }
44 
45 int main(void)
46 {
47     Person p1(33, 173, "Nancy");
48     Animal a1;
49     a1.animal(p1);
50     
51     return 0;
52 }
53 
54 /*
55 输出结果:
56 Person name = Nancy
57 Person age = 33
58 Person height = 173
59 */
类的前置声明正确用法

 

在这个例子中获得前置声明后可以先定义类对象的指针,编译器可以先不检查这个类的细节从而可以通过编译

 

2.3. 总结

设计多个类的体系时,尽量设计好层次关系为单向的(树形结构),尽量避免互相引用的情况

 

3. 友元类

3.1. 友元类的概念

(1)将A声明为B的friend class后,则A中所有成员函数都成为了类B的友元函数

 

C++的友元函数和友元类(一)
 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Person;
 7 
 8 class Animal
 9 {
10 public:
11     void animal(Person& pn);
12     void animal2(Person& pn);
13 };
14 
15 class Person
16 {
17 private:
18     int age;
19 protected:
20     int height;
21 public:    
22     string name;
23     
24     Person(){}; // 空构造函数(函数构造,函数体都写在里面了)
25     Person(int age, int height, string name); //构造函数
26     //friend void Animal :: animal(Person& pn);
27     friend class Animal;
28 };
29 
30 void Animal :: animal(Person& pn)
31 {
32     cout << "Person name = " << pn.name << endl;
33     cout << "Person age = " << pn.age << endl;
34     cout << "Person height = " << pn.height << endl;
35 }
36 
37 void Animal :: animal2(Person& pn)
38 {
39     cout << "Person name = " << pn.name << endl;
40     cout << "Person age = " << pn.age << endl;
41     cout << "Person height = " << pn.height << endl;
42 }
43 
44 Person::Person(int age, int height, string name)
45 {
46     this->age = age;
47     this->height = height;
48     this->name = name;
49 }
50 
51 int main(void)
52 {
53     Person p1(33, 173, "Nancy");
54     Animal a1;
55     a1.animal(p1);
56     a1.animal2(p1);
57     
58     return 0;
59 }
60 
61 /*
62 输出结果:
63 Person name = Nancy
64 Person age = 33
65 Person height = 173
66 Person name = Nancy
67 Person age = 33
68 Person height = 173
69 */
友元类示例

 

(2)友元类的定义和使用友元类是单向的

 

C++的友元函数和友元类(一)
 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Person;
 7 
 8 class Animal
 9 {
10 private:
11     int size;
12 public:
13     Animal(){};
14     Animal(int size);
15     void animal(Person& pn);
16     void animal2(Person& pn);
17 };
18 
19 class Person
20 {
21 private:
22     int age;
23 protected:
24     int height;
25 public:    
26     string name;
27     
28     Person(){}; // 空构造函数(函数构造,函数体都写在里面了)
29     Person(int age, int height, string name); //构造函数
30     void disp(Animal& ani);
31     //friend void Animal :: animal(Person& pn);
32     friend class Animal;
33 };
34 
35 Animal :: Animal(int size)
36 {
37     this->size = size;
38 }
39 
40 Person :: Person(int age, int height, string name)
41 {
42     this->age = age;
43     this->height = height;
44     this->name = name;
45 }
46 
47 void Person :: disp(Animal& ani)
48 {
49     cout << "size = " << ani.size << endl;
50 }
51 
52 int main(void)
53 {
54     Animal a1(30);
55     Person p1;
56     p1.disp(a1);
57 
58     return 0;
59 }
60 
61 /*
62 输出结果:
63 报错
64 */
单个定义使用友元类是单向的

 

3.2. 互为友元类

(1)两个类可以互为友元类

 

C++的友元函数和友元类(一)
 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Person;
 7 
 8 class Animal
 9 {
10 private:
11     int size;
12 public:
13     Animal(){};
14     Animal(int size);
15     void animal(Person& pn);
16     void animal2(Person& pn);
17     friend class Person;
18 };
19 
20 class Person
21 {
22 private:
23     int age;
24 protected:
25     int height;
26 public:    
27     string name;
28     
29     Person(){}; // 空构造函数(函数构造,函数体都写在里面了)
30     Person(int age, int height, string name); //构造函数
31     void disp(Animal& ani);
32     //friend void Animal :: animal(Person& pn);
33     //friend class Animal;
34 };
35 
36 Animal :: Animal(int size)
37 {
38     this->size = size;
39 }
40 
41 Person :: Person(int age, int height, string name)
42 {
43     this->age = age;
44     this->height = height;
45     this->name = name;
46 }
47 
48 void Person :: disp(Animal& ani)
49 {
50     cout << "size = " << ani.size << endl;
51 }
52 
53 int main(void)
54 {
55     Animal a1(30);
56     Person p1;
57     p1.disp(a1);
58 
59     return 0;
60 }
61 
62 /*
63 输出结果:
64 size = 30
65 */
友元类

 

C++的友元函数和友元类(一)
 1 #include <iostream>
 2 #include <string>
 3 
 4 using namespace std;
 5 
 6 class Person;
 7 
 8 class Animal
 9 {
10 private:
11     int size;
12 public:
13     Animal(){};
14     Animal(int size);
15     void animal(Person& pn);
16     void animal2(Person& pn);
17     friend class Person;
18 };
19 
20 class Person
21 {
22 private:
23     int age;
24 protected:
25     int height;
26 public:    
27     string name;
28     
29     Person(){}; // 空构造函数(函数构造,函数体都写在里面了)
30     Person(int age, int height, string name); //构造函数
31     void disp(Animal& ani);
32     //friend void Animal :: animal(Person& pn);
33     friend class Animal;
34 };
35 
36 Animal :: Animal(int size)
37 {
38     this->size = size;
39 }
40 
41 void Animal :: animal(Person& pn)
42 {
43     cout << "Person name = " << pn.name << endl;
44     cout << "Person age = " << pn.age << endl;
45     cout << "Person height = " << pn.height << endl;
46 }
47 
48 Person :: Person(int age, int height, string name)
49 {
50     this->age = age;
51     this->height = height;
52     this->name = name;
53 }
54 
55 void Person :: disp(Animal& ani)
56 {
57     cout << "size = " << ani.size << endl;
58 }
59 
60 int main(void)
61 {
62     Animal a1(30);
63     Person p1(35, 180, "Jake");
64     p1.disp(a1);
65     a1.animal(p1);
66     
67     return 0;
68 }
69 
70 /*
71 输出结果:
72 size = 30
73 Person name = Jake
74 Person age = 35
75 Person height = 180
76 */
互为友元类

 

(2)互为友元类要注意互相引用的细节

 

3.3 友元类的总结

(1)友元类就是批量制造友元函数

(2)友元类中所有全部成员都成为了友元函数,相当于打了很多洞,极大地破坏了面向对象

(3)除非确实有必要,否则建议按需定义友元函数,尽量维护面向对象

上一篇:element ui table(表格)点击一行展开


下一篇:Java 抽象类和接口