{"id":"58954457","type":"page","status":"current","title":"05.友元","version":{"by":{"type":"known","username":"ethanliu","userKey":"2c90931b6cfb654f016d5c69becc0001","profilePicture":{"path":"/images/icons/profilepics/default.svg","width":48,"height":48,"isDefault":true},"displayName":"刘浩","_links":{"self":"https://wiki.suncaper.net/rest/api/user?key=2c90931b6cfb654f016d5c69becc0001"},"_expandable":{"status":""}},"when":"2022-07-09T01:51:24.000Z","message":"","number":1,"minorEdit":false,"hidden":false,"_links":{"self":"https://wiki.suncaper.net/rest/experimental/content/58954457/version/1"},"_expandable":{"content":"/rest/api/content/58954457"}},"body":{"storage":{"value":"<ac:layout><ac:layout-section ac:type=\"two_right_sidebar\"><ac:layout-cell><h2><span>4.5 </span>友元</h2><p>类的主要特点之一是数据隐藏，即类的私有成员无法在类的外部<span>(</span>作用域之外<span>)</span>访问。但是，有时候需要在类的外部访问类的私有成员，怎么办？</p><p>解决方法是使用友元函数，友元函数是一种特权函数，<span>c++</span>允许这个特权函数访问私有成员。这一点从现实生活中也可以很好的理解：</p><p>比如你的家，有客厅，有你的卧室，那么你的客厅是<span>Public</span>的，所有来的客人都可以进去，但是你的卧室是私有的，也就是说只有你能进去，但是呢，你也可以允许你的闺蜜好基友进去。</p><p>程序员可以把一个全局函数、某个类中的成员函数、甚至整个类声明为友元。</p><h3><span>4.5.1 </span>友元语法</h3><ul><li>friend关键字只出现在声明处</li><li>其他类、类成员函数、全局函数都可声明为友元</li><li>友元函数不是类的成员，不带<span>this</span>指针</li><li>友元函数可访问对象任意成员属性，包括私有属性</li></ul><ac:structured-macro ac:name=\"code\" ac:schema-version=\"1\" ac:macro-id=\"aaa2d567-4d7c-48e8-af7d-361239d5af64\"><ac:parameter ac:name=\"language\">cpp</ac:parameter><ac:plain-text-body><![CDATA[class Building;\n//友元类\nclass MyFriend{\npublic:\n\t//友元成员函数\n\tvoid LookAtBedRoom(Building& building);\n\tvoid PlayInBedRoom(Building& building);\n};\nclass Building{\n\t//全局函数做友元函数\n\tfriend void CleanBedRoom(Building& building);\n#if 0\n\t//成员函数做友元函数\n\tfriend void MyFriend::LookAtBedRoom(Building& building);\n\tfriend void MyFriend::PlayInBedRoom(Building& building);\n#else\t\n\t//友元类\n\tfriend class MyFriend;\n#endif\npublic:\n\tBuilding();\npublic:\n\tstring mSittingRoom;\nprivate:\n\tstring mBedroom;\n};\n\nvoid MyFriend::LookAtBedRoom(Building& building){\n\tcout << \"我的朋友参观\" << building.mBedroom << endl;\n}\nvoid MyFriend::PlayInBedRoom(Building& building){\n\tcout << \"我的朋友玩耍在\" << building.mBedroom << endl;\n}\n\n//友元全局函数\nvoid CleanBedRoom(Building& building){\n\tcout << \"友元全局函数访问\" << building.mBedroom << endl;\n}\n\nBuilding::Building(){\n\tthis->mSittingRoom = \"客厅\";\n\tthis->mBedroom = \"卧室\";\n}\n\nint main(){\n\n\tBuilding building;\n\tMyFriend myfriend;\n\n\tCleanBedRoom(building);\n\tmyfriend.LookAtBedRoom(building);\n\tmyfriend.PlayInBedRoom(building);\n\n\tsystem(\"pause\");\n\treturn EXIT_SUCCESS;\n}]]></ac:plain-text-body></ac:structured-macro><p><span> </span></p><table class=\"wrapped\"><colgroup><col /></colgroup><tbody><tr><td><p><span>    </span><strong>[</strong><strong>友元类注意<span>]</span></strong></p><p>1．友元关系不能被继承。</p><p>2．友元关系是单向的，类<span>A</span>是类<span>B</span>的朋友，但类<span>B</span>不一定是类<span>A</span>的朋友。</p><p>3．友元关系不具有传递性。类<span>B</span>是类<span>A</span>的朋友，类<span>C</span>是类<span>B</span>的朋友，但类<span>C</span>不一定是类<span>A</span>的朋友。</p></td></tr></tbody></table><p><strong>思考<span>: c++</span>是纯面向对象的吗？</strong></p><table class=\"wrapped\"><colgroup><col /></colgroup><tbody><tr><td><p>如果一个类被声明为<span>friend,</span>意味着它不是这个类的成员函数，却可以修改这个类的私有成员，而且必须列在类的定义中，因此他是一个特权函数。<span>c++</span>不是完全的面向对象语言，而只是一个混合产品。增加<span>friend</span>关键字只是用来解决一些实际问题，这也说明这种语言是不纯的。毕竟<span>c++</span>设计的目的是为了实用性，而不是追求理想的抽象。</p><p>                                                       --- Thinking in C++</p></td></tr></tbody></table><h3><span>4.5.2 </span>课堂练习</h3><table class=\"wrapped\"><colgroup><col /></colgroup><tbody><tr><td><p>请编写电视机类，电视机有开机和关机状态，有音量，有频道，提供音量操作的方法，频道操作的方法。由于电视机只能逐一调整频道，不能指定频道，增加遥控类，遥控类除了拥有电视机已有的功能，再增加根据输入调台功能。</p></td></tr></tbody></table></ac:layout-cell><ac:layout-cell><p><br /></p></ac:layout-cell></ac:layout-section></ac:layout>","representation":"storage","_expandable":{"content":"/rest/api/content/58954457"}},"_expandable":{"editor":"","view":"","export_view":"","styled_view":"","anonymous_export_view":""}},"extensions":{"position":"none"},"_links":{"webui":"/pages/viewpage.action?pageId=58954457","edit":"/pages/resumedraft.action?draftId=58954457","tinyui":"/x/2ZKDAw","collection":"/rest/api/content","base":"https://wiki.suncaper.net","context":"","self":"https://wiki.suncaper.net/rest/api/content/58954457"},"_expandable":{"container":"/rest/api/space/2CT","metadata":"","operations":"","children":"/rest/api/content/58954457/child","restrictions":"/rest/api/content/58954457/restriction/byOperation","history":"/rest/api/content/58954457/history","ancestors":"","descendants":"/rest/api/content/58954457/descendant","space":"/rest/api/space/2CT"}}