1. 友元函数的总结
a. 友元函数不是本类的成员函数,是一个外部函数
b. 友元函数的标志是在类的内部添加的外部函数声明加上friend关键字
c. 友元函数对在类内声明的位置不要求, 在public, private和protected中都可以
d. 一个类的外部函数成为友元后,访问权限被扩展了(外部函数原先只能访问类中的public部分,友元化后可以访问public, protected, private),等同于类内部的成员函数
e. 友元函数是单向的,反过来不行,友元函数是访问类内的变量的,类内部不能反过来访问友元函数内的变量
f. 友元函数就好像在类的封装和访问权限保护上打了个“洞”,所以是对面向对象的一种破坏,所以不能滥用(影响访问权限存在的意义)
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. 不能试图通过前置声明解决类成员的调用
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. 不能试图通过前置声明来定义类的对象,只能改为定义类对象的指针
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的友元函数
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)友元类的定义和使用友元类是单向的
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)两个类可以互为友元类
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 */友元类
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)除非确实有必要,否则建议按需定义友元函数,尽量维护面向对象