Learnc www pupuol com

Page 1


â€Ťď­˜ď­˜ďť? ﺎďş&#x; ﺊďş?ﺸﺎ ďť­ ﺪﺭﺳ‏

C++ ‍ Ůˆ ŘŻŮˆ ن‏ blog version

version: 1.35 March 3, 2009

http://www.irancplusplus.blogspot.com/

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ‬

‫ﺳﺎلﻫﺎﺳﺖ ﻛﻪ ‪) C++‬ﺑﺨﻮاﻧﻴﺪ ‪ (C plus plus‬ﻳﻜﻲ از زﺑﺎنﻫﺎي ﻣﺤﺒﻮب ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ و ﺷﺎﻳﺪ ﭘﺮ ﻃﺮﻓﺪارﺗﺮﻳﻦ‬ ‫زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ اﺳﺖ‪ C++ .‬ﮔﺴﺘﺮﺷﻲ از زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ‪ C‬اﺳﺖ‪ .‬ﻳﻌﻨﻲ ﺗﻘﺮﻳﺒﺎ ﻫﺮ ﺑﺮﻧﺎﻣﻪ ‪ C‬ﻳﻚ ﺑﺮﻧﺎﻣﻪي‬ ‫‪ C++‬اﺳﺖ‪ .‬ﺷﺎﻳﺪ اﺳﻢ ‪ C#‬را ﻫﻢ‪ ،‬ﻛﻪ ‪ C Sharp‬ﺗﻠﻔﻆ ﻣﻲﺷﻮد‪ ،‬ﺷﻨﻴﺪه ﺑﺎﺷﻴﺪ‪ C# .‬ﮔﺴﺘﺮش ‪ C++‬ﻧﻴﺴﺖ وﻟﻲ‬ ‫ﺑﻪ ‪ C++‬ﺷﺒﺎﻫﺖ دارد‪.‬‬ ‫در اﻳﻦ ﻧﻮﺷﺘﻪ ﻣﻲﺧﻮاﻫﻢ ﺳﺎﺧﺘﺎر زﺑﺎن ‪ C++‬را ﺑﻪ ﺷﻜﻞ ﻓﺸﺮده ﺑﺮاي ﺷﻤﺎ ﺑﮕﻮﻳﻢ‪ .‬ﻫﺪف اﺻﻠﻲ ﻣﻦ ﻳﺎد دادن ﺗﻮاﺑﻊ‬ ‫ﻣﻮﺟﻮد در ‪header file‬ﻫﺎ ﻧﻴﺴﺖ‪ .‬درﺑﺎرهي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﺑﺮاي ‪ Windows‬ﻫﻢ ﭼﻴﺰي زﻳﺎدي ﻧﻤﻲﮔﻮﻳﻢ وﻟﻲ‬ ‫ﭼﻴﺰﻫﺎﻳﻲ ﻛﻪ اﻳﻦ ﺟﺎ ﻣﻲﮔﻮﻳﻢ ﺑﺮاي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ‪ Windows‬ﻻزم ﻫﺴﺘﻨﺪ‪ .‬ﻫﻤﻴﻦ ﻃﻮر ﻗﺼﺪ ﻧﺪارم ﺑﻪ ﻃﻮر‬ ‫ﺳﻴﺴﺘﻤﺎﺗﻴﻚ ﺑﻪ روشﻫﺎ و ﺷﮕﺮدﻫﺎي ﻣﺨﺘﻠﻒ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﺑﭙﺮدازم‪ .‬ﺷﺎﻳﺪ ﺑﻌﺪﻫﺎ در ﻳﻚ ﻧﻮﺷﺘﻪ دﻳﮕﺮ اﻳﻦ روشﻫﺎ‬ ‫را ﺑﮕﻮﻳﻢ‪ .‬وﻟﻲ اﮔﺮ واﻗﻌﺎ در ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ اﺳﺘﻌﺪاد داﺷﺘﻪ ﺑﺎﺷﻴﺪ ﺧﻴﻠﻲ از اﻳﻦ روشﻫﺎ را ﺧﻮدﺗﺎن ﭘﻴﺪا ﻣﻲﻛﻨﻴﺪ اﮔﺮﭼﻪ‬ ‫داﻧﺴﺘﻦ آنﻫﺎ ﺑﺎﻋﺚ ﺻﺮﻓﻪ ﺟﻮﻳﻲ در وﻗﺖ ﻣﻲﺷﻮد‪.‬‬ ‫ﺑﺮاي ﻳﺎدﮔﻴﺮي ‪ C++‬ﺑﻬﺘﺮ اﺳﺖ ‪ C‬را ﻳﺎد ﻧﮕﺮﻓﺘﻪ ﺑﺎﺷﻴﺪ‪ .‬ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﻗﺮار ﻧﻴﺴﺖ ﻣﻦ اول ﺷﻤﺎ را ﺑﺎ ‪ C‬و ﺑﻌﺪ ﺑﺎ‬ ‫‪ C++‬آﺷﻨﺎ ﻛﻨﻢ‪ .‬ﺑﻪ ﻗﻮل ﺑﻌﻀﻲ ﻣﻴﻮه ﻓﺮوشﻫﺎ »ﺳﻮاﻳﻲ ﻧﻴﺲ ﻫﻤﻪ درﻫﻤﻪ!«‬

‫‪.‬‬

‫‪ The ANSI Standard‬ﻳﻚ ﺟﻮر اﺳﺘﺎﻧﺪارد ﺑﺮاي ‪ C++‬دارد‪ .‬اﻳﻦ اﺳﺘﺎﻧﺪارد ﻛﻤﻚ ﻣﻲﻛﻨﺪ ﻛﻪ ﻳﻚ ﺑﺮﻧﺎﻣﻪي‬ ‫ﺧﺎص در ‪compiler‬ﻫﺎي ﻣﺨﺘﻠﻒ ﻗﺎﺑﻞ اﺟﺮا ﺑﺎﺷﺪ‪ .‬ﻗﻮل ﻧﻤﻲدﻫﻢ ﻫﻤﻪ ﺑﺮﻧﺎﻣﻪﻫﺎي اﻳﻦ ﻧﻮﺷﺘﻪ اﺳﺘﺎﻧﺪارد ﺑﺎﺷﻨﺪ وﻟﻲ‬ ‫ﻫﻤﻪي ﺑﺮﻧﺎﻣﻪﻫﺎ را در‬ ‫‪Borland Developer Studio 2006‬‬ ‫آزﻣﺎﻳﺶ ﻛﺮدهام ﺗﺎ ﻣﺸﻜﻠﻲ ﻧﺪاﺷﺘﻪ ﺑﺎﺷﻨﺪ‪ .‬ﺑﻴﺶ ﺗﺮ آنﻫﺎ در‬ ‫‪Microsoft Visual C++ 2005 Express Edition‬‬ ‫ﻫﻢ آزﻣﺎﻳﺶ ﺷﺪهاﻧﺪ )و اﮔﺮ ﺑﺎ آن آزﻣﺎﻳﺶ ﻧﻜﺮده ﺑﺎﺷﻢ ﮔﻔﺘﻪام(‪.‬‬ ‫ﭼﻮن ﻧﻮﺷﺘﻪﻫﺎي ﺧﺸﻚ وﻋﻠﻤﻲ و ﺑﻲ روح را دوﺳﺖ ﻧﺪارم ﻫﺮ ﺟﺎ ﻛﻪ ﭼﻴﺰي ﺑﺮاي ﺧﻨﺪﻳﺪن ﭘﻴﺪا ﺷﺪه ﺑﻪ ﻧﻮﺷﺘﻪ اﺿﺎﻓﻪ‬ ‫ﻛﺮدهام‪ .‬ﺣﺘﻲ ﻗﺼﺪ داﺷﺘﻢ ﻧﻮﺷﺘﻪ را ﺑﻪ زﺑﺎن ﻋﺎﻣﻴﺎﻧﻪ ﺑﻨﻮﻳﺴﻢ ﻛﻪ ﺑﻪ ﺗﻮﺻﻴﻪي ﻳﻜﻲ از دوﺳﺘﺎن ﻣﻨﺼﺮف ﺷﺪم وﻟﻲ‬ ‫ﻃﻮري ﻧﻮﺷﺘﻪام ﻛﻪ ﻣﻲﺷﻮد آن را ﻋﺎﻣﻴﺎﻧﻪ ﺧﻮاﻧﺪ‪ .‬اﻣﻴﺪوارم ﻛﻪ ﺷﻮﺧﻲﻫﺎي )ﮔﺎﻫﻲ ﺑﻲ ﻣﺰهي( ﻣﻦ ﺑﺎﻋﺚ آزردﮔﻲ‬ ‫ﺷﻤﺎ ﻧﺸﻮد‪ .‬اﻳﻦ ﻛﻪ ﻣﻲﺑﻴﻨﻴﺪ ﻓﻌﻞﻫﺎ را ﻣﻔﺮد ﺑﻪ ﻛﺎر ﺑﺮدهام )ﻣﺜﻼ ﺑﻪ ﺟﺎي »ﺑﮕﻮﻳﻴﻢ«‪» ،‬ﺑﮕﻮﻳﻢ« را ﺑﻪ ﻛﺎر ﺑﺮدهام( ﺑﻪ‬ ‫ﭘﻴﺮوي از ‪ Jesse Liberty‬ﻧﻮﻳﺴﻨﺪهي ﭘﺮ ﻓﺮوش ﺗﺮﻳﻦ ﻛﺘﺎبﻫﺎي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ اﺳﺖ‪ .‬ﻓﻜﺮ ﻣﻲﻛﻨﻢ ﻓﻌﻞﻫﺎي ﻣﻔﺮد‬ ‫ﺧﺸﻜﻲ ﻣﺘﻦ را ﻛﻢ ﻣﻲﻛﻨﻨﺪ‬

‫‪.‬‬

‫ﭼﻮن ﺑﺮاي ﻣﻦ ﺗﺼﻮر ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﺑﺪون ﻛﻤﻚ ﮔﺮﻓﺘﻦ از ‪ ِ help‬ﻳﻚ ‪ compiler‬ﻏﻴﺮ ﻣﻤﻜﻦ اﺳﺖ و ‪ِ help‬‬ ‫‪compiler‬ﻫﺎ ﺑﻪ زﺑﺎن اﻧﮕﻠﻴﺴﻲ ﻧﻮﺷﺘﻪ ﺷﺪه اﺳﺖ‪ ،‬ﺑﻬﺘﺮ اﺳﺖ اﺻﻄﻼﺣﺎت ﺗﺨﺼﺼﻲ ﺗﺎ ﺣﺪ اﻣﻜﺎن ﺑﻪ ﻓﺎرﺳﻲ ﺗﺮﺟﻤﻪ‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻧﺸﻮﻧﺪ‪ .‬ﺿﻤﻦ اﻳﻦ ﻛﻪ ﻣﻌﻤﻮﻻ ﺑﺮاي ﻳﻚ واژه در ﻛﺘﺎبﻫﺎي ﻣﺨﺘﻠﻒ ﺗﺮﺟﻤﻪﻫﺎي ﻣﺘﻔﺎوﺗﻲ ﮔﻔﺘﻪ ﻣﻲﺷﻮد ﻛﻪ اﻳﻦ ﺧﻴﻠﻲ‬ ‫ﺧﻮب ﻧﻴﺴﺖ‪ .‬ﺑﺮاي ﻫﻤﻴﻦ اﺻﻼ ﺳﻌﻲ ﻧﻜﺮدهام ﺑﺮاي واژﮔﺎن آﺷﻨﺎي اﻧﮕﻠﻴﺴﻲ ﻣﻌﺎدلﻫﺎي ﺑﻴﮕﺎﻧﻪي ﻓﺎرﺳﻲ ﭘﻴﺪا ﻛﻨﻢ‬ ‫‪.‬‬ ‫اﮔﺮ درﺑﺎرهي اﻳﻦ ﻧﻮﺷﺘﻪ ﭘﻴﺸﻨﻬﺎد ﻳﺎ اﻧﺘﻘﺎدي دارﻳﺪ ﻟﻄﻔﺎ ﺑﺮاي ﻣﻦ اﻳﻤﻴﻞ ﻛﻨﻴﺪ‪:‬‬ ‫‪CppBuilder2006@msn.com‬‬ ‫ﺣﺘﻤﺎ ﭘﻴﺸﻨﻬﺎدﻫﺎي ﺷﻤﺎ را در وﻳﺮاﻳﺶﻫﺎي ﺑﻌﺪي ﺑﻪ ﻛﺎر ﻣﻲﮔﻴﺮم‪.‬‬ ‫در ﻣﻮرد ‪ copyright‬و ﺣﻖ ﻣﺆﻟﻒ ﻫﻢ ﺑﺎﻳﺪ ﺑﮕﻮﻳﻢ ﻛﻪ اﻳﻦ ﻧﻮﺷﺘﻪ ﺑﺮاي اﺳﺘﻔﺎده ﻋﻤﻮم ﻣﺮدم اﺳﺖ و ﻫﺮ ﮔﻮﻧﻪ‬ ‫اﺳﺘﻔﺎده از آن )از ﻧﻈﺮ ﻣﻦ( آزاد اﺳﺖ‪.‬‬ ‫اﻳﻦ وﻳﺮاﻳﺶ دوم »ﺑﺎ ‪ C++‬آﺷﻨﺎ ﺷﻮﻳﻢ« اﺳﺖ‪ .‬ﻓﺎﻳﻞ ‪ pdf‬و ‪ word‬آن را ﻫﻤﺮاه ﺑﺎ ﺗﻮﺿﻴﺤﺎﺗﻲ درﺑﺎرهي وﻳﺮاﻳﺶ‬ ‫دوم در ﭘﺴﺖ ﺷﻤﺎرهي ‪ 13‬وﺑﻼگ ﻣﻦ ﻳﻌﻨﻲ‬ ‫‪http://www.irancplusplus.blogspot.com/‬‬ ‫ﭘﻴﺪا ﻣﻲﻛﻨﻴﺪ‪ .‬ﻋﻼوه ﺑﺮ اﻳﻤﻴﻞ ﺑﺎﻻ ﻣﻲﺗﻮاﻧﻴﺪ ﻧﻈﺮﻫﺎي ﺧﻮدﺗﺎن را در ﻗﺴﻤﺖ ﻧﻈﺮ وﺑﻼگ ﻗﺮار ﺑﺪﻫﻴﺪ‪.‬‬ ‫در اﻳﻦ وﻳﺮاﻳﺶ ﺑﻪ ﺣﺠﻢ ﻛﺘﺎب ﺣﺪود ‪ 20‬در ﺻﺪ اﺿﺎﻓﻪ ﺷﺪه‪ .‬اﺷﺘﺒﺎﻫﺎت ﺗﺎﻳﭙﻲ در اﻳﻦ وﻳﺮاﻳﺶ ﻫﻢ ﭘﻴﺪا ﻣﻲﺷﻮد ﺑﻪ‬ ‫ﺧﺼﻮص در ﺑﺨﺶﻫﺎي اﺿﺎﻓﻪ ﺷﺪه‪ .‬ﺑﻌﻀﻲ از اﺷﺘﺒﺎﻫﺎت ﺗﺎﻳﭙﻲ وﻳﺮاﻳﺶ ﻗﺒﻞ درﺳﺖ ﺷﺪهاﻧﺪ‪ .‬در اﻳﻦ وﻳﺮاﻳﺶ از ﻓﻮﻧﺖ‬ ‫”‪ “2 Compset‬اﺳﺘﻔﺎده ﺷﺪه ﻛﻪ ﺟﺰء ﻓﻮﻧﺖﻫﺎي ﻣﻌﻤﻮل در وﻳﻨﺪوز و ‪ word‬ﻧﻴﺴﺖ‪.‬‬ ‫در ﭘﺎﻳﺎن از ﻣﺴﺌﻮﻻن ‪ http://forum.p30world.com‬ﺗﺸﻜﺮ ﻣﻲﻛﻨﻢ ﻛﻪ اﻳﻦ ﻧﻮﺷﺘﻪ را در وﺑﺴﺎﻳﺖ ﺧﻮدﺷﺎن‬ ‫‪ upload‬ﻛﺮدهاﻧﺪ‪.‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻓﻬﺮﺳﺖ‬ ‫ ان‬ ‫ اول‬ ‫ عه ‬ ‫او ‬ ‫در ار از ر ‬ ‫! ه ‬ ‫‪#$‬ار"ه ‬ ‫د&‪ %‬ر ‪if‬‬ ‫ ' ار و ‪ (%‬‬ ‫* )ه ‬ ‫ار*‪ /‬ط ‪ -‬را ‪ %‬و ‪,‬ر‪ $‬ن * )‬ ‫‪comment‬ه ‬ ‫ر ‪ %‬ه ‬ ‫ا&‪ 0%‬د" از ‪,‬را ‬ ‫ا&‪ 0%‬د" از ‪new‬‬ ‫ا ر" ‪ $‬ه و ‪,‬را ه ‬ ‫ا! اد ‪1 23‬‬ ‫ا! اد ا!‪ 4‬ر ‬ ‫*‪ /‬ع‬ ‫ ‪unsigned‬‬ ‫)(‪getch‬‬ ‫ ‪5‬ار ‪ (%‬ه و * )ه ‬ ‫ ‪ (%‬ه ! ‪6‬‬ ‫! ه ‪ ++‬و ‪--‬‬ ‫ عه ‪ 6‬و& ; *‪ 6 9 :‬‬ ‫ز ‪ 6 /‬و < ا ‪ 6‬‬ ‫>= * ‬ ‫ @ * &? ‬ ‫ دوم‬ ‫ا اع د&‪ %‬ره در ‪C++‬‬ ‫! ه =‪6 B‬‬ ‫د&‪ %‬ر ‪if … else‬‬ ‫‪for C‬‬ ‫‪while C‬‬ ‫‪do … while C‬‬ ‫‪ D‬ه ‬ ‫د&‪ %‬ر ‪switch‬‬ ‫د&‪ %‬ر ‪goto‬‬ ‫ ه ‪ sizeof‬و ‪ typeid‬و ‪typedef‬‬

‫ ‬ ‫‪7‬‬ ‫‪7‬‬ ‫‪8‬‬ ‫‪15‬‬ ‫‪16‬‬ ‫‪19‬‬ ‫‪20‬‬ ‫‪22‬‬ ‫‪23‬‬ ‫‪28‬‬ ‫‪32‬‬ ‫‪33‬‬ ‫‪41‬‬ ‫‪43‬‬ ‫‪45‬‬ ‫‪50‬‬ ‫‪50‬‬ ‫‪52‬‬ ‫‪58‬‬ ‫‪59‬‬ ‫‪60‬‬ ‫‪61‬‬ ‫‪62‬‬ ‫‪64‬‬ ‫‪66‬‬ ‫‪68‬‬ ‫‪69‬‬ ‫‪70‬‬ ‫‪70‬‬ ‫‪75‬‬ ‫‪84‬‬ ‫‪87‬‬ ‫‪94‬‬ ‫‪95‬‬ ‫‪97‬‬ ‫‪101‬‬ ‫‪106‬‬ ‫‪108‬‬

‫‪www.pupuol.com‬‬


â€Ťď­˜ď­˜ďť? ﺎďş&#x; ﺊďş?ﺸﺎ ďť­ ﺪﺭﺳ‏ 114 115 116 120 127 129 131 133 136 139 140 141 141 142 146 155 156 158 161 161 164 170 178 179 180 193 201 201 204 207 210 212 215 220 232 237 240 242 256 263 265 274 280

www.pupuol.com

default-int 6$E â€ŤŮˆâ€Ź LValue ‍ Ůˆâ€ŹRValue prototype 6%4$‍* )ه Ůˆ * )ه ز‏ pointer ‍عا ه‏, ‍ * )ه Ůˆâ€Ź ‍ > ' Ř&#x;‏#include default % ‍ عا‏‍ دن‏overload namespace ‍ Ůˆâ€Źusing throw ŘŒtry ŘŒ catch ) * @ ‍ ŘŻŘąŮˆŮ†â€Źstatic register auto inline enum $ => ‍عا ه‏, void* ‍ ؚ‏$ "‍ا ع‏ * => ?& ‍* ه‏ ‍ & م‏ ‍سه‏I constructor ‍ Ůˆâ€Źdestructor copy constructor explicit this ‍ه‏Operator new ! conversion operator operator = private constructor ‍ه‏member ‍ اع اŮˆ دادن‏ method ‍ ه‏inline ‍س‏I ‍ Ůˆâ€Ź6 ! ‍( ه‏% ŘŒtypedef static J!‍ا‏ Template ‍ه‏ friend member ‍ Řš != ان‏ const ‍ه‏method Inheritance virtual ‍ه‏method virtual destructor dynamic_cast virtual inheritance abstract ‍سه‏I


â€Ťď­˜ď­˜ďť? ﺎďş&#x; ﺊďş?ﺸﺎ ďť­ ﺪﺭﺳ‏ 284 287 291 294 296 296 308 308 311 315 317 328 329 331 336 341 343 346 350 353 357 366 369 370 375 376 377 391

compiler < = ‍سه دع‏I ‍ ŘŻ" از‏0%&‍ا‏ ‍ه‏union * => ?& ‍* ه‏ ‍ عم‏K> preprocessor ‍ عه‏%&‍د‏ precompiled headers " 9 :* L - ‍ ŮˆŮ‡ از‏ => ‍ دع‏%

extern linkage => ‍ Ůˆ دع‏#define ‍ ا! اد‏L 9 %? ‍ ه‏M ‍ Řą ه‏ 6% ‍! ه‏ calling convention stdio.h stdlib.h main() ) * ‍ نه‏$‍ع‏, stdarg.h Map string string.h vector fstream.h math.h windows.h ‍ اع‏K ‍< ا‏

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ اول‬ ‫در اﻳﻦ ﻓﺼﻞ ﺑﺎ ﻫﻢ در ‪ C++‬دوري ﻣﻲزﻧﻴﻢ و ﺑﺎ ﺑﺨﺶﻫﺎي ﻣﺨﺘﻠﻔﺶ آﺷﻨﺎ ﻣﻲﺷﻮﻳﻢ‪.‬‬

‫ عه ‬

‫ﻧﻮع ﻳﻚ ﻣﺘﻐﻴﺮ ﺗﻌﺪاد ﺑﺎﻳﺖﻫﺎي ﺣﺎﻓﻈﻪي آن را ﻧﺸﺎن ﻣﻲدﻫﺪ‪ .‬اﻟﺒﺘﻪ ﺗﻨﻬﺎ ﻛﺎر ﻧﻮع‪ ،‬اﻳﻦ ﻧﻴﺴﺖ‪ .‬وﻟﻲ ﻓﻌﻼ ﻫﻤﻴﻦ ﺗﺼﻮر‬ ‫از آن ﻛﺎﻓﻲ اﺳﺖ‪ .‬ﺑﻌﻀﻲ از ﻧﻮعﻫﺎي ﻣﻮﺟﻮد در ‪ C++‬اﻳﻦﻫﺎ ﻫﺴﺘﻨﺪ‪:‬‬ ‫ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ )ﻋﺪد ﻏﻴﺮ اﻋﺸﺎري ﻛﻪ ﻣﻲﺗﻮاﻧﺪ ﻣﻨﻔﻲ ﻫﻢ ﺑﺎﺷﺪ(‬

‫‪ 4‬ﺑﺎﻳﺖ‬

‫‪int‬‬

‫ﻳﻚ ﻛﺎراﻛﺘﺮ )ﻳﻚ ﺣﺮف در زﺑﺎن اﻧﮕﻠﻴﺴﻲ(‬

‫‪ 1‬ﺑﺎﻳﺖ‬

‫‪char‬‬

‫ﻳﻚ ﮔﺰاره )ﻋﺒﺎرﺗﻲ ﻛﻪ ﻳﺎ درﺳﺖ ﻳﺎ ﻏﻠﻂ اﺳﺖ(‬

‫‪ 1‬ﺑﺎﻳﺖ‬

‫‪bool‬‬

‫ﻳﻚ رﺷﺘﻪ )دﺳﺘﻪاي از ﻛﺎراﻛﺘﺮﻫﺎ ﻛﻪ ﻳﻚ ﺟﻤﻠﻪ و‪ ...‬ﺗﺸﻜﻴﻞ ﻣﻲدﻫﻨﺪ(‬

‫‪ 4‬ﺑﺎﻳﺖ‬

‫*‪char‬‬

‫ﻳﻚ ﻋﺪد اﻋﺸﺎري‬

‫‪ 8‬ﺑﺎﻳﺖ‬

‫‪double‬‬

‫)‪compiler‬ﻫﺎي ﺧﻴﻠﻲ ﻗﺪﻳﻤﻲ ‪ bool‬را اﺻﻼ ﻧﻤﻲ ﺷﻨﺎﺳﻨﺪ‪(.‬‬ ‫ﺑﻪ ﻋﻨﻮان ﻣﺜﺎل اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻣﺘﻐﻴﺮي داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﻛﻪ ﻋﺪد ﺻﺤﻴﺢ )ﻳﻌﻨﻲ ﻋﺪد ﻏﻴﺮ اﻋﺸﺎري( در ﺧﻮد ﺟﺎ ﺑﺪﻫﺪ‪ ،‬ﻣﻲ‪-‬‬ ‫ﻧﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪int a‬‬

‫ﺣﺎل ‪ a‬ﻣﻲﺗﻮاﻧﺪ ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ را در ﺧﻮدش ﺟﺎ ﺑﺪﻫﺪ‪ .‬ﺑﺮاي ﻗﺮار دادن ﻋﺪد ‪ 2‬در اﻳﻦ ﻣﺘﻐﻴﺮ ﻣﻲﺷﻮد ﻧﻮﺷﺖ‬ ‫;‪a = 2‬‬

‫"‪ "hello, bye‬ﻳﻚ رﺷﺘﻪ اﺳﺖ‪ .‬ﺑﺮاي ﻗﺮار دادن اﻳﻦ رﺷﺘﻪ در ﻳﻚ ﻣﺘﻐﻴﺮ ﻣﻲﻧﻮﻳﺴﻴﻢ‪:‬‬ ‫;"‪char* c = "hello, bye‬‬

‫'‪ 'g‬ﻳﻚ ﻛﺎراﻛﺘﺮ اﺳﺖ و ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;'‪char ch = 'g‬‬

‫ﺑﻪ ﻗﺮار دادن ﻣﻘﺪار )ﻣﺜﻼ ﻋﺪد ﻳﺎ رﺷﺘﻪ( در ﻳﻚ ﻣﺘﻐﻴﺮ ‪ assignment‬ﻳﺎ ‪ assign‬ﻛﺮدن ﻣﻲﮔﻮﻳﻴﻢ‪.‬‬ ‫ﻳﻌﻨﻲ در ﺑﺎﻻ ﺑﺎ ﻧﻮﺷﺘﻦ‬ ‫;‪a = 2‬‬

‫‪7‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻋﺪد ‪ 2‬را ﺑﻪ ‪ assign ،a‬ﻛﺮد هاﻳﻢ‪.‬‬ ‫ﻣﻲﺷﻮد دو ﻳﺎ ﭼﻨﺪ ﺑﺎر ﻣﻘﺪارﻫﺎي ﻣﺨﺘﻠﻒ را ﺑﻪ ﻳﻚ ﻣﺘﻐﻴﺮ ‪ assign‬ﻛﺮد‪:‬‬ ‫;‪double r = 2.3‬‬ ‫;‪r = 5‬‬ ‫;‪r = 7.91‬‬

‫ﭘﺲ از اﻧﺠﺎم اﻳﻦ دﺳﺘﻮرات ﻣﻘﺪار ‪ 7.91 ،r‬اﺳﺖ )ﺣﺘﻤﺎ ﻣﻲداﻧﻴﺪ ﻛﻪ ﻧﻘﻄﻪ در ‪ 7.91‬ﺑﻪ ﻣﻌﻨﻲ ﻣﻤﻴﺰ اﺳﺖ‬

‫(‪.‬‬

‫او ‬

‫اول ﺑﺎﻳﺪ ‪ compiler‬ﺧﻮدﺗﺎن را ﺑﺎز ﻛﻨﻴﺪ و ﻳﻚ ‪ project‬از ﻧﻮع ‪ console‬اﻳﺠﺎد ﻛﻨﻴﺪ‪ .‬ﺑﮕﺬارﻳﺪ ﻧﺤﻮهي اﻳﺠﺎد‬ ‫‪ project‬را در دو ‪ compiler‬ﺧﻮدم ﺑﮕﻮﻳﻢ‪:‬‬ ‫)‪ :BDS 2006 (C++Builder‬اول از ﻃﺮﻳﻖ ﻣﻨﻮﻫﺎ‪ ،‬ﻣﺴﻴﺮ زﻳﺮ را ﻃﻲ ﻛﻨﻴﺪ‪:‬‬ ‫…‪File | New | Other‬‬ ‫ﭘﻨﺠﺮهاي ﺑﺎ ﻧﺎم ‪ New Items‬ﺑﺎز ﻣﻲﺷﻮد‪:‬‬

‫‪8‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫از ﻗﺴﻤﺖ ‪ Console Application ،C++Builder Projects‬را اﻧﺘﺨﺎب ﻛﻨﻴﺪ‪ .‬ﭘﻨﺠﺮهاي دﻳﮕﺮ ﺑﺎ ﻧﺎم ‪New‬‬ ‫‪ Console Application‬ﺑﺎز ﻣﻲﺷﻮد‪ .‬ﺗﻨﻬﺎ ‪ Console Application‬و ‪ C++‬را ﺗﻴﻚ ﺑﺰﻧﻴﺪ‪:‬‬

‫و دﻛﻤﻪي ‪ OK‬را ﻓﺸﺎر ﺑﺪﻫﻴﺪ‪ .‬در ﻓﺎﻳﻞ ‪ .cpp‬ﻣﻲﺗﻮاﻧﻴﺪ ﺑﺮﻧﺎﻣﻪي ﺧﻮدﺗﺎن را ﺑﻨﻮﻳﺴﻴﺪ‪.‬‬

‫‪ :Visual C++ 2005 Express Edition‬اول از ﻃﺮﻳﻖ ﻣﻨﻮ ﻣﺴﻴﺮ زﻳﺮ را ﻃﻲ ﻛﻨﻴﺪ‪:‬‬ ‫‪9‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪File | New | Project‬‬ ‫ﭘﻨﺠﺮهاي ﺑﺎ ﻧﺎم ‪ New Project‬ﺑﺎز ﻣﻲﺷﻮد‪ .‬در ﺑﺨﺶ ‪ Project Types‬روي ‪ Visual C++‬ﻛﻠﻴﻚ ﻛﻨﻴﺪ و‬ ‫‪ Win32 Console Application‬را اﻧﺘﺨﺎب ﻛﻨﻴﺪ‪ .‬در ﻧﻮار ‪ ِ Name‬ﭘﺎﻳﻴﻦ‪ ،‬ﻳﻚ اﺳﻢ ﺑﺮاي آن ﻣﺸﺨﺺ ﻛﻨﻴﺪ‬ ‫)ﺑﻬﺘﺮ اﺳﺖ اﺳﻢ ‪ console‬را اﻧﺘﺨﺎب ﻛﻨﻴﺪ ﺗﺎ در اداﻣﻪ اﻳﻦ ﻧﻮﺷﺘﻪ راﺣﺖ ﺗﺮ ﺑﺎﺷﻴﺪ(‪:‬‬

‫دﮔﻤﻪي ‪ OK‬را ﻓﺸﺎر ﺑﺪﻫﻴﺪ‪ .‬ﭘﻨﺠﺮهاي ﺑﺎ ﻧﺎم ‪ Win32 Application Wizard‬ﺑﺎز ﻣﻲﺷﻮد‪:‬‬

‫‪10‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫دﮔﻤﻪي ‪ Next‬را ﻓﺸﺎر ﺑﺪﻫﻴﺪ و ‪ Empty Project‬را ﺗﻴﻚ ﺑﺰﻧﻴﺪ‪:‬‬

‫‪11‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫و در آﺧﺮ ‪ Finish‬را ﻓﺸﺎر ﺑﺪﻫﻴﺪ‪ .‬در ﻗﺴﻤﺖ ‪ Solution Explorer‬روي ﻓﻮﻟﺪر ‪ Source Files‬ﻛﻠﻴﻚ‬ ‫ﻛﻨﻴﺪ و دﮔﻤﻪي ‪ Delete‬را روي ﺻﻔﺤﻪ ﻛﻠﻴﺪ ﻓﺸﺎر ﺑﺪﻫﻴﺪ ﺗﺎ ﺣﺬف ﺑﺸﻮد‪ .‬ﻫﻤﻴﻦ ﻛﺎر را ﺑﺎ دو ﺗﺎ ﻓﻮﻟﺪر دﻳﮕﺮ ﻫﻢ‬ ‫اﻧﺠﺎم ﺑﺪﻫﻴﺪ‪.‬‬ ‫ﺣﺎﻻ روي ‪ ،console‬راﺳﺖ ﻛﻠﻴﻚ ﻛﻨﻴﺪ‪ .‬ﻳﻚ ﻣﻨﻮ ﺑﺎز ﻣﻲﺷﻮد‪ .‬از اﻳﻦ ﻣﻨﻮ‪ ،‬اﻳﻦ ﻣﺴﻴﺮ را دﻧﺒﺎل ﻛﻨﻴﺪ‪:‬‬ ‫‪Add | New Item… | Visual C++ | C++ File (.cpp) | Name | Add‬‬ ‫در ﻓﺎﻳﻞ ‪ .cpp‬ﻣﻲﺗﻮاﻧﻴﺪ ﺑﺮﻧﺎﻣﻪي ﺧﻮد را ﺑﻨﻮﻳﺴﻴﺪ‪.‬‬ ‫ﻣﺮﺳﻮم اﺳﺖ ﻛﻪ اوﻟﻴﻦ ﺑﺮﻧﺎﻣﻪ‪ ،‬ﺑﺮﻧﺎﻣﻪاي ﺑﺎﺷﺪ ﻛﻪ ﭘﻴﺎم‬ ‫"!‪"Hello World‬‬

‫را ﺑﺮ ﺻﻔﺤﻪي ﻧﻤﺎﻳﺶ ﭼﺎپ ﻣﻲﻛﻨﺪ ﻛﻪ ﻧﻮﻋﻲ ﺧﻮﺷﺎﻣﺪ ﮔﻮﻳﻲ ﺑﻪ دﻧﻴﺎي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ اﺳﺖ‪» .‬ﭼﺎپ ﻛﺮدن« در اﻳﻦ‬ ‫ﺟﺎ ﻫﻴﭻ رﺑﻄﻲ ﺑﻪ »‪ print‬ﮔﺮﻓﺘﻦ روي ﻛﺎﻏـﺬ« ﻧﺪارد‪ .‬اﻳﻦ اوﻟﻴﻦ ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;"!‪cout<< "Hello World‬‬ ‫;)(‪getch‬‬ ‫}‬

‫اﻳﻦ ﺑﺮﻧﺎﻣﻪ را در ﻓﺎﻳﻞ ‪ .cpp‬ﻛﻪ در ‪ Project‬ﺷﻤﺎ ﻗﺮار دارد ﻛﭙﻲ ﻛﻨﻴﺪ و ﻛﻠﻴﺪ ‪ Run‬را در ‪ compiler‬ﺧﻮد ﭘﻴﺪا‬ ‫ﻛﻨﻴﺪ و ﻓﺸﺎر ﺑﺪﻫﻴﺪ‪ .‬ﺧﺮوﺟﻲ زﻳﺮ را درﻳﺎﻓﺖ ﻣﻲﻛﻨﻴﺪ‪:‬‬ ‫‪Output:‬‬ ‫!‪Hello World‬‬

‫ﺣﺘﻤﺎ از دﻳﺪن اﻳﻦ ﻫﻤﻪ ﻛﻠﻤﺎت ﻋﺠﻴﺐ و ﻏﺮﻳﺐ در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺷﻮﻛﻪ ﺷﺪهاﻳﺪ‪ .‬اﺻﻼ ﻧﺘﺮﺳﻴﺪ ﺗﻨﻬﺎ ﻳﻚ ﺧﻂ از اﻳﻦ‬ ‫ﺑﺮﻧﺎﻣﻪ ﻣﻬﻢ اﺳﺖ‪ .‬ﺑﻘﻴﻪي ﺧﻂﻫﺎ در ﻫﻤﻪي ﺑﺮﻧﺎﻣﻪﻫﺎ ﻣﺸﺘﺮك ﻫﺴﺘﻨﺪ و ﻣﻲﺗﻮاﻧﻴﺪ آنﻫﺎ را ﻧﺎدﻳﺪه ﺑﮕﻴﺮﻳﺪ‪ .‬ﺧﻂ ﻣﻬﻢ‬ ‫ﺑﺮﻧﺎﻣﻪ اﻳﻦ اﺳﺖ‪:‬‬ ‫;"!‪cout<< "Hello World‬‬

‫ﻗﺒﻼ ﮔﻔﺘﻢ "!‪ "Hello World‬ﻳﻚ رﺷﺘﻪ اﺳﺖ‪ .‬ﺑﺮاي ﭼﺎپ ﻛﺮدن ﻳﻚ رﺷﺘﻪ )ﻛﻪ رﺑﻄﻲ ﺑﻪ ‪ print‬ﮔﺮﻓﺘﻦ‬ ‫روي ﻛﺎﻏـﺬ ﻧﺪارد( از ‪) cout‬ﺑﺨﻮاﻧﻴﺪ ‪ (See Out‬اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪ .‬اﮔﺮ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;"‪char* c = "This is a test‬‬

‫‪12‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ c‬ﻳﻚ رﺷﺘﻪ اﺳﺖ و ﻣﻲﺷﻮد آن را ﺑﺎ ‪ cout‬روي ﺻﻔﺤﻪي ﻧﻤﺎﻳﺶ ﭼﺎپ ﻛﺮد‪ .‬ﺑﺮاي ﭼﺎپ ﻣﻲﻧﻮﻳﺴﻢ‪:‬‬ ‫;‪cout<< c‬‬

‫ﻳﻌﻨﻲ ﻗﺒﻞ از آن <<‪ cout‬ﻣﻲﮔﺬارم‪ .‬آﺧﺮ ﻫﻤﻪي دﺳﺘﻮرات در ‪ ««; ،C++‬ﻗﺮار ﻣﻲﮔﻴﺮد )ﺑﻪ ﺟﺰ ﻣﻮارد ﺧﺎﺻﻲ‬ ‫ﻛﻪ اﻳﻦ ﺟﺎ ﺟﺎي ﮔﻔﺘﻦ آنﻫﺎ ﻧﻴﺴﺖ(‪ .‬اﺳﻢ ﻋﻼﻣﺖ »;«‪ semicolon ،‬اﺳﺖ‪.‬‬ ‫ﻫﻤﺎن ﻃﻮر ﻛﻪ ﻗﺒﻼ اﺷﺎره ﻛﺮدم ﺑﺨﺶ ﻣﺸﺘﺮك ﻫﻤﻪي ﺑﺮﻧﺎﻣﻪﻫﺎ اﻳﻦ اﺳﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪// your code‬‬ ‫;)(‪getch‬‬ ‫}‬

‫اﮔﺮ ‪ compiler‬ﺷﻤﺎ ﺑﻴﺶ از ﺣﺪ ﺟﺪﻳﺪ ﺑﺎﺷﺪ ﻣﻤﻜﻦ اﺳﺖ ﻣﺠﺒﻮر ﺷﻮﻳﺪ ﺑﻪ ﺟﺎي ;)(‪ getch‬ﺑﻨﻮﻳﺴﻴﺪ‬ ‫;)(‪ ._getch‬در ﺿﻤﻦ ﺗﻐﻴﻴﺮ زﻳﺮ در ‪ compiler‬ﻫﺎي ﻗﺪﻳﻤﻲ ﻻزم‪ ،‬در ‪ BDS 2006‬اﻣﻜﺎن ﭘﺬﻳﺮ و در‬ ‫‪ compiler‬ﻫﺎي ﺟﺪﻳﺪ ‪ Microsoft‬ﻏﻴﺮ ﻣﻤﻜﻦ اﺳﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream.h‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪// your code‬‬ ‫;)(‪getch‬‬ ‫}‬

‫دﺳﺘﻮرات ﺑﺮﻧﺎﻣﻪ در ﻗﺴﻤﺘﻲ ﻛﻪ ﺑﺎ ‪ // your code‬ﻣﺸﺨﺺ ﻛﺮدهام ﻗﺮار ﻣﻲﮔﻴﺮﻧﺪ‪ .‬ﺑﻨﺎﺑﺮاﻳﻦ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;"‪char* c = "This is a test‬‬ ‫;‪cout<<c‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪This is a test‬‬

‫‪13‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺑﺎ ‪ cout‬ﻣﻲﺷﻮد ﻫﺮ ﭼﻴﺰ دﻳﮕﺮي را ﻫﻢ ﭼﺎپ ﻛﺮد‪ .‬ﻣﺜﻼ ﻳﻚ ﻋﺪد ﻳﺎ ﻳﻚ ﻛﺎراﻛﺘﺮ )ﻛﺎراﻛﺘﺮ ﻳﻚ ﺣﺮف در‬ ‫اﻟﻔﺒﺎي اﻧﮕﻠﻴﺴﻲ اﺳﺖ(‪ .‬ﺑﺮﻧﺎﻣﻪي زﻳﺮ دو ﺗﺎ ﻋﺪد را ﺑﺎ ﻫﻢ ﺟﻤﻊ ﻣﻲﻛﻨﺪ و ﺣﺎﺻﻞ را ﭼﺎپ ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a‬‬ ‫;‪int b‬‬ ‫;‪int c‬‬ ‫;‪a = 2‬‬ ‫;‪b = 3‬‬ ‫;‪c = a + b‬‬ ‫;‪cout<< c‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬

‫اﻳﻦ ﺑﺮﻧﺎﻣﻪ را ﻣﻲﺷﻮد ﺑﻪ ﺷﻜﻞ ﺳﺎده ﺗﺮي ﻫﻢ ﻧﻮﺷﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a = 2, b = 3, c = a + b‬‬ ‫;‪cout<< c‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬

‫در واﻗﻊ ﺑﻪ ﺟﺎي‬ ‫;‪int a‬‬ ‫;‪a = 2‬‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;‪int a = 2‬‬

‫و ﺑﻪ ﺟﺎي‬ ‫;‪int a = 2‬‬ ‫;‪int b = 3‬‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬

‫‪14‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪int a = 2, b = 3‬‬

‫و در آﺧﺮ ﺑﻪ ﺟﺎي‬ ‫;‪int a = 2, b = 3‬‬ ‫;‪int c = a + b‬‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;‪int a = 2, b = 3, c = a + b‬‬

‫و ﺑﻪ اﻳﻦ ﺷﻜﻞ از ﺗﻜﺮار ‪ int‬ﺟﻠﻮﮔﻴﺮي ﻣﻲﺷﻮد‪ .‬ﻣﻲﺷﻮد اﻳﻦ ﻗﺪر ﻣﺨﺘﺼﺮﻧﻮﻳﺴﻲ ﻛﺮد وﻟﻲ اﺻﻼ ﺧﻮب ﻧﻴﺴﺖ ﭼﻮ ن‬ ‫زﻳﺒﺎﻳﻲ و ﺳﺎدﮔﻲ ﻣﺘﻦ از دﺳﺖ ﻣﻲرود‪.‬‬

‫در ار از ر ‬

‫ﺣﺘﻤﺎ ﻣﻲﭘﺮﺳﻴﺪ ﻛﺎرﺑﺮ دﻳﮕﺮ ﻛﻴﺴﺖ؟ ﻛﺎرﺑﺮ ﻓﻌﻼ ﺧﻮد ﺷﻤﺎ ﻫﺴﺘﻴﺪ‪ .‬وﻗﺘﻲ ﺑﺮﻧﺎﻣﻪي ﺧﻮدﺗﺎن را اﺟﺮا ﻣﻲﻛﻨﻴﺪ و ﺑﺮﻧﺎﻣﻪ‬ ‫در ﺣﺎل اﺟﺮاﺳﺖ ﺷﻤﺎ ﻣﻮﻗﺘﺎ از ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﺑﻪ ﻛﺎرﺑﺮ ﺗﺒﺪﻳﻞ ﻣﻲﺷﻮﻳﺪ‪ .‬ﺑﻌﺪ ﺑﺎ ﻓﺸﺎر ﻳﻚ ﻛﻠﻴﺪ از ‪ keyboard‬اﺟﺮاي‬

‫ﺑﺮﻧﺎﻣﻪ ﺗﻤﺎم ﻣﻲﺷﻮد و ﺷﻤﺎ دوﺑﺎره ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻣﻲﺷﻮﻳﺪ و روزﮔﺎر وﺻﻞ ﺧﻮﻳﺶ ﺑﺎز ﻣﻲﺟﻮﻳﻴﺪ‬

‫‪.‬‬

‫ﺑﺮاي اﻳﻦ ﻛﻪ ﻛﺎرﺑﺮ ﺑﺘﻮاﻧﺪ ﺑﻪ ﻳﻚ ﻣﺘﻐﻴﺮ ﻣﻘﺪار ﺑﺪﻫﺪ ﺑﺎﻳﺪ از >>‪ cin‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ cin .‬ﺑﺮ ﻋﻜﺲ ‪ cout‬ﻋﻤﻞ‬ ‫ﻣﻲﻛﻨﺪ‪ cout .‬ﻣﻘﺪار ﻳﻚ ﻣﺘﻐﻴﺮ را در ﺻﻔﺤﻪي ﻧﻤﺎﻳﺶ ﻧﺸﺎن ﻣﻲدﻫﺪ و ‪ cin‬ﻳﻚ ﻣﻘﺪار را از ﺻﻔﺤﻪ ﻧﻤﺎﻳﺶ ﻣﻲ‪-‬‬ ‫ﮔﻴﺮد و در ﻣﺘﻐﻴﺮ ﻗﺮار ﻣﻲدﻫﺪ‪.‬‬ ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻣﻘﺪاري را از ﻛﺎرﺑﺮ ﻣﻲﮔﻴﺮد‪ ،‬اﻳﻦ ﻣﻘﺪار را ﺑﻪ ﺗﻮان ‪ 2‬ﻣﻲرﺳﺎﻧﺪ و ﭼﺎپ ﻣﻲﻛﻨﺪ‪ .‬ﻓﻘﻂ ﺑﺎﻳﺪ ﺑﮕﻮﻳﻢ ﻛﻪ‬ ‫در ‪ C++‬ﺑﺮاي ﺿﺮب ﻛﺮدن دو ﻋﺪد از * اﺳﺘﻔﺎده ﻣﻲﺷﻮد ﻧﻪ از ‪.‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a‬‬ ‫;‪cin>> a‬‬ ‫;‪cout<< a*a‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬

‫‪15‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪25‬‬

‫وﻗﺘﻲ ﻣﻦ اﻳﻦ ﺑﺮﻧﺎﻣﻪ را اﺟﺮا ﻛﺮدم اول ﺑﺮﻧﺎﻣﻪ ﻣﻨﺘﻈﺮ ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ ﻣﺎﻧﺪ‪ .‬ﻣﻦ ﻋﺪد ‪ 5‬را وارد ﻛﺮدم و ﻛﻠﻴﺪ‬ ‫‪ Enter‬را ﻓﺸﺎر دادم‪ .‬ﻫﻤﺎن ﻃﻮر ﻛﻪ ﻣﻲﺑﻴﻨﻴﺪ ﻋﺪد ‪ 25‬ﭼﺎپ ﺷﺪ‪.‬‬ ‫ﺷﺎﻳﺪ ﺑﺎ دﻳﺪن ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ اﻳﻦ ﺳﻮال ﺑﺮاﻳﺘﺎن ﻣﻄﺮح ﺷﺪه ﺑﺎﺷﺪ ﻛﻪ ﭼﺮا از ﺗﻮان اﺳﺘﻔﺎده ﻧﻜﺮدﻳﻢ؟ ﺧﻴﻠﻲ واﺿﺢ اﺳﺖ؛‬ ‫ﭼﻮن در ‪ C++‬ﺑﺮ ﻋﻜﺲ ‪ Basic‬ﻋﻤﻠﮕﺮ ﺗﻮان ﻧﺪارﻳﻢ )در ‪ C++‬ﻋﻤﻠﮕﺮ »^« ﻫﺴﺖ اﻣﺎ ﻣﻌﻨﻲ دﻳﮕﺮي دارد و‬ ‫ﺑﺮاي ﺗﻮان از آن اﺳﺘﻔﺎده ﻧﻤﻲﺷﻮد(‪ .‬اﻟﺒﺘﻪ در آﻳﻨﺪه ﻣﺘﻮﺟﻪ ﺧﻮاﻫﻴﺪ ﺷﺪ ﻛﻪ ‪ C++‬آن ﻗﺪر اﻧﻌﻄﺎف دارد ﻛﻪ ﺧﻮد‬ ‫ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻣﻲﺗﻮاﻧﺪ ﻗﺎﺑﻠﻴﺖ »ﺑﻪ ﺗﻮان رﺳﺎﻧﺪن« را ﺑﻪ ﺑﺮﻧﺎﻣﻪي ﺧﻮدش اﺿﺎﻓﻪ ﻛﻨﺪ‪.‬‬

‫از ‪ cin‬ﻣﻲﺷﻮد ﺑﺮاي ﮔﺮﻓﺘﻦ ﻫﺮ ﻧﻮع ﻣﻘﺪاري ﻣﺜﻞ ﻋﺪد ﺻﺤﻴﺢ‪ ،‬ﻋﺪد اﻋﺸﺎري‪ ،‬ﻛﺎراﻛﺘﺮ و رﺷﺘﻪ اﺳﺘﻔﺎده ﻛﺮد‪ .‬اﻣﺎ‬ ‫ﻓﻌﻼ ﺑﺮاي ﮔﺮﻓﺘﻦ رﺷﺘﻪ از آن اﺳﺘﻔﺎده ﻧﻜﻨﻴﺪ ﭼﻮن در ﻣﻮرد رﺷﺘﻪ‪ ،‬ﭼﻴﺰﻫﺎﻳﻲ ﻫﺴﺖ ﻛﻪ ﻫﻨﻮز ﻧﮕﻔﺘﻪام‪.‬‬ ‫ ه ‬

‫ﻗﺒﻼ ﺑﺎ ﻋﻤﻠﮕﺮﻫﺎﻳﻲ ﻣﺜﻞ ﺟﻤﻊ و ﺿﺮب آﺷﻨﺎ ﺷﺪﻳﺪ‪ .‬در ‪ C++‬ﻋﻤﻠﮕﺮﻫﺎي زﻳﺎدي ﻫﺴﺖ ﺑﻌﻀﻲ از آنﻫﺎ را در ﺟﺪول‬ ‫زﻳﺮ ﻣﻲﺑﻴﻨﻴﺪ‪:‬‬ ‫ﻣﺜﺎل‬

‫‪a + b‬‬

‫ﺗﻮﺿﻴﺤﺎت‬ ‫ﺟﻤﻊ‬

‫‪+‬‬

‫‪a – b‬‬

‫ﺗﻔﺮﻳﻖ‬

‫‪-‬‬

‫‪a * b‬‬

‫ﺿﺮب‬

‫*‬

‫‪a / b‬‬

‫ﺗﻘﺴﻴﻢ‬

‫‪/‬‬

‫‪ ++a‬ﻳﺎ ‪ a++‬اﺿﺎﻓﻪ ﻛﺮدن ﻳﻚ واﺣﺪ‬ ‫ﻛﻢ ﻛﺮدن ﻳﻚ واﺣﺪ‬ ‫‪ –a‬ﻳﺎ ‪a--‬‬ ‫‪a % b‬‬ ‫ﺑﺎﻗﻴﻤﺎﻧﺪهي ﺗﻘﺴﻴﻢ دو ﻋﺪد‬

‫ﻋﻤﻠﮕﺮ‬

‫‪++‬‬ ‫‪-‬‬‫‪%‬‬

‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ را از ﻛﺎرﺑﺮ ﻣﻲﮔﻴﺮد ﻳﻜﻲ ﺑﻪ آن اﺿﺎﻓﻪ ﻣﻲﻛﻨﺪ ﺣﺎﺻﻞ را ﺑﻪ ﺗﻮان ‪ 2‬ﻣﻲرﺳﺎﻧﺪ و از‬ ‫ﺣﺎﺻﻞ ﻳﻜﻲ ﻛﻢ ﻣﻲﻛﻨﺪ و ﻧﺘﻴﺠﻪ را ﭼﺎپ ﻣﻲﻛﻨﺪ‪ .‬ﺑﻪ ﻃﻮر ﺳﺎده ﺗﺮ ﺑﺮﻧﺎﻣﻪ‪ ،‬را از ﻛﺎرﺑﺮ ﻣﻲﮔﻴﺮد و‬ ‫ را ﭼﺎپ ﻣﻲﻛﻨﺪ‪.‬‬

‫‪16‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a‬‬ ‫;‪cin>> a‬‬ ‫;‪a++‬‬ ‫;‪int b = a*a‬‬ ‫;‪b--‬‬ ‫;‪cout<< b‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬ ‫‪35‬‬

‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ دو ﺗﺎ ﻣﺘﻐﻴﺮ ﺻﺤﻴﺢ ‪ a‬و ‪ b‬ﺗﻌﺮﻳﻒ ﺷﺪهاﻧﺪ‪ .‬ﻣﻲﺷﻮد آنﻫﺎ را ﺑﻪ ﺗﻨﻬﺎ ﻳﻚ ﻣﺘﻐﻴﺮ ﺻﺤﻴﺢ ﺗﺒﺪﻳﻞ ﻛﺮد‪.‬‬ ‫ﺑﺮاي اﻳﻦ ﻛﺎر ﺑﺎﻳﺪ ﺗﻮﺟﻪ ﻛﻨﻴﻢ ﻛﻪ در ‪) assignment‬ﻳﻌﻨﻲ ﻫﻤﺎن ﺗﺴﺎوي( اول ﻃﺮف راﺳﺖ ﺗﺴﺎوي ﺣﺴﺎب ﻣﻲ‪-‬‬ ‫ﺷﻮد و ﺑﻌﺪ ﻣﻘﺪار ﺣﺴﺎب ﺷﺪه در ﺳﻤﺖ ﭼﭗ ﺗﺴﺎوي ﻛﭙﻲ ﻣﻲﺷﻮد‪ .‬ﻣﺜﻼ در‬ ‫;‪b = a*a‬‬

‫اول ‪ a*a‬ﺣﺴﺎب ﻣﻲﺷﻮد و اﻳﻦ ﻣﻘﺪار ﺣﺴﺎب ﺷﺪه در ‪ b‬ﻗﺮار ﻣﻲﮔﻴﺮد‪ .‬ﺣﺎﻻ اﮔﺮ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪a = a*a‬‬

‫ﺑﺎز ﻫﻢ ﻫﻤﻴﻦ اﺗﻔﺎق ﻣﻲاﻓﺘﺪ ﻳﻌﻨﻲ ﻣﺜﻼ اﮔﺮ ﻣﻘﺪار ‪ a‬ﻋﺪد ‪ 5‬ﺑﺎﺷﺪ ﺑﻌﺪ از اﺟﺮاي اﻳﻦ دﺳﺘﻮر ﻣﻘﺪار ‪ a‬ﺑﻪ ‪ 25‬ﺗﻐﻴﻴﺮ ﻣﻲ‪-‬‬ ‫ﻛﻨﺪ‪ .‬اﻳﻦ ﺟﺎﺳﺖ ﻛﻪ ﺳﺮ و ﺻﺪاي رﻳﺎﺿﻴﺪاﻧﺎن ﻣﺤﺘﺮم ) ﻛﻪ اﻟﺒﺘﻪ ﻣﻦ ﺧﻮدم را از آنﻫﺎ ﺟﺪا ﻧﻤﻲداﻧﻢ( ﺑﻠﻨﺪ ﻣﻲﺷﻮد ﻛﻪ‬ ‫ﭼﻨﻴﻦ ﭼﻴﺰي اﻣﻜﺎن ﻧﺪارد‪ .‬اﻟﺒﺘﻪ آنﻫﺎ ﺣﻖ دارﻧﺪ ﭼﻮن وﻗﺘﻲ در رﻳﺎﺿﻲ ﻣﺘﻐﻴﺮي ﻣﺜﻞ ﺗﻌﺮﻳﻒ ﻣﻲﺷﻮد دﻳﮕﺮ اﺟﺎزه‪-‬‬ ‫ي ﺗﻐﻴﻴﺮ ﻧﺪارد )ﻣﺘﻐﻴﺮي ﻛﻪ ﺗﻐﻴﻴﺮ ﻧﻤﻲﻛﻨﻪ!‬

‫(‪ .‬ﻣﺘﻐﻴﺮ ﻣﻲﮔﻮﻳﻨﺪ ﭼﻮن ﻣﻘﺪارش ﻣﻌﻠﻮم ﻧﻴﺴﺖ‪ .‬رﻳﺎﺿﻴﺪاﻧﺎن‬

‫ﺣﺪاﻛﺜﺮ ﻛﺎري ﻛﻪ ﻣﻲﺗﻮاﻧﻨﺪ ﺑﺮاي ﻣﻘﺪار دﻫﻲ اﻧﺠﺎم دﻫﻨﺪ اﻳﻦ اﺳﺖ ﻛﻪ ﻓﺮض ﻛﻨﻨﺪ ﺑﺮاﺑﺮ ﺑﺎ ‪ 1‬ﻳﺎ ‪ 5‬ﻳﺎ ﭼﻴﺰ‬ ‫دﻳﮕﺮي اﺳﺖ‪ .‬در ‪ C++‬ﻧﺎم ﻳﻚ ﻣﺘﻐﻴﺮ )ﻣﺜﻞ ‪ (a‬ﻧﺸﺎن دﻫﻨﺪه ﻣﻜﺎﻧﻲ از ﺣﺎﻓﻈﻪي ‪ RAM‬اﺳﺖ )ﺑﻪ زﺑﺎن ﺷﻨﺎﺳﺎن‬ ‫ﻋﺰﻳﺰ )و ﻛﻤﻲ اﻳﺮادﮔﻴﺮ( ﻣﻲﮔﻢ ﻛﻪ درﺳﺘﻪ ﻛﻪ ﺗﺮﻛﻴﺐ »ﺣﺎﻓﻈﻪي ‪) «RAM‬ﺗﻘﺮﻳﺒﺎ( ﻏﻠﻄﻪ و ﭘﺴﻨﺪﻳﺪه ﺗﺮ آن ﺑﻮد‬ ‫ﻛﻪ ﻓﻘﻂ ﺑﻨﻮﻳﺴﻢ »‪ «RAM‬وﻟﻲ ﺧﺐ اﻧﻘﺪر اﻳﺮاد ﻧﮕﻴﺮﻳﺪ دﻳﮕﻪ‬

‫‪17‬‬

‫‪www.pupuol.com‬‬

‫(‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻣﺘﻐﻴﺮﻫﺎي ‪ ،C++‬ﺑﺮﻋﻜﺲ ﻣﺘﻐﻴﺮﻫﺎي رﻳﺎﺿﻲ‪ ،‬ﻣﻘﺪار ﻧﻴﺴﺘﻨﺪ ﺑﻠﻜﻪ ﻣﻜﺎنﻫﺎﻳﻲ از ﺣﺎﻓﻈﻪ ﻫﺴﺘﻨﺪ‪ .‬ﺑﻨﺎﺑﺮاﻳﻦ ﻣﻘﺪار آنﻫﺎ‬ ‫ﻣﻲﺗﻮاﻧﺪ در ﻃﻮل ﺑﺮﻧﺎﻣﻪ ﺗﻐﻴﻴﺮ ﻛﻨﺪ‪ .‬ﻗﺒﻼ ﺗﻌﺮﻳﻒ ‪) assignment‬ﻫﻤﺎن ﺗﺴﺎوي( را دﻳﺪﻳﺪ‪ assignment .‬در‬ ‫ﺣﻘﻴﻘﺖ ﻣﻘﺪار ﻣﺘﻐﻴﺮ را ﻋﻮض ﻣﻲﻛﻨﺪ‪ .‬ﻣﺜﻼ ‪ a=2‬ﻣﻘﺪار ﻗﺴﻤﺘﻲ از )ﺣﺎﻓﻈﻪي( ‪ RAM‬را ﻛﻪ ﺑﺎ ‪ a‬ﻣﺸﺨﺺ ﺷﺪه ‪2‬‬ ‫ﻣﻲﮔﺬارد‪ .‬ﺣﺎل ﻣﻲﺗﻮاﻧﻴﻢ ﺑﺮﻧﺎﻣﻪي ﻗﺒﻠﻲ را ﺑﻪ ﺻﻮرت زﻳﺮ ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a‬‬ ‫;‪cin>> a‬‬ ‫;‪a++‬‬ ‫;‪a = a*a‬‬ ‫;‪--a‬‬ ‫;‪cout<< a‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬ ‫‪35‬‬

‫اﻳﻦ ﺑﺮﻧﺎﻣﻪ را ﻓﻘﻂ ﺑﺮاي آﻣﻮزش اﻳﻦ ﻃﻮر ﻧﻮﺷﺘﻪام‪ .‬اﮔﺮ اﻳﻦ ﻫـﺪف را ﻧﺪاﺷﺘﻢ آن را ﺧﻴﻠﻲ راﺣﺖ ﺑﻪ ﺻﻮرت زﻳﺮ‬ ‫ﻣﻲﻧﻮﺷﺘﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a‬‬ ‫;‪cin>> a‬‬ ‫;‪cout<< (a+1)*(a+1)-1‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬ ‫‪35‬‬

‫‪18‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫! ار ه ‬

‫در ﺟﺪول ﺻﻔﺤﻪ ‪ 3‬ﻧﻮﻋﻲ ﺑﺎ ﻧﺎم ‪ bool‬ﻣﻌﺮﻓﻲ ﺷﺪ‪ .‬در آن ﺟﺎ ﮔﻔﺘﻢ ﻫﺮ ﻣﺘﻐﻴﺮ ﺑﺎ اﻳﻦ ﻧﻮع ﻳﻚ ﮔﺰاره اﺳﺖ و‬ ‫ﮔﺰاره ﻋﺒﺎرﺗﻲ اﺳﺖ ﻛﻪ ﻳﺎ درﺳﺖ اﺳﺖ ﻳﺎ ﻏﻠﻂ‪ .‬ﻗﺒﻞ از اﻳﻦ ﻛﻪ ﺑﻴﺶﺗﺮ ﺗﻮﺿﻴﺢ ﺑﺪﻫﻢ ﺑﮕﺬارﻳﺪ ﻋﻤﻠﮕﺮﻫﺎي ﻣﻨﻄﻘﻲ را‬ ‫ﻣﻌﺮﻓﻲ ﻛﻨﻢ‪:‬‬ ‫ﻣﺜﺎل‬

‫ﺗﻮﺿﻴﺤﺎت‬

‫ﻋﻤﻠﮕﺮ‬

‫‪a < b‬‬

‫آﻳﺎ ﻛﻮﭼﻚ ﺗﺮ اﺳﺖ؟‬

‫<‬

‫‪6 > 2‬‬

‫آﻳﺎ ﺑﺰرگ ﺗﺮ اﺳﺖ؟‬

‫>‬

‫‪ 5 <= 5‬آﻳﺎ ﻛﻮﭼﻚ ﺗﺮ ﻳﺎ ﻣﺴﺎوي اﺳﺖ؟‬

‫=<‬

‫‪a >= b‬‬

‫آﻳﺎ ﺑﺰرگ ﺗﺮ ﻳﺎ ﻣﺴﺎوي اﺳﺖ؟‬

‫=>‬

‫‪a == 2‬‬

‫آﻳﺎ ﻣﺴﺎوي اﺳﺖ؟‬

‫==‬

‫‪1 != 2‬‬

‫آﻳﺎ ﻣﺴﺎوي ﻧﻴﺴﺖ؟‬

‫=!‬

‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ >= و <= )ﻛﻪ در آنﻫﺎ ﺗﺴﺎوي‪ ،‬ﺳﻤﺖ ﭼﭗ اﺳﺖ( در ‪ C++‬ﻋﻤﻠﮕﺮ ﻧﻴﺴﺘﻨﺪ‪ .‬در ﺿﻤﻦ ﺑﻴﻦ < ﻳﺎ‬ ‫> و = ﻧﺒﺎﻳﺪ ﻫﻴﭻ ﻓﺎﺻﻠﻪاي ﺑﺎﺷﺪ‪ .‬ﻳﻌﻨﻲ اﮔﺮ ﺑﻨﻮﻳﺴﻴﺪ ‪= 5‬‬

‫)‪ error‬ﺑﻪ ﻣﻌﻨﻲ ﺧﻄﺎﺳﺖ‬

‫< ‪ compiler ،5‬ﻳﻚ ‪ error‬ﺻﺎدر ﻣﻲﻛﻨﺪ‪.‬‬

‫ در دن ه وج و ت از "!ر‪%‬‬

‫(‪.‬‬

‫ﺣﺎﻻ ﻣﻲﺗﻮاﻧﻴﻢ ﻳﻚ ﻣﺘﻐﻴﺮ از ﻧﻮع ‪ bool‬ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ و ﺑﻪ آن ﻣﻘﺪار ﺑﺪﻫﻴﻢ‪:‬‬ ‫;‪bool b‬‬ ‫;)‪b = (2 < 3‬‬

‫ﻳﻚ ﻣﺘﻐﻴﺮ ﺑﺎ ﻧﻮع ‪ bool‬ﺗﻨﻬﺎ ﻣﻲﺗﻮاﻧﺪ دو ﻣﻘﺪار داﺷﺘﻪ ﺑﺎﺷﺪ ‪ true :‬ﻳﺎ ‪ false. true‬ﺑﻪ ﻣﻌﻨﻲ »درﺳﺖ« و‬ ‫‪ false‬ﺑﻪ ﻣﻌﻨﻲ »ﻏﻠﻂ« اﺳﺖ‪ .‬ﻣﺜﻼ ﻣﻲداﻧﻴﻢ ﻛﻪ )‪ (2<3‬ﺑﺮاﺑﺮ ﺑﺎ ‪ true‬و )‪ (6==5‬ﺑﺮاﺑﺮ ﺑﺎ ‪ false‬اﺳﺖ‪.‬‬ ‫اﮔﺮ ﻳﻚ ﻣﻘﺪار ﺑﺎ ﻧﻮع ‪ bool‬را ﺑﺎ ‪ cout‬ﭼﺎپ ﻛﻨﻴﺪ ‪ 0‬ﻳﺎ ‪ 1‬ﭼﺎپ ﻣﻲﺷﻮد‪ 0 .‬ﺑﺮاي ‪ false‬و ‪ 1‬ﺑﺮاي‬ ‫‪ .true‬ﻣﺜﻼ‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪bool b = (2 == 2‬‬ ‫;‪cout<< b‬‬ ‫;)(‪getch‬‬

‫‪19‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬

‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ‪ b==2‬ﻳﻌﻨﻲ »ﻣﻘﺪار ‪ b‬ﺑﺮاﺑﺮ ﺑﺎ ‪ 2‬اﺳﺖ« وﻟﻲ ‪ b = 2‬ﻳﻌﻨﻲ »ﻣﻘﺪار ‪ b‬را ﺑﻪ ‪ 2‬ﺗﺒﺪﻳﻞ ﻛﻦ«‪ .‬اﮔﺮ‬ ‫ﻫﻨﻮز ﻣﻨﻈﻮر ﻣﻦ را از ﮔﺰاره ﻣﺘﻮﺟﻪ ﻧﺸﺪهاﻳﺪ ﺣﻖ دارﻳﺪ‪ .‬اﻳﻦ ﺑﻪ اﻳﻦ ﺧﺎﻃﺮ اﺳﺖ ﻛﻪ ﻫﻨﻮز دﺳﺘﻮر ‪ if‬را ﻣﻌﺮﻓﻲ‬ ‫ﻧﻜﺮدهام‪.‬‬

‫د‪ "#‬ر ‪if‬‬

‫اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﻢ ﻛﻪ ﻋﺪدﻫﺎي زوج و ﻓﺮد را ﺗﺸﺨﻴﺺ دﻫﺪ ﺑﺎﻳﺪ از ‪ if‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ .‬ﺑﺮﻧﺎﻣﻪي زﻳﺮ‬ ‫ﻳﻚ ‪ int‬را )ﻳﻌﻨﻲ ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ را( از ﻛﺎرﺑﺮ ﻣﻲﮔﻴﺮد‪ ،‬اﮔﺮ زوج ﺑﻮد ﻋـﺒﺎرت "‪ "it is even‬و اﮔﺮ‬ ‫ﻓﺮد ﺑﻮد ﻋـﺒﺎرت "‪ "it is odd‬را ﭼﺎپ ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a‬‬ ‫;‪cin>> a‬‬ ‫)‪if(a%2 == 0‬‬ ‫;"‪cout<< "it is even‬‬ ‫)‪if(a%2 == 1‬‬ ‫;"‪cout<< "it is odd‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪7‬‬ ‫‪it is odd‬‬

‫اﻳﻦ ﺑﺮﻧﺎﻣﻪ اول ﺣﺎﻓﻈﻪاي ﺑﻪ اﻧﺪارهي ‪ 4‬ﺑﺎﻳﺖ ﺑﺮاي ﻳﻚ ‪ int‬ﺑﺎ اﺳﻢ ‪ a‬ﺗﺨﺼﻴﺺ ﻣﻲدﻫﺪ‪ .‬ﺑﻌﺪ ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ از‬ ‫ﻛﺎرﺑﺮ ﻣﻲﮔﻴﺮد و آن را در ‪ a‬ﻗﺮار ﻣﻲدﻫﺪ‪ .‬اﮔﺮ ﺑﺎﻗﻲ ﻣﺎﻧﺪهي ‪ a‬ﺑﺮ ‪ 2‬ﺻﻔﺮ ﺑﺎﺷﺪ )ﻳﻌﻨﻲ اﮔﺮ زوج ﺑﺎﺷﺪ(‪ ،‬ﭘﻴﺎم ‪it‬‬

‫‪ is even‬ﭼﺎپ ﻣﻲﺷﻮد‪ .‬اﮔﺮ ﺑﺎﻗﻲ ﻣﺎﻧﺪهي ‪ a‬ﺑﺮ ‪ 2‬ﻳﻚ ﺑﺎﺷﺪ‪ ،‬ﭘﻴﺎم ‪ it is odd‬ﭼﺎپ ﻣﻲﺷﻮد‪ .‬ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬ ‫ﭼﻮن ﺑﺎﻗﻲ ﻣﺎﻧﺪهي ‪ 7‬ﺑﺮ ‪ 2‬ﻳﻚ اﺳﺖ )ﻳﻌﻨﻲ ﭼﻮن ‪ 7‬ﻓﺮد اﺳﺖ( ﭘﻴﺎم ‪ it is odd‬ﭼﺎپ ﺷﺪه اﺳﺖ‪ .‬ﻣﻲﺷﻮد‬ ‫ﮔﻔﺖ ‪ if‬ﺳﺎﺧﺘﺎر زﻳﺮ را دارد‪:‬‬

‫‪20‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)‪67‬ار‪if(3‬‬ ‫;د‪89:‬ر‬

‫ﭘﺮاﻧﺘﺰﻫﺎي ﺑﻌﺪ از ‪ if‬ﺿﺮوري ﻫﺴﺘﻨﺪ‪ .‬اﮔﺮ ﻣﻘﺪار ‪23‬ار‪ ،/‬ﺑﺮاﺑﺮ ﺑﺎ ‪ true‬ﺑﺎﺷﺪ )ﻳﻌﻨﻲ اﮔﺮ درﺳﺖ ﺑﺎﺷﺪ(‪،‬‬ ‫د‪456‬ر اﺟﺮا ﻣﻲﺷﻮد وﮔﺮﻧﻪ د‪456‬ر ﺑﺪون اﺟﺮا ﻧﺎدﻳﺪه ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد‪ .‬ﻣﺜﻼ‬ ‫)‪if(3 > 4‬‬ ‫;"‪cout<< "hello‬‬

‫ﻫﻴﭻ ﻛﺎري اﻧﺠﺎم ﻧﻤﻲدﻫﺪ ﭼﻮن ‪ 3 > 4‬ﻧﺎدرﺳﺖ اﺳﺖ‪ .‬ﺧﻮد‬ ‫)‪if(3 > 4‬‬ ‫;"‪cout<< "hello‬‬

‫ﻳﻚ دﺳﺘﻮر اﺳﺖ‪ .‬ﭘﺲ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;"‪cout<< "hello‬‬

‫)‪if(a == 4‬‬ ‫)‪if(3 > 4‬‬

‫ﻫﻴﭻ ﻻزم ﻧﻴﺴﺖ اﻳﻦ دﺳﺘﻮرات در دو ﻳﺎ ﭼﻨﺪ ﺧﻂ ﻧﻮﺷﺘﻪ ﺑﺸﻮﻧﺪ‪ .‬در ‪ C++‬ﺣﺘﻲ ﻣﻲﺷﻮد ﻳﻚ ﺑﺮﻧﺎﻣﻪي ﺧﻴﻠﻲ ﻃﻮﻻﻧﻲ‬ ‫را در دو ﻳﺎ ﺳﻪ ﺧﻂ ﻧﻮﺷﺖ‪ .‬اﻣﺎ واﺿﺢ اﺳﺖ ﻛﻪ اﻳﻦ ﻛﺎر اﺻﻼ ﻣﻨﺎﺳﺐ ﻧﻴﺴﺖ‪ .‬در ﺿﻤﻦ ﮔﺬاﺷﺘﻦ ‪ =) space‬ﺟﺎي‬ ‫ﺧﺎﻟﻲ( و ‪ tab‬ﺑﻪ ﻫﺮ ﺗﻌﺪاد ﻣﺠﺎز اﺳﺖ و اﺿﺎﻓﻲﻫﺎ ﻧﺎدﻳﺪه ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮﻧﺪ‪ .‬ﻣﻦ در ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪﻫﺎ از ﻳﻚ اﺳﺘﺎﻧﺪارد‬ ‫ﭘﻴﺮوي ﻣﻲﻛﻨﻢ و ﺷﻤﺎ ﻫﻢ از ﻫﻤﻴﻦ اﺑﺘﺪا ﺑﺎﻳﺪ ﭼﻨﻴﻦ اﺳﺘﺎﻧﺪاردي را رﻋﺎﻳﺖ ﻛﻨﻴﺪ وﮔﺮﻧﻪ ﻫﺮﮔﺰ ﻳﻚ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ‬ ‫ﺣﺮﻓﻪاي ﻧﻤﻲﺷﻮﻳﺪ‪ .‬ﺑﺎ ﺗﺎﻛﻴﺪ ﻓﺮاوان ﻣﻲﮔﻮﻳﻢ ﻛﻪ ﺣﺘﻤﺎ ﺑﻪ زﻳﺒﺎﻳﻲ و اﺳﺘﺎﻧﺪارد ﺑﻮدن ﻧﺤﻮهي ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ و ﺗﻨﻈﻴﻢ‬ ‫ﺧﻄﻮط ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪ .‬ﺷﺎﻳﺪ اﻳﻦ اﺻﻼ ﺑﺮاﻳﺘﺎن ﻣﻬﻢ ﺑﻪ ﻧﻈﺮ ﻧﺮﺳﺪ وﻟﻲ واﻗﻌﺎ ﻣﻬﻢ اﺳﺖ‪.‬‬ ‫ﻫﺮ دو ﺻﻮرت ﻧﻮﺷﺘﻦ ﻛﻪ در زﻳﺮ ﻧﺸﺎن داده ﺷﺪه ﻏﻴﺮ ﻋﺎدي و ﻏﻴﺮ اﺳﺘﺎﻧﺪارد اﺳﺖ وﻟﻲ از ﻧﻈﺮ ‪ compiler‬ﻣﺠﺎز‬ ‫اﺳﺖ و ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ ﺑﺪون ‪ error‬اﺟﺮا ﺧﻮاﻫﺪ ﺷﺪ‪:‬‬ ‫‪if‬‬ ‫(‬ ‫== ‪a‬‬ ‫‪2‬‬ ‫)‬ ‫‪cout‬‬ ‫<<‬ ‫"‪"hello‬‬ ‫;‬ ‫;"‪if(a==2)cout<<"hello‬‬

‫)‪1‬‬

‫)‪2‬‬

‫ﺷﻜﻞ اﺳﺘﺎﻧﺪارد اﻳﻦ اﺳﺖ‪:‬‬ ‫)‪if(a==2‬‬ ‫;"‪cout<<"hello‬‬

‫‪ true‬ﻳﻚ ﮔﺰارهي درﺳﺖ اﺳﺖ و ‪ false‬ﻳﻚ ﮔﺰارهي ﻏﻠﻂ اﺳﺖ‪ .‬ﺑﻨﺎﺑﺮاﻳﻦ‬

‫‪21‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)‪if(true‬‬ ‫;"‪cout<<"hello‬‬

‫و‬ ‫)‪if(1 == 1‬‬ ‫;"‪cout<<"hello‬‬

‫و‬ ‫)‬

‫‪(1 == 1) == true‬‬ ‫;"‪cout<<"hello‬‬

‫(‪if‬‬

‫و‬ ‫;"‪cout<<"hello‬‬

‫ﻫﻤﻪ ﻳﻚ ﺟﻮر ﻋﻤﻞ ﻣﻲﻛﻨﻨﺪ‪ .‬ﻧﻮﺷﺘﻦ‬ ‫)‪if(false‬‬ ‫;"‪cout<<"hello‬‬

‫ﻫﻢ ﺑﺎ ﻧﻨﻮﺷﺘﻦ آن ﻳﻜﻲ اﺳﺖ‪.‬‬ ‫ﻣﻤﻜﻦ اﺳﺖ ﻫﻨﻮز ﻗﺎدر ﻧﺒﺎﺷﻴﺪ ﻣﻌﻨﻲ ﮔﺰاره را ﺧﻴﻠﻲ ﺧﻮب ﺑﻴﺎن ﻛﻨﻴﺪ وﻟﻲ ﺣﺎﻻ دﻳﮕﺮ ﺑﺎﻳﺪ ﺑﺘﻮاﻧﻴﺪ از ‪ if‬اﺳﺘﻔﺎده‬ ‫ﻛﻨﻴﺪ ‪ .‬ﻫﻨﻮز ﭼﻴﺰﻫﺎﻳﻲ ﻫﺴﺖ ﻛﻪ ﻧﮕﻔﺘﻪام‬

‫‪.‬‬

‫ ‪ $‬ار و "‪ %‬‬

‫ﺣﺎل ﻓﺮض ﻛﻨﻴﺪ ‪ a‬و‪ b‬دو ﻣﺘﻐﻴﺮ از ﻧﻮع ‪ int‬ﻫﺴﺘﻨﺪ‪ a==b .‬ﻳﻌﻨﻲ ﻣﺤﺘﻮﻳﺎت دو ﻣﺤﻞ از ﺣﺎﻓﻈﻪ ﻛﻪ ﺑﺎ ‪ a‬و ‪ b‬ﺑﻪ‬ ‫آنﻫﺎ اﺷﺎره ﻣﻲﺷﻮد ﻣﺴﺎوي ﻫﺴﺘﻨﺪ ﻣﺜﻼ ﺑﻪ ﺷﻜﻞ زﻳﺮ ﻫﺴﺘﻨﺪ‪:‬‬ ‫‪a:‬‬ ‫‪0 1 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 1 0 0 1 1‬‬ ‫‪b:‬‬ ‫‪0 1 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 1 1 1 1 1 1 0 1 0 0 1 1‬‬

‫ﺣﺘﻤﺎ ﻣﻲداﻧﻴﺪ ﻛﻪ ﻫﻤﻪ ﭼﻴﺰ ﺣﺘﻲ اﻋﺪاد در ﻛﺎﻣﭙﻴﻮﺗﺮ ﺑﻪ ﺻﻔﺮ و ﻳﻚ ﺗﺒﺪﻳﻞ ﻣﻲﺷﻮﻧﺪ و ﺑﻌﺪ ذﺧﻴﺮه ﻣﻲﺷﻮﻧﺪ‪ .‬در واﻗﻊ‬ ‫‪ 01101111000011100001111111010011‬ﻫﻤﺎن ﻋﺪد ‪ 1863196627‬اﺳﺖ‪) .‬ﺑﺮاي اﻳﻦ ﻛﻪ‬ ‫ﭼﺸﻤﺎﺗﻮن ﺑﻪ ﺧﺎﻃﺮ ﺧﻮاﻧﺪن اﻳﻦ ﻧﻮﺷﺘﻪ ﺧﻴﻠﻲ درد ﻧﮕﻴﺮه‬

‫)و ﻧﻪ ﺑﺮاي اﻳﻦ ﻛﻪ ﺧﻮدم از ﺷﺮ ﺗﺎﻳﭗ ﻛﺮدن راﺣﺖ‬

‫ﺑﺸﻢ(‪ ،‬ﻧﺤﻮهي ﺗﺒﺪﻳﻞ ‪ 01101111000011100001111111010011‬رو ﺑﻪ ‪ 1863196627‬ﻧﻤﻲﮔﻢ‪ .‬ﺑﻪ‬ ‫ﻫﺮ ﺣﺎل ﻫﺮ ﺟﺎ ﻧﻴﺎز ﺑﻪ ﺗﺒﺪﻳﻞ داﺷﺘﻴﺪ از ﻣﺎﺷﻴﻦ ﺣﺴﺎب وﻳﻨﺪوز ﻛﻤﻚ ﺑﮕﻴﺮﻳﺪ(‪.‬‬

‫‪22‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﭘﺲ ‪ a==b‬ﻳﻌﻨﻲ »ﻣﻘﺪار ‪ a‬و ‪ b‬ﻳﻜﻲ اﺳﺖ«‪ .‬در ﺿﻤﻦ ‪ a==2‬ﻳﻌﻨﻲ »ﻣﻘﺪار ‪ a‬ﻣﺴﺎوي ﺑﺎ ‪ 2‬اﺳﺖ« و »‪3==2‬‬

‫ﻳﻌﻨﻲ ‪ 2‬ﺑﺮاﺑﺮ اﺳﺖ ﺑﺎ ‪.«3‬‬ ‫ﻣﻨﻈﻮر ﻣﻦ از ﻣﻄﺎﻟﺐ اﻳﻦ ﺑﺨﺶ اﻳﻦ اﺳﺖ ﻛﻪ ﻣﺘﻐﻴﺮ ‪ a‬ﺑﺎ ﻣﻘﺪارش ﻣﺘﻔﺎوت اﺳﺖ اﻣﺎ وﻗﺘﻲ ﺑﺨﻮاﻫﻴﻢ از ﻣﻘﺪار ‪a‬‬

‫اﺳﺘﻔﺎده ﻛﻨﻴﻢ ﺧﻮد ‪ a‬را ﻣﻲﻧﻮﻳﺴﻢ‪ .‬در ‪ a ،a=1‬ﺑﻪ ﻋﻨﻮان ﻣﻜﺎﻧﻲ از ﺣﺎﻓﻈﻪ اﺳﺖ وﻟﻲ در ‪ a ،a==1‬ﺑﻪ ﻋﻨﻮان ﻣﻘﺪار‬ ‫ﺑﻪ ﻛﺎر رﻓﺘﻪ اﺳﺖ‪.‬‬

‫' &ه ‬

‫ﺣﺘﻤﺎ در رﻳﺎﺿﻲ دورهي دﺑﻴﺮﺳﺘﺎن ﺑﺎ ﻣﻔﻬﻮم ﺗﺎﺑﻊ آﺷﻨﺎ ﺷﺪهاﻳﺪ )اﮔﺮ ﻫﻨﻮز ﺑﻪ دور هي دﺑﻴﺮﺳﺘﺎن ﻧﺮﺳﻴﺪهاﻳﺪ ﻳﺎ ﺑﻪ ﻫﺮ‬ ‫دﻟﻴﻞ دﻳﮕﺮ ﺑﺎ ﻣﻔﻬﻮم ﺗﺎﺑﻊ آﺷﻨﺎ ﻧﻴﺴﺘﻴﺪ‪ .‬اﺑﺘﺪا اﻳﻦ ﺑﺨﺶ را ﺑﺨﻮاﻧﻴﺪ و اﮔﺮ ﻣﺘﻮﺟﻪ ﻧﺸﺪﻳﺪ ﺑﻪ ﭘﺎﻳﮕﺎه ﻛﺘﺎبﻫﺎي درﺳﻲ‬ ‫اﻳﺮان )اﺣﺘﻤﺎﻻ ﺑﺎ آدرس ‪ (www.chap.sch.ir‬ﻣﺮاﺟﻌﻪ ﻛﻨﻴﺪ و ﻛﺘﺎب رﻳﺎﺿﻲ ﺳﺎل دوم رﺷﺘﻪي رﻳﺎﺿﻲ ﻓﻴﺰﻳﻚ‬ ‫را ‪ download‬و ﻣﻄﺎﻟﻌﻪ ﺑﻜﻨﻴﺪ‪ .‬ﺑﻪ ﻃﻮر ﺳﺎده ﺗﺎﺑﻊ ﻳﻌﻨﻲ ﻓﺮﻣﻮل(‪.‬‬ ‫ﺗﺎﺑﻊ‬ ‫ ‬

‫را در ﻧﻈﺮ ﺑﮕﻴﺮﻳﺪ‪ .‬ﺑﺮاي ﻣﺤﺎﺳﺒﻪي ﺑﮕﺬارﻳﻢ ﺟﺎي ﺑﻪ ﺑﺎﻻ ﻓﺮﻣﻮل در اﺳﺖ ﻛﺎﻓﻲ ‪:‬‬

‫ﭘﺲ ﺑﺮاﺑﺮ ﺑﺎ اﺳﺖ‪ .‬ﺑﻪ ‪) argument ،2‬ﻳﺎ آرﮔﻮﻣﺎن( ﻣﻲﮔﻮﻳﻨﺪ‪ .‬در ‪ C++‬ﻫﻢ ﻣﻲﺷﻮد ﺗﺎﺑﻊﻫﺎﻳﻲ ﻣﺜﻞ‬ ‫اﻳﻦ ﻧﻮﺷﺖ‪ .‬ﻫﻤﻴﻦ ﺗﺎﺑﻊ در ‪ C++‬ﺑﻪ ﺷﻜﻞ زﻳﺮ ﻧﻮﺷﺘﻪ ﻣﻲﺷﻮد‪:‬‬ ‫)‪double f(double x‬‬ ‫{‬ ‫;‪return x*x - x + 1‬‬ ‫}‬

‫اوﻟﻴﻦ ‪ double‬ﻧﻮع ﺧﺮوﺟﻲ ﺗﺎﺑﻊ را ﻣﺸﺨﺺ ﻣﻲﻛﻨﺪ‪ .‬ﻳﻌﻨﻲ )‪ f(-1) ،f(2) ،f(1.1‬و‪ ...‬ﻫﻤﻪ ﻣﻘﺪارﻫﺎﻳﻲ ﺑﺎ‬ ‫ﻧﻮع ‪ double‬ﻳﻌﻨﻲ ﻋﺪد اﻋﺸﺎري ﻫﺴﺘﻨﺪ‪ .‬دوﻣﻴﻦ ‪ double‬ﻣﻲﮔﻮﻳﺪ ﻛﻪ ورودي ﺗﺎﺑﻊ ﻳﺎ ﻫﻤﺎن ‪ argument‬ﻛﻪ‬ ‫در ﺑﺎﻻ ﻣﻌﺮﻓﻲ ﻛﺮدم ﺑﺎﻳﺪ ﺑﺎ ﻧﻮع ‪ double‬ﺑﺎﺷﺪ‪ .‬ﻣﺜﻼ ﻣﻲﺗﻮان ﻧﻮﺷﺖ )‪ f(2.32‬اﻣﺎ ﻧﻤﻲﺗﻮان ﻧﻮﺷﺖ‬ ‫)"‪ f("hello‬زﻳﺮا "‪ "hello‬ﻳﻚ رﺷﺘﻪ اﺳﺖ ﻧﻪ ﻳﻚ ﻋﺪد‪ .‬ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ return‬ﻣﻘﺪاري را ﻛﻪ‬ ‫)‪) f(x‬ﺑﻪ ازاي ‪ x‬داده ﺷﺪه( ﺑﺎﻳﺪ داﺷﺘﻪ ﺑﺎﺷﺪ ﻣﻌﻴﻦ ﻣﻲﻛﻨﺪ‪.‬‬

‫‪23‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻋﺪهاي از ﻛﻠﻤﺎت در ‪ C++‬ﻛﻠﻴﺪي ﻫﺴﺘﻨﺪ‪ .‬در اﻏﻠﺐ ‪compiler‬ﻫﺎي ﻣﻌﺘﺒﺮ وﻗﺘﻲ اﻳﻦ ﻛﻠﻤﺎت ﻧﻮﺷﺘﻪ ﻣﻲﺷﻮﻧﺪ‬ ‫رﻧﮓ آنﻫﺎ ﻋﻮض ﻣﻲﺷﻮد‪ .‬ﻣﻦ ‪ compiler‬ﺧﻮدم را ﻃﻮري ﺗﻨﻈﻴﻢ ﻛﺮدهام ﻛﻪ اﻳﻦ ﻛﻠﻤﺎت ﺳﻔﻴﺪ رﻧﮓ ﺷﻮﻧﺪ‪ .‬ﺑﻪ‬ ‫ﻋﻜﺲ زﻳﺮ ﻛﻪ ﻣﻦ از ‪compiler‬م ﮔﺮﻓﺘﻪام ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻛﻠﻤﻪﻫﺎي ﻛﻠﻴﺪي ‪ return‬و ‪ double‬ﺑﻪ رﻧﮓ ﺳﻔﻴﺪ ﻫﺴﺘﻨﺪ‪ .‬ﻋـﻠﺖ ِ اﻳﻦ ﻛﻪ رﻧﮓ زﻣﻴﻨﻪ را آﺑﻲ‬ ‫ﺗﻴﺮه ﮔﺮﻓﺘﻪام اﻳﻦ اﺳﺖ ﻛﻪ ﭼﺸﻢ ﻛﻢ ﺗﺮ اذﻳﺖ ﺑﺸﻮد‪ ) .‬ﺑﺒﻴﻨﻴﺪ اوﻻ ﻣﻦ ﭼﺸﻢ ﭘﺰﺷﻚ ﻧﻴﺴﺘﻢ ﻛﻪ ﺑﺪوﻧﻢ ﺑﺎ ﭼﻪ رﻧﮓ‬ ‫زﻣﻴﻨﻪاي ﭼﺸﻢ ﻛﻢ ﺗﺮ آﺳﻴﺐ ﻣﻲﺑﻴﻨﻪ و ﺛﺎﻧﻴﺎ اﮔﺮ ﺷﻤﺎم ﻣﻲﺧﻮاﻳﺪ از ‪ compiler‬ﺧﻮد ﻋﻜﺲ ﺑﮕﻴﺮﻳﺪ ﻛﻠﻴﺪﻫﺎي‬ ‫‪ Alt + Print_Screen‬را ﻓﺸﺎر ﺑﺪﻳﺪ و ﻋﻜﺲ رو در ﻧﺮم اﻓﺰار ‪ Paint‬وﻳﻨﺪوز ‪ paste‬ﻛﻨﻴﺪ‪ .‬ﻛﻠﻴﺪ‬ ‫‪ Print_Screen‬ﻫﻢ ﻳﻜﻲ از ﺳﻪ ﺗﺎ ﻛﻠﻴﺪ ﭘﻴﺶ ﻫﻢ در ﮔﻮﺷﻪي ﺑﺎﻻ و راﺳﺖ ‪keyboard‬ده‪ .‬در ﺿﻤﻦ »ﻛﻠﻤﻪ‪-‬‬ ‫ي ﻛﻠﻴﺪي« ﺗﺮﺟﻤﻪي ‪keyword‬ده‬

‫(‪.‬‬

‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ از ﺗﺎﺑﻊ ﻣﻌﺮﻓﻲ ﺷﺪه در ﺑﺎﻻ اﺳﺘﻔﺎده ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪double f(double x‬‬ ‫{‬ ‫;‪return x*x - x + 1‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪cout<< f(2‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪3‬‬

‫‪24‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻛﻪ ﺑﺎ ﻣﻘﺪاري ﻛﻪ از راه رﻳﺎﺿﻲ ﺑﻪ دﺳﺖ آورده ﺑﻮدﻳﻢ ﻳﻜﻲ اﺳﺖ‪.‬‬ ‫ﺗﺎﺑﻊﻫﺎي ‪ C++‬ﺑﺮ ﻋﻜﺲ ﺗﻮاﺑﻊ رﻳﺎﺿﻲ ﺧﻴﻠﻲ ﺑﻲ دﺳﺖ و ﭘﺎ ﻧﻴﺴﺘﻨﺪ‪ .‬ﻣﺜﻼ در ﻣﺜﺎل ﺑﺎﻻ ﻣﻲﺷﻮد ﺧﻮد ﺗﺎﺑﻊ ‪ f‬را وادار‬ ‫ﺑﻪ ﭼﺎپ ﻣﻘﺪارش ﻛﺮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪double f(double x‬‬ ‫{‬ ‫;‪int a = x*x - x + 1‬‬ ‫;‪cout<< a‬‬ ‫;‪return a‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪f(2‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪3‬‬

‫ﻫﻤﺎن ﻃﻮر ﻛﻪ ﻣﻲﺑﻴﻨﻴﺪ در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻧﻴﺎزي ﺑﻪ ﺧﺮوﺟﻲ ﺗﺎﺑﻊ ﻧﺪارﻳﻢ‪ .‬ﭘﺲ ﺑﻬﺘﺮ اﺳﺖ ﺗﺎﺑﻊ را ﻃﻮري ﺗﻌﺮﻳﻒ ﻛﻨﻢ ﻛﻪ‬ ‫ﺧﺮوﺟﻲ ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪void f(double x‬‬ ‫{‬ ‫;‪int a = x*x - x + 1‬‬ ‫;‪cout<< a‬‬ ‫;‪return‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪f(2‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪3‬‬

‫‪ void‬ﻳﻌﻨﻲ اﻳﻦ ﻛﻪ ﺗﺎﺑﻊ ﺧﺮوﺟﻲ ﻧﺪارد‪.‬‬

‫‪25‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻫﻤﺎن ﻃﻮر ﻛﻪ در رﻳﺎﺿﻴﺎت ﺗﺎﺑﻊﻫﺎي ﭼﻨﺪ ﻣﺘﻐﻴﺮه دارﻳﻢ‪ ،‬در ‪ C++‬ﻫﻢ ﺗﺎﺑﻊﻫﺎ ﻣﻲﺗﻮاﻧﻨﺪ ﭼﻨﺪ ﭘﺎراﻣﺘﺮ داﺷﺘﻪ ﺑﺎﺷﻨﺪ‪.‬‬ ‫ﻣﺜﻼ‬ ‫)‪int f(int a, char* c‬‬ ‫{‬ ‫;‪cout<< c‬‬ ‫;‪return a*a‬‬ ‫}‬

‫دو ﭘﺎراﻣﺘﺮ دارد‪ .‬ﭘﺎراﻣﺘﺮ اول ﻳﻚ ‪ int‬اﺳﺖ و ﭘﺎراﻣﺘﺮ دوم ﻳﻚ رﺷﺘﻪ اﺳﺖ‪ .‬اﻳﻦ ﺗﺎﺑﻊ ﺑﻌﺪ از ﻓﺮاﺧﻮاﻧﻲ‪ ،‬رﺷﺘﻪ را‬ ‫ﭼﺎپ ﻣﻲﻛﻨﺪ و ﻣﺮﺑﻊ ‪ a‬را ﺑﻪ ﻋﻨﻮان ﺧﺮوﺟﻲ ﺑﺮ ﻣﻲﮔﺮداﻧﺪ )ﻣﺮﺑﻊ ﻫﻢ ﻛﻪ ﻳﻌﻨﻲ ﺗﻮان دوم ﻳﺎ ﻣﺠﺬور ﻳﺎ ﻫﻤﺎن‬ ‫‪ square‬ﺧﻮدﻣﺎن‬

‫(‪.‬‬

‫ﺑﻪ ﻣﺜﺎل زﻳﺮ ﻛﻪ ﻓﻬﻢ آن ﻛﻤﻲ ﺳﺨﺖ اﺳﺖ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪int f(int a, char* c‬‬ ‫{‬ ‫;‪cout<< c << a‬‬ ‫;‪return a*a‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)" ‪cout<< endl << f(2,"an integer‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪an integer 2‬‬ ‫‪4‬‬ ‫ﻧﻜﺎت زﻳﺎدي در اﻳﻦ ﻣﺜﺎل وﺟﻮد دارد‪ .‬اوﻟﻴﻦ و ﻣﻬﻢ ﺗﺮﻳﻦ آنﻫﺎ اﻳﻦ اﺳﺖ ﻛﻪ ﺑﺮاي ﭼﺎپ دو ﻣﻘﺪار ﺑﺎ ‪ cout‬ﻻزم‬

‫ﻧﻴﺴﺖ دو ﺑﺎر از ‪ cout‬اﺳﺘﻔﺎده ﺷﻮد و ﺑﻪ ﺟﺎي‬ ‫;‪cout<< c‬‬ ‫;‪cout<< a‬‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;‪cout<< c << a‬‬

‫ﻧﻜﺘﻪي ﺑﻌﺪي آن اﺳﺖ ﻛﻪ ﺑﺮاي اﻳﻦ ﻛﻪ ﭼﺎپ ﺑﻘﻴﻪي ﻣﻘﺪارﻫﺎ ﺑﻪ ﺧﻂ ﺑﻌﺪي ﻣﻨﺘﻘﻞ ﺷﻮد ﻣﻲﻧﻮﻳﺴﻢ‪:‬‬ ‫;‪cout<< endl‬‬

‫در ﻋﻮض ﻣﻲﺗﻮاﻧﻴﺪ ﺑﻨﻮﻳﺴﻴﺪ‪:‬‬ ‫;"‪cout<< "\n‬‬

‫‪26‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻳﺎ‬ ‫;'‪cout<< '\n‬‬

‫در ﺿﻤﻦ ﻫﻤﺎن ﻃﻮر ﻛﻪ ﺑﻪ ﺟﺎي‬ ‫;"‪cout<< "hello"<< "bye‬‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‬ ‫;"‪cout<< "hellobye‬‬

‫ﺑﻪ ﺟﺎي‬ ‫;"‪cout<< "hello" << "\n‬‬

‫ﻫﻢ ﻣﻲﺷﻮد ﻧﻮﺷﺖ‬ ‫;"‪cout<< "hello\n‬‬

‫ﻧﻜﺘﻪي ﺑﻌﺪي ﺗﺮﺗﻴﺐ اﺟﺮاﺳﺖ‪ .‬اول اﺟﺮاﻛﻨﻨﺪهي ﺧﻄﻮط ) ﻛﻪ ﺑﻪ آن ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ ﻣﻲﮔﻮﻳﻨﺪ( ﺑﻪ ﺳﺮاغ‬ ‫‪cout‬ي ﻣﻲرود ﻛﻪ ﺑﻌﺪ از ‪ main‬ﻗﺮار دارد‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ‪ cout‬اﺟﺮا ﺑﺸﻮد ﺑﺎﻳﺪ ﻣﻘﺪار ﭘﺎراﻣﺘﺮﻫﺎي آن ﻣﺸﺨﺺ‬ ‫ﺑﺎﺷﻨﺪ‪ .‬ﭘﺲ ﺑﺎﻳﺪ ﻣﻘﺪار )" ‪ f(2,"an integer‬ﻣﺸﺨﺺ ﺑﺎﺷﺪ‪ .‬ﺑﺮاي ﻣﺸﺨﺺ ﺷﺪن اﻳﻦ ﻣﻘﺪار‪ِ control ،‬‬ ‫ﺑﺮﻧﺎﻣﻪ وارد ﺗﻌﺮﻳﻒ ﺗﺎﺑﻊ ﻣﻲﺷﻮد‪ .‬در اﻳﻦ ﺣﺎﻟﺖ ﻣﻘﺪار ﭘﺎراﻣﺘﺮ ‪ a‬ﺑﺮاﺑﺮ ‪ 2‬اﺳﺖ و ‪ c‬ﻫﻢ ﺑﻪ رﺷﺘﻪي‬

‫‪"an‬‬

‫" ‪ integer‬اﺷﺎره دارد )ﺑﻌﺪﻫﺎ ﻣﺘﻮﺟﻪ ﻣﻲﺷﻮﻳﺪ ﻛﻪ ﭼﺮا ﻣﻲﮔﻮﻳﻢ »اﺷﺎره دارد«(‪ .‬دﺳﺘﻮر ‪ ِ cout‬درون ﺗﺎﺑﻊ‬ ‫اﺟﺮا ﻣﻲﺷﻮد و ﻋﺒﺎرت‪ an integer 2 ‬ﭼﺎپ ﻣﻲﺷﻮد‪ .‬ﺳﭙﺲ ‪ 4‬ﺑﺮﮔﺮداﻧﺪه ﻣﻲﺷﻮد‪ .‬و اﻳﻦ ‪ 4‬ﻫﻤﺎن ﻣﻘﺪار‬ ‫)" ‪ f(2,"an integer‬اﺳﺖ ﻛﻪ ﺑﻪ دﻧﺒﺎل آن ﺑﻮدﻳﻢ‪ .‬ﺣﺎل ‪ ،cout‬اﺑﺘﺪا ‪ endl‬را ﭼﺎپ ﻣﻲﻛﻨﺪ ﻛﻪ ﻧﺘﻴﺠﻪ‪-‬‬ ‫ي آن رﻓﺘﻦ ﺑﻪ ﺧﻂ ﺑﻌﺪي اﺳﺖ و ﺳﭙﺲ ‪ 4‬را ﭼﺎپ ﻣﻲﻛﻨﺪ‪.‬‬ ‫ﺑﻪ اﻳﻦ ﺗﺮﺗﻴﺐ ﻓﻬﻤﻴﺪم ﻛﻪ ﻣﻘﺪارﻫﺎﻳﻲ ﻛﻪ ﺑﺎ ‪ cout‬ﭼﺎپ ﻣﻲﺷﻮﻧﺪ ﺑﺎﻳﺪ از راﺳﺖ ﺑﻪ ﭼﭗ ﻣﺸﺨﺺ ﺷﻮﻧﺪ وﻟﻲ‬ ‫ﺗﺮﺗﻴﺐ ﭼﺎپ آنﻫﺎ از ﭼﭗ ﺑﻪ راﺳﺖ اﺳﺖ‪ .‬ﻣﺜﻼ در‬ ‫;)‪cout<< f(1) << g(2‬‬

‫اول ﺑﺎﻳﺪ ﻣﻘﺪار )‪ g(2‬ﻣﺸﺨﺺ ﺷﻮد )ﻛﻪ ﺑﺮاي ﻣﺸﺨﺺ ﺷﺪن آن ﺗﺎﺑﻊ ‪ g‬اﺟﺮا ﻣﻲﺷﻮد( و ﺳﭙﺲ ﺑﺎﻳﺪ )‪f(1‬‬

‫ﻣﺸﺨﺺ ﺷﻮد‪ .‬وﻟﻲ اول )‪ f(1‬ﭼﺎپ ﻣﻲﺷﻮد و ﺳﭙﺲ )‪.g(2‬‬ ‫ﺑﺮاي اﻳﻦ ﻛﻪ ﻣﺜﺎل ﺑﺎﻻ ﺑﺮاﻳﺘﺎن ﺑﻬﺘﺮ ﺟﺎ ﺑﻴﻔﺘﺪ ﻣﺜﺎل زﻳﺮ را ﻣﻲآورم ﻛﻪ در ﺿﻤﻦ ﺗﺎﺑﻊﻫﺎﻳﻲ ﺑﺪون ﭘﺎراﻣﺘﺮ دارد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int f‬‬ ‫{‬ ‫;‪cout<< "function f" << endl‬‬ ‫;‪return 1‬‬ ‫}‬ ‫)(‪int g‬‬

‫‪27‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫{‬ ‫;‪cout<< "function g" << endl‬‬ ‫;‪return 2‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪cout<< "hello\n" << f()<< endl << g‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪function g‬‬ ‫‪function f‬‬ ‫‪hello‬‬ ‫‪1‬‬ ‫‪2‬‬

‫)ﻳﻌﻨﻲ ﺗﺤﻠﻴﻞ آن ﺑﻪ ﻋﻬﺪهي ﺧﻮدﺗﺎن‪ .‬ﻓﻘﻂ ﺑﻪ ﻋﻨﻮان راﻫﻨﻤﺎﻳﻲ ﺑﮕﻮﻳﻢ ﻛﻪ از ﻣﻨﻮي ‪ Run‬ﻳﺎ ﻣﻨﻮي ‪Debug‬‬ ‫ﮔﺰﻳﻨﻪي ‪ Trace Into‬ﻳﺎ ‪ Step Into‬را اﻧﺘﺨﺎب ﻛﻨﻴﺪ ﺗﺎ ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ ﺧﻂ ﺑﻪ ﺧﻂ اﺟﺮا ﺑﺸﻮد و ﺑﺮاي رﻓﺘﻦ ﺑﻪ‬ ‫ﺧﻂ ﺑﻌﺪي ﻣﻨﺘﻈﺮ اﺟﺎزهي ﺷﻤﺎ ﺑﻤﺎﻧﺪ‪ .‬ﺑﻪ اﻳﻦ ﻧﻮع از اﺟﺮاي ﺑﺮﻧﺎﻣﻪ و رﻓﻊ اﺷﻜﺎﻻت آن ‪ debug‬ﻛﺮدن ﻣﻲﮔﻮﻳﻴﻢ‪.‬‬ ‫ﻓﻘﻂ ﻳﺎدﺗﺎن ﺑﺎﺷﺪ ﻛﻪ وﻗﺘﻲ ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ از ﻓﺎﻳﻞ ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ ﺧﺎرج ﺷﺪ آن ﻗﺪر ﮔﺰﻳﻨﻪي ‪ Step Over‬را‬ ‫اﻧﺘﺨﺎب ﻛﻨﻴﺪ ﺗﺎ ﺑﻪ ﻓﺎﻳﻞ ﺷﻤﺎ ﺑﺮﮔﺮدد‪ .‬وﻟﻲ ﺑﺮاي اﻳﻦ ﺟﻮر ﻛﺎرﻫﺎ ﺧﻴﻠﻲ از ﻣﻨﻮي ﺑﺎﻻي ‪ compiler‬ﺧﻮدﺗﺎن اﺳﺘﻔﺎده‬ ‫ﻧﻜﻨﻴﺪ )راه ﺳﺎده ﺗﺮي ﻫﻢ ﻫﺴﺖ !((‪.‬‬

‫ار'‪ ,‬ط

* را " و )ر! ن ' &‬

‫ﺑﻪ ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪int f(int a‬‬ ‫{‬ ‫;‪a = 2‬‬ ‫;‪return 0‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a = 1‬‬ ‫;)‪f(a‬‬ ‫;‪cout<< a‬‬ ‫;)(‪getch‬‬

‫‪28‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬

‫در ﺗﺤﻠﻴﻞ اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﭼﻨﺪ ﻧﻜﺘﻪ ﻫﺴﺖ‪ .‬اوﻻ ‪ a‬در ﺗﺎﺑﻊ ‪ main‬ﻫﻴﭻ رﺑﻄﻲ ﺑﻪ ‪ a‬در ﺗﺎﺑﻊ ‪ f‬ﻧﺪارد )ﺗﺎ ﺣﺎﻻ ﺑﻪ اﻳﻦ ﻓﻜﺮ‬ ‫ﻛﺮده ﺑﻮدﻳﺪ ﻛﻪ ﺧﻮد ‪ main‬ﻫﻢ ﻳﻚ ﺗﺎﺑﻊ اﺳﺖ؟‬

‫(‪ .‬وﻗﺘﻲ ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ وارد ﺗﺎﺑﻊ ‪ f‬ﺷﺪ ﻣﻜﺎن ﺟﺪﻳﺪي از‬

‫ﺣﺎﻓﻈﻪ را در اﺧﺘﻴﺎر ﻣﻲﮔﻴﺮد‪ ،‬اﺳﻢ آن را ‪ a‬ﻣﻲﮔﺬارد و ﻣﻘﺪار ‪a‬يِ ﺗﺎﺑﻊ ‪ main‬را در ‪a‬ي ﺟﺪﻳﺪ ‪ copy‬ﻣﻲﻛﻨﺪ‪.‬‬ ‫ﻫﻨﮕﺎم ﺧﺮوج از ﺗﺎﺑﻊ ‪a ،f‬ي ﺟﺪﻳﺪ از ﺑﻴﻦ ﻣﻲرود‪ .‬ﻳﻌﻨﻲ ﺣﺎﻓﻈﻪاي ﻛﻪ ﺑﺎ ﻧﺎم ‪ a‬در اﺧﺘﻴﺎر ﺑﺮﻧﺎﻣﻪ ﺑﻮد از اﺧﺘﻴﺎر ﺑﺮﻧﺎﻣﻪ‬ ‫ﺧﺎرج ﻣﻲﺷﻮد و ﺑﻪ اﺻﻄﻼح آزاد ﻣﻲﺷﻮد‪ .‬ﺑﻪ آزاد ﻛﺮدن ﺣﺎﻓﻈﻪي ﮔﺮﻓﺘﻪ ﺷﺪه ‪ delete‬ﻛﺮدن‪ free ،‬ﻛﺮدن ﻳﺎ‬ ‫‪ destroy‬ﻛﺮدن ﻫﻢ ﻣﻲﮔﻮﻳﻴﻢ‪ .‬ﺑﺎ اﻳﻦ ﻛﻪ ‪a‬ي ﺟﺪﻳﺪ از ﺑﻴﻦ ﻣﻲرود ‪a‬ي ﻗﺒﻠﻲ ﻫﻤﭽﻨﺎن ﻣﻮﺟﻮد اﺳﺖ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ‬ ‫ﻣﻄﻤﺌﻦ ﺑﺸﻮﻳﺪ ‪a‬ﻫﺎي دو ﺗﺎ ﺗﺎﺑﻊ ﺑﻪ ﻫﻢ رﺑﻄﻲ ﻧﺪارﻧﺪ در ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ ﻣﻘﺪار ‪ a‬در ﺗﺎﺑﻊ ‪ main‬را ﺑﻌﺪ از اﺟﺮاي ﺗﺎﺑﻊ ‪f‬‬

‫ﭼﺎپ ﻛﺮدهام ﺗﺎ ﺑﺒﻴﻨﻴﺪ ﻣﻘﺪارش ﺗﻐﻴﻴﺮ ﻧﻜﺮده‪ .‬اﻣﺎ اﮔﺮ واﻗﻌﺎ ﻣﻲﺧﻮاﺳﺘﻴﻢ ﺗﻐﻴﻴﺮ ﻛﻨﺪ ﺑﺎﻳﺪ ﭼﻪ ﻣﻲﻛﺮدﻳﻢ؟ ﺧﻴﻠﻲ ﺳﺎده‬ ‫اﺳﺖ‪ .‬ﻛﺎﻓﻲ ﺑﻮد ﻓﻘﻂ ﻳﻚ & ﻧﺎﻗﺎﺑﻞ ﺟﻠﻮي ﭘﺎراﻣﺘﺮ ‪ a‬ﺑﮕﺬارم‪ .‬ﻳﻌﻨﻲ ﺑﺮﻧﺎﻣﻪ را ﺻﻮرت زﻳﺮ ﺗﻐﻴﻴﺮ دﻫﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪int f(int& a‬‬ ‫{‬ ‫;‪a = 2‬‬ ‫;‪return 0‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a = 1‬‬ ‫;)‪f(a‬‬ ‫;‪cout<< a‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪2‬‬

‫ﻓﺮق اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺑﺎ ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ اﻳﻦ اﺳﺖ ﻛﻪ وﻗﺘﻲ ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ‪ ،‬وارد ‪ f‬ﻣﻲﺷﻮد ﺣﺎﻓﻈﻪي ﺟﺪﻳﺪي ﭘﻴﺪا ﻧﻤﻲ‪-‬‬ ‫ﻛﻨﺪ و از ﻫﻤﺎن ﺣﺎﻓﻈﻪي ﻗﺒﻠﻲ اﺳﺘﻔﺎده ﻣﻲﻛﻨﺪ‪ .‬ﭼﻮن اﺳﻢ ﻣﺘﻐﻴﺮﻫﺎ اﻫﻤﻴﺖ ﺧﺎﺻﻲ ﻧﺪارد ﻫﻤﻴﻦ ﺑﺮﻧﺎﻣﻪ را ﻣﻲﺷﻮد ﺑﻪ‬ ‫اﻳﻦ ﺻﻮرت ﻧﻮﺷﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪29‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)‪int f(int& b‬‬ ‫{‬ ‫;‪b = 2‬‬ ‫;‪return 0‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a = 1‬‬ ‫;)‪f(a‬‬ ‫;‪cout<< a‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output :‬‬ ‫‪2‬‬

‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﺗﺎﺑﻊ ‪ f‬ﻳﻚ ﺧﺮوﺟﻲ دارد‪ .‬اﻣﺎ ﻣﻦ ﻫﻴﭻ ﻧﻴﺎزي ﺑﻪ ﺧﺮوﺟﻲ آن ﻧﺪارم‪ .‬در ‪compiler‬ﻫﺎي ‪Borland‬‬ ‫ﻣﻲﺗﻮان ;‪ return 0‬را از ﺑﺮﻧﺎﻣﻪ ﺣﺬف ﻛﺮد و اﻳﻦ ﻳﻚ ‪ error‬ﻧﻴﺴﺖ اﻣﺎ ﺑﺎﻋـﺚ ﻣﻲﺷﻮد ‪ compiler‬ﻳﻚ‬ ‫‪ warning‬ﺻﺎدر ﻛﻨﺪ ﻛﻪ اﻫﻤﻴﺖ ﭼﻨﺪاﻧﻲ ﻧﺪارد‪ warning ) .‬ﻳﻌﻨﻲ ﻫﺸﺪار‪ .‬ﻣﻌﻨﻲ »ﺻﺎدر ﻛﺮدن« را ﻫﻢ ﻛﻪ ﻣﻲ‪-‬‬ ‫دوﻧﻴﺪ ﭼﻴﻪ‬

‫(‪ .‬ﻓﻜﺮ ﻣﻲﻛﻨﻴﺪ وﻗﺘﻲ در ﻳﻚ ‪ compiler‬از ‪ Borland‬از ‪ return‬اﺳﺘﻔﺎده ﻧﺸﻮد‪ ،‬ﻣﻘﺪار )‪f(2‬‬

‫ﭼﻪ ﻗﺪر اﺳﺖ؟ )ﺟﻮاب‪ :‬ﻫﻴﭻ ﻣﻌﻠﻮم ﻧﻴﺴﺖ‪ .‬آزﻣﺎﻳﺶ ﻛﻨﻴﺪ!(‬ ‫ﺷﺎﻳﺪ ﺗﺎ ﺑﻪ ﺣﺎل ﻓﻬﻤﻴﺪه ﺑﺎﺷﻴﺪ ﻛﻪ ﻣﺜﻼ در ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ ﺑﻪ ‪ a‬در ‪) f(a); argument‬ﻳﺎ آرﮔﻮﻣﺎن( ﻣﻲﮔﻮﻳﻨﺪ و‬ ‫ﺑﻪ ‪ b‬در )‪ int f(int b‬ﭘﺎراﻣﺘﺮ‪ .‬وﻟﻲ ﺧﻴﻠﻲ ﻻزم ﻧﻴﺴﺖ وﺳﻮاس ﺑﻪ ﺧﺮج دﻫﻢ ﻛﻪ ﻣﺒﺎدا اﻳﻦ دو واژه )ﻳﻌﻨﻲ‬ ‫ﭘﺎراﻣﺘﺮ و آرﮔﻮﻣﺎن( ﺟﺎ ﺑﻪ ﺟﺎ اﺳﺘﻔﺎده ﺷﻮﻧﺪ‪.‬‬ ‫ﺣﺎﻻ ﺑﻪ ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﺗﻮﺟﻪ ﻛﻨﻴﺪ و ﺣﺘﻤﺎ ﻗﺒﻞ از ﺧﻮاﻧﺪن ﺗﻮﺿﻴﺤﺎت‪ ،‬آن را ﺑﻪ دﻗﺖ ﺑﺮرﺳﻲ ﻛﻨﻴﺪ‪ .‬ﺧﺮوﺟﻲ ﻫﻢ‬ ‫ﻧﻨﻮﺷﺘﻪاﻳﻢ ﺗﺎ ﺧﻮدﺗﺎن ﺣﺪس ﺑﺰﻧﻴﺪ‪ .‬اﻳﻦ آزﻣﺎﻳﺶ ﺧﻮﺑﻲ ﺑﺮاي درك ﻋﻤﻴﻖ ﺷﻤﺎ از ﻳﻚ ﺑﺮﻧﺎﻣﻪ اﺳﺖ‪ .‬وﻟﻲ ﺷﺎﻳﺪ ﻫﻨﻮز‬ ‫ﺗﺠﺮﺑﻪي ﻛﺎﻓﻲ ﻧﺪاﺷﺘﻪ ﺑﺎﺷﻴﺪ و ﻛﻤﻲ زود ﺑﺎﺷﺪ ﻛﻪ اﻧﺘﻈﺎر داﺷﺘﻪ ﺑﺎﺷﻢ ﺑﻪ آن ﭼﻴﺰي ﻛﻪ ﻣﻨﻈﻮر ﻣﻦ اﺳﺖ ﺑﺮﺳﻴﺪ‪ .‬ﺑﻪ ﻫﺮ‬ ‫ﺣﺎل دوﺳﺖ ﻧﺪارم ﺷﻤﺎ را دﺳﺖ ﻛﻢ ﺑﮕﻴﺮم‬

‫‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪void f(int& b‬‬ ‫{‬ ‫;‪b = 2‬‬ ‫;‪cout<< b‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬

‫‪30‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;)‪f(1‬‬ ‫;)(‪getch‬‬ ‫}‬

‫ﻧﺤﻮهي اﺟﺮاي اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺑﻪ ‪ compiler‬ﺷﻤﺎ ﺑﺴﺘﮕﻲ دارد‪ .‬ﻣﺜﻼ ‪ Visual C++ 2005‬از آن ﻳﻚ ‪ error‬ﻣﻲ‪-‬‬ ‫ﮔﻴﺮد و ﺑﺮﻧﺎﻣﻪ را اﺟﺮا ﻧﻤﻲﻛﻨﺪ‪ .‬اﻣﺎ ‪ BDS 2006‬ﻓﻘﻂ از آن ﻳﻚ ‪ warning‬ﻣﻲﮔﻴﺮد و ﺑﻌﺪ آن را اﺟﺮا ﻣﻲﻛﻨﺪ‬ ‫)اﻳﻦ ﻫﻢ اﺧﺘﺮاع »ﻓﻌﻞ« در زﺑﺎن ﻓﺎرﺳﻲ‪ warning» :‬ﮔﺮﻓﺘﻦ«‪ .‬ﺗﻮﻟﺪش ﻣﺒﺎرك ﻓﻮت ﻛﻨﻴﺪ‪:‬‬

‫(‪ .‬ﻓﻜﺮ ﻣﻲﻛﻨﻴﺪ‬

‫اﺷﺘﺒﺎه در ﻛﺠﺎﺳﺖ ﻛﻪ ‪ error‬ﻳﺎ ‪ warning‬ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد؟ ﻗﺒﻼ ﮔﻔﺘﻢ ﻛﻪ وﻗﺘﻲ ﺑﻪ ﺟﺎي‬ ‫}…{)‪void f(int b‬‬

‫ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫}…{)‪void f(int& b‬‬

‫ﺣﺎﻓﻈﻪي ﺟﺪﻳﺪي ﺑﺮاي ‪ b‬در ﻧﻈﺮ ﮔﺮﻓﺘﻪ ﻧﻤﻲﺷﻮد‪ .‬اﻣﺎ ﺑﺎﻳﺪ ﺣﺎﻓﻈﻪي ﻗﺪﻳﻤﻲ ﺑﺎﺷﺪ ﻛﻪ ﺟﺪﻳﺪش ﺑﻪ وﺟﻮد ﻧﻴﺎﻳﺪ‪ .‬اﻣﺎ ﻣﻦ‬ ‫در ﺑﺮﻧﺎﻣﻪ ﻧﻮﺷﺘﻪام ;)‪ ،f(1‬در ﺣﺎﻟﻲ ﻛﻪ ‪ 1‬ﻓﻘﻂ ﻳﻚ ﻣﻘﺪاراﺳﺖ ﻧﻪ ﻣﻜﺎﻧﻲ از ﺣﺎﻓﻈﻪ‪ .‬ﺗﺎﺑﻊ ‪ f‬ﺑﻪ ﻣﻜﺎﻧﻲ از ﺣﺎﻓﻈﻪ ﻧﻴﺎز‬ ‫دارد وﻟﻲ ﻣﻦ ﺑﺎ ﻧﻮﺷﺘﻦ &‪ int‬ﺑﻪ ﺟﺎي ‪ int‬ﺑﻪ آن اﺟﺎزه ﻧﺪادهام ﻛﻪ ﺧﻮدش ﺣﺎﻓﻈﻪاي ﺗﻬﻴﻪ ﻛﻨﺪ و از ﻃﺮف دﻳﮕﺮ‬ ‫ﺣﺎﻓﻈﻪاي ﻫﻢ از ﻃﺮﻳﻖ آرﮔﻮﻣﺎن ﺑﻪ آن ﻧﺪادهام‪ .‬اﻳﻦ ﺟﺎﺳﺖ ﻛﻪ ‪ compiler‬ﺗﺼﻤﻴﻢ ﻣﻲﮔﻴﺮد ﻛﻪ ﭼﻪ ﻛﻨﺪ‪ .‬آﻳﺎ از‬ ‫‪ compile‬ﻛﺮدن ﻣﻨﺼﺮف ﺷﻮد ﻳﺎ از ﻃﺮﻳﻘﻲ ﺣﺎﻓﻈﻪاي ﺑﻪ وﺟﻮد ﺑﻴﺎورد و ﻫﺮ ﺟﻮر ﺷﺪه ﻛﺎر را ﺑﻪ اﺗﻤﺎم ﺑﺮﺳﺎﻧﺪ ؟‬ ‫‪compiler‬ﻫﺎي ﻣﺨﺘﻠﻒ ﻳﻚ ﻛﺎر را از را هﻫﺎي ﻣﺨﺘﻠﻒ اﻧﺠﺎم ﻣﻲدﻫﻨﺪ‪ .‬ﻣﺜﻼ ﻳﻚ ‪ compiler‬ﻣﻤﻜﻦ اﺳﺖ ﺑﺮاي‬ ‫ﻫﺮ ﻣﻘﺪاري ﻛﻪ در ﺑﺮﻧﺎﻣﻪ ﻧﻮﺷﺘﻪ ﻣﻲﺷﻮد ﻣﺜﻞ ﻳﻚ ﻣﺘﻐﻴﺮ ﺣﺎﻓﻈﻪاي در ﻧﻈﺮ ﺑﮕﻴﺮد ﻣﺜﻼ ﻣﻤﻜﻦ اﺳﺖ در‬ ‫;‪int a = 2‬‬

‫اول ﺣﺎﻓﻈﻪاي ﺑﺮاي ‪ a‬اﺧﺘﺼﺎص دﻫﺪ ﺳﭙﺲ ﺣﺎﻓﻈﻪاي ﺑﺮاي ﻳﻚ ﻣﺘﻐﻴﺮ ﻣﺨﻔﻲ اﺧﺘﺼﺎص دﻫﺪ و ﻣﻘﺪار آن را ‪2‬‬ ‫ﺑﮕﺬارد و در ﻧﻬﺎﻳﺖ ﻣﻘﺪار اﻳﻦ ﻣﺘﻐﻴﺮ ﻣﺨﻔﻲ را در ‪ a‬ﻛﭙﻲ ﻛﻨﺪ‪ compiler .‬دﻳﮕﺮي ﻣﻤﻜﻦ اﺳﺖ ﻣﺴﺘﻘﻴﻤﺎ ﻣﻘﺪار ‪a‬‬

‫را ‪ 2‬ﺑﮕﺬارد‪ .‬ﺑﻪ ﻫﺮ ﺷﻜﻞ ﻛﻪ اﻳﻦ ﻛﺎر اﻧﺠﺎم ﺑﺸﻮد ﻧﺘﻴﺠﻪ ﻳﻜﻲ اﺳﺖ ﻳﻌﻨﻲ‪ a ،‬ﻣﻜﺎﻧﻲ از ﺣﺎﻓﻈﻪ ﻣﻲﺷﻮد ﻛﻪ ﻣﻘﺪارش‬ ‫‪ 2‬اﺳﺖ‪ .‬ﻣﻦ و ﺷﻤﺎ ﺑﻪ ﻋﻨﻮان ‪) programmer‬ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ( ﻛﺎري ﺑﻪ اﻳﻦ ﻛﺎرﻫﺎ ﻧﺪارﻳﻢ‪ .‬ﻣﺎ ﻓﻘﻂ ﺑﺮﻧﺎﻣﻪي‬ ‫ﺧﻮدﻣﺎن را در ‪ compiler‬ﻣﺤﺒﻮﺑﻤﺎن ﻣﻲﻧﻮﻳﺴﻴﻢ‪) .‬ﺳﻌﻲ ﻛﻨﻴﺪ ‪ compiler‬ﺧﻮدﺗﻮﻧﻮ را دوﺳﺖ داﺷﺘﻪ ﺑﺎﺷﻴﺪ و روي‬ ‫ﺷﺮﻛﺖ ﺳﺎزﻧﺪهاش ﺗﻌﺼﺐ داﺷﺘﻪ ﺑﺎﺷﻴﺪ‪ .‬ﻣﻦ ‪compiler‬ﻫﺎي ‪ Borland‬رو ﺗﻮﺻﻴﻪ ﻣﻲﻛﻨﻢ ﮔﺮﭼﻪ ﺑﺮاي‬ ‫‪ Microsoft‬ﻫﻢ اﺣﺘﺮام ﻗﺎﺋﻠﻢ‪.‬‬

‫(‬

‫‪31‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪comment‬ه ‬

‫ﻳﻚ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻧﻴﺎز دارد ﻛﻪ در ﻛﻨﺎر ﺧﻴﻠﻲ از دﺳﺘﻮرات ﺑﺮﻧﺎﻣﻪ‪ ،‬ﺗﻮﺿﻴﺤﺎﺗﻲ ﺑﻨﻮﻳﺴﺪ ﻛﻪ در ﻣﺮاﺟﻌﺎت ﺑﻌﺪي ﺑﻪ‬ ‫راﺣﺘﻲ ﻣﻌﻨﻲ آن ﭼﻴﺰي را ﻧﻮﺷﺘﻪ ﺷﺪه‪ ،‬ﻣﺘﻮﺟﻪ ﺑﺸﻮد‪ .‬وﻗﺘﻲ ﺷﻤﺎ ﻳﻚ ﺑﺮﻧﺎﻣﻪ ﻣﻲﻧﻮﻳﺴﻴﺪ ﺣﺘﻲ اﮔﺮ ﺧﻴﻠﻲ ﻫﻢ ﻃﻮﻻﻧﻲ‬ ‫ﻧﺒﺎﺷﺪ ﺗﺎ ﻣﺪت ﻛﻮﺗﺎﻫﻲ از آن ﺳﺮ در ﻣﻲآورﻳﺪ‪ .‬وﻗﺘﻲ ﻳﻚ ﻣﺎه ﺑﻌﺪ از ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪي ﺧﻮدﺗﺎن‪ ،‬دوﺑﺎره ﺳﺮاﻏ ﺶ ﻣﻲ‪-‬‬ ‫آﻳﻴﺪ ﺗﻨﻬﺎ ﭼﻴﺰي ﻛﻪ ﻣﻲﺑﻴﻨﻴﺪ ﻳﻚ ﻣﺸﺖ دﺳﺘﻮر در ﻫﻢ ﭘﻴﭽﻴﺪه و ﻏﻴﺮ ﻗﺎﺑﻞ ﻓﻬﻢ اﺳﺖ ﻛﻪ ﺑﺮاي ﻓﻬﻤﻴﺪﻧﺶ ﻧﻴﺎز ﺑﻪ‬ ‫ﺗﻮﺿﻴﺢ ﻫﺴﺖ‪.‬‬ ‫ﺑﻪ ﺗﻮﺿﻴﺤﺎﺗﻲ ﻛﻪ در ﻳﻚ ﺑﺮﻧﺎﻣﻪ ﻧﻮﺷﺘﻪ ﻣﻲﺷﻮد و ‪ compiler‬آنﻫﺎ را ﻧﺎدﻳﺪه ﻣﻲﮔﻴﺮد ‪ comment‬ﻣﻲﮔﻮﻳﻴﻢ‪ .‬در‬ ‫‪ C++‬ﺑﻪ دو ﺷﻜﻞ ﻣﻲﺗﻮان ‪ comment‬ﻧﻮﺷﺖ‪ .‬ﺷﻜﻞ ﻗﺪﻳﻤﻲ ﻛﻪ از ‪ C‬ﺑﻪ ارث ﺑﺮده ﺷﺪه؛ و ﺷﻜﻞ ﺟﺪﻳﺪ ﻛﻪ‬ ‫ﻣﺨﺼﻮص ‪ C++‬اﺳﺖ‪ .‬در ﺷﻜﻞ ﻗﺪﻳﻤﻲ )ﻛﻪ ﺑﻪ آن ‪ C Style Comment‬ﻣﻲﮔﻮﻳﻨﺪ( ﺗﻮﺿﻴﺤﺎت ﺑﻴﻦ »*‪ «/‬و‬ ‫»‪ «*/‬ﻧﻮﺷﺘﻪ ﻣﻲﺷﻮﻧﺪ‪ .‬ﻣﺜﻼ‬ ‫‪cout<< b; /* This is‬‬ ‫‪a comment */‬‬

‫‪ compiler‬ﺑﻪ ﻛﻞ‬ ‫‪/* This is‬‬ ‫‪a comment */‬‬

‫را ﻧﺎدﻳﺪه ﻣﻲﮔﻴﺮد اﻧﮕﺎر اﺻﻼ ﻧﻮﺷﺘﻪ ﻧﺸﺪه ﺑﺎﺷﺪ‪ .‬ﺷﻜﻞ ﺟﺪﻳﺪ )ﻛﻪ ﺑﻪ آن ‪ C++ Style Comment‬ﻣﻲﮔﻮﻳﻨﺪ(‬ ‫ﻳﻚ ﺧﻂ را از ﺟﺎﻳﻲ ﺑﻪ ﺑﻌﺪ ﺣﺬف ﻣﻲﻛﻨﺪ‪ .‬ﻣﺜﻼ‬ ‫‪cout<< b; // This is a comment‬‬

‫رﻧﮓ ‪comment‬ﻫﺎ در ‪ Editor‬ﻳﻌﻨﻲ آن ﺟﺎﻳﻲ ﻛﻪ ﺑﺮﻧﺎﻣﻪ را در آن ﻣﻲﻧﻮﻳﺴﻴﻢ ﻣﻌﻤﻮﻻ ﻣﺘﻔﺎوت اﺳﺖ‪ .‬ﻣﻦ رﻧﮓ‬ ‫ﺧﺎﻛﺴﺘﺮي ﺑﺎ زﻣﻴﻨﻪي آﺑﻲ ﭘﺮ رﻧﮓ را ﺑﺮاي ‪comment‬ﻫﺎ اﻧﺘﺨﺎب ﻛﺮدهام‪.‬‬ ‫از ‪comment‬ﻫﺎ‪ ،‬ﻫﻢ ﭼﻨﻴﻦ‪ ،‬ﻣﻲﺷﻮد ﺑﺮاي ﺣﺬف ﻣﻮﻗﺖ ﺑﺨﺶﻫﺎﻳﻲ از ﺑﺮﻧﺎﻣﻪ اﺳﺘﻔﺎده ﻛﺮد )ﺑﻪ اﻳﻦ ﻛﺎر‬ ‫‪ comment out‬ﻛﺮدن ﻣﻲﮔﻮﻳﻴﻢ(‪ .‬ﻫﻢ ﭼﻨﻴﻦ رﻳﺰه ﻛﺎريﻫﺎﻳﻲ در ﻣﻮرد ‪comment‬ﻫﺎي ﺗﻮ در ﺗﻮ ﻫﺴﺖ ﻛﻪ‬ ‫ﺗﺮﺟﻴﺢ ﻣﻲدﻫﻢ وﻗﺖ ﺷﻤﺎ را ﺑﺎ آنﻫﺎ ﺗﻠﻒ ﻧﻜﻨﻢ ﭼﻮن در ﻣﻮﻗﻊ ﻧﻴﺎز ﺑﺎ آزﻣﺎﻳﺶ و ﺧﻄﺎ ﺑﺎ آنﻫﺎ آﺷﻨﺎ ﻣﻲﺷﻮﻳﺪ‪ .‬ﺣﺎﻻ‬ ‫ﺑﻪ ﻣﺜﺎل زﻳﺮ ﺧﻮب دﻗﺖ ﻛﻨﻴﺪ‪:‬‬ ‫‪// a comment‬‬

‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪//------------------------------------------------‬‬‫*‪/‬‬ ‫)‪void f(int& b‬‬ ‫{‬ ‫;‪b = 2‬‬

‫‪32‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪// cout<< b; // This is a comment‬‬ ‫}‬ ‫‪*/‬‬ ‫@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@‪//‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪// //f(1‬‬ ‫‪// /* ff */‬‬ ‫‪////////////////////////////‬‬ ‫‪///‬‬ ‫;"‪cout<< "hello and /*hallo*/ and //hello‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪hello and /*hallo*/ and //hello‬‬

‫در ﭘﺎﻳﺎن ﻣﻲﮔﻮﻳﻢ ﻛﻪ در ‪compiler‬ﻫﺎي ﺟﺪﻳﺪ ‪ Borland‬و ‪ Microsoft‬ﻣﻲﺷﻮد ‪comment‬ﻫﺎ را ﻓﺎرﺳﻲ ﻫﻢ‬ ‫ﻧﻮﺷﺖ‪ .‬وﻟﻲ اﮔﺮ اﻳﻦ ﻛﺎر را ﺑﻜﻨﺒﺪ ﻣﺠﺒﻮر ﻫﺴﺘﻴﺪ ﻓﺎﻳﻞ را در ﻓﺮﻣﺖ ﻏﻴﺮ ‪) ANSI‬ﻏﻴﺮ اﺳﺘﺎﻧﺪارد( ذﺧﻴﺮه ﻛﻨﻴﺪ‪.‬‬ ‫ﺑﻌﻀﻲ ‪compiler‬ﻫﺎ ﻓﻘﻂ ﻓﺎﻳﻞﻫﺎي ‪ ANSI‬را ﻣﻲﭘﺬﻳﺮﻧﺪ‪ .‬ﺿﻤﻦ اﻳﻦ ﻛﻪ اﻣﻜﺎن ﻓﺎرﺳﻲ ﻧﻮﻳﺴﻲ اﻳﻦ ‪compiler‬ﻫﺎ‬ ‫ﺧﻴﻠﻲ ﻫﻢ ﻛﺎﻣﻞ ﻧﻴﺴﺖ و اﻳﺮاد دارد‪ .‬اﮔﺮ اﻧﮕﻴﺴﻲ ﺷﻤﺎ ﺧﻮب ﻧﻴﺴﺖ از ﻓﻴﻨﮕﻠﻴﺶ اﺳﺘﻔﺎده ﻛﻨﻴﺪ‪.‬‬

‫ر " ه ‬

‫ا‪ * +‬ول (' ‪ 3 ,‬ﻧﮕﺎه ﻛﻨﻴﺪ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻧﻮﺷﺘﻪام ﻧﻮع ﻳﻚ رﺷﺘﻪ *‪ char‬اﺳﺖ و *‪ char‬ﻓﻘﻂ ‪ 4‬ﺑﺎﻳﺖ‬ ‫از ﺣﺎﻓﻈﻪ را ﻣﻲﮔﻴﺮد‪ .‬ﻣﺜﻼ ﻣﻲﺗﻮان ﻧﻮﺷﺖ‪:‬‬ ‫;"‪char* c = "isn’t long Iranian history packed with defeats? y/n‬‬

‫اﻣﺎ آﻳﺎ ﺗﻤﺎم اﻳﻦ ﺟﻤﻠﻪي ﻃﻮﻻﻧﻲ در ‪ 4‬ﺑﺎﻳﺖ ﺟﺎ ﻣﻲﺷﻮد؟ ﺑﺪون ﺷﻚ اﻳﻦ ﻃﻮر ﻧﻴﺴﺖ‪ .‬ﭘﺲ اﻳﻦ رﺷﺘﻪ در ﻛﺠﺎي‬ ‫ﺣﺎﻓﻈﻪ ﻗﺮار دارد؟ و اﺻﻼ ﻧﻘﺶ ‪ c‬ﭼﻴﺴﺖ؟‬ ‫ﻣﺜﺎلﻫﺎي ﻛﻠﻴﺸﻪاي و ﺗﻜﺮاري را دوﺳﺖ ﻧﺪارم‪ .‬ﺑﻪ ﺧﺎﻃﺮ ﻫﻤﻴﻦ از آﺷﻨﺎﻳﻲ ﺷﻤﺎ ﺑﺎ ﻣﺤﻴﻂ )زﻳﺒﺎي‬

‫( وﻳﻨﺪوز ﻛﻤﻚ‬

‫ﻣﻲﮔﻴﺮم‪ .‬ﻓﺮض ﻛﻨﻴﺪ ﺷﻤﺎ ﻳﻚ ﻓﻴﻠﻢ ‪ 500‬ﻣﮕﺎ ﺑﺎﻳﺘﻲ در دراﻳﻮ ‪ E‬ﻛﺎﻣﭙﻴﻮﺗﺮ دارﻳﺪ و ﻣﻲﺧﻮاﻫﻴﺪ اﻳﻦ ﻓﻴﻠﻢ از‬ ‫‪ Desktop‬ﻗﺎﺑﻞ دﺳﺘﺮﺳﻲ ﺑﺎﺷﺪ‪ .‬ﺑﺮاي اﻳﻦ ﻛﺎر روي ‪ Desktop‬ﻳﻚ ‪ shortcut‬ﺑﻪ آن ﻓﻴﻠﻢ درﺳﺖ ﻣﻲﻛﻨﻴﺪ‪.‬‬ ‫ﻣﻲداﻧﻴﺪ ﻛﻪ ‪ shortcut‬ﻳﻚ ﻓﺎﻳﻞ ﺑﺎ ﺣﺠﻢ ﺑﺴﻴﺎر ﻛﻢ اﺳﺖ وﻟﻲ از ﻃﺮﻳﻖ آن ﺑﻪ ﻳﻚ ﻓﻴﻠﻢ ﭘﺮﺣﺠﻢ دﺳﺘﺮﺳﻲ دارﻳﺪ‪.‬‬ ‫)ﻓﺎﻳﻞﻫﺎ ﻣﻌﻤﻮﻻ ﻳﻚ ﭘﺴﻮﻧﺪ ﺳﻪ ﺣﺮﻓﻲ دارن‪ .‬ﻣﻲدوﻧﻴﺪ ﭘﺴﻮﻧﺪ ‪shortcut‬ﻫﺎ ﭼﻴﻪ؟ ‪ .lnk‬ﻛﻪ ﻣﺨﻔﻴﻪ وﻟﻲ ﻣﻲﺷﻪ ﺑﺪون‬

‫‪33‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫دﺳﺘﻜﺎري ﻣﺴﺘﻘﻴﻢ ‪ registry‬و ﻓﻘﻂ ﺑﺎ اﻣﻜﺎﻧﺎت وﻳﻨﺪوز )‪ (XP‬ﭘﺴﻮﻧﺪ رو ﻇﺎﻫﺮ ﻛﺮد‪ .‬اﮔﺮ ﻓﻚ ﻣﻲﻛﻨﻴﺪ از ﻫﺮ ﭼﻴﺰ‬ ‫وﻳﻨﺪور ﺳﺮ در ﻣﻴﺎرﻳﺪ ﭘﻴﺪا ﻛﺮدن روش اﻳﻦ ﻛﺎر ﺑﺎﻳﺪ ﺑﺮاﺗﻮن ﺳﺮﮔﺮﻣﻲ ﺧﻮﺑﻲ ﺑﺎﺷﻪ‪ .‬اﮔﺮ ﺗﻮﻧﺴﺴﻴﺪ در ﻛﻢ ﺗﺮ از ‪3‬‬ ‫ﺳﺎﻋـﺖ اﻳﻦ ﻛﺎر رو اﻧﺠﺎم ﺑﺪﻳﺪ‬

‫‪ .‬ﭘﻴﺸﻨﻬﺎد ﻣﻲﻛﻨﻢ ﻗﺒﻞ از ﻫﺮ ﻛﺎر ﻳﻚ ‪ restore point‬درﺳﺖ ﻛﻨﻴﺪ!‬

‫(‪.‬‬

‫‪ c‬در ﺑﺎﻻ ﻣﺎﻧﻨﺪ ﻳﻚ ‪ shortcut‬ﻋﻤﻞ ﻣﻲﻛﻨﺪ‪ .‬ﺧﻮد ِ رﺷﺘﻪ در ﺟﺎﻳﻲ دﻳﮕﺮ از ﺣﺎﻓﻈﻪ ﻗﺮار دارد و ‪ c‬اﺷﺎره ﮔﺮي ﺑﻪ‬ ‫آن ﻣﻜﺎن اﺳﺖ‪ .‬ﺑﺎ ﻧﻮﺷﺘﻦ‬ ‫;"?‪char* c = "isn’t short American history packed with victories‬‬

‫اول ﻣﻜﺎﻧﻲ از ﺣﺎﻇﻪ ﺑﻪ اﻧﺪازهي ‪ 52‬ﺑﺎﻳﺖ درﺳﺖ ﻣﻲﺷﻮد‪ .‬ﺑﻌﺪ اﻳﻦ رﺷﺘﻪ در آن ﻗﺮار ﻣﻲﮔﻴﺮد و ‪ c‬ﻃﻮري ﺗﻨﻈﻴﻢ‬ ‫ﻣﻲﺷﻮد ﻛﻪ ﺑﻪ اﻳﻦ رﺷﺘﻪ اﺷﺎره ﻛﻨﺪ‪ .‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﺑﺎ اﻳﻦ ﻛﻪ رﺷﺘﻪي ﺑﺎﻻ ‪ 51‬ﻛﺎراﻛﺘﺮ ﺑﻴﺶ ﺗﺮ ﻧﺪارد ‪ 52‬ﺑﺎﻳﺖ ﺑﺮاﻳ ﺶ‬ ‫در ﻧﻈﺮ ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد‪.‬ﻋﻠﺖ اﻳﻦ اﺳﺖ ﻛﻪ ﻫﻤﻴﺸﻪ در اﻧﺘﻬﺎي ﻫﺮ رﺷﺘﻪ ﺑﺎﻳﺪ ﻛﺎراﻛﺘﺮ'‪)'\0‬ﻛﻪ ﺑﻪ آن ‪ null‬ﻳﺎ‬ ‫ﻛﺎراﻛﺘﺮ ‪ null‬ﻣﻲﮔﻮﻳﻴﻢ( ﻗﺮار ﺑﮕﻴﺮد‪ .‬در اﻳﻦ ﺟﺎ ﺧﻮد ‪ compiler‬اﻳﻦ ﻛﺎراﻛﺘﺮ را اﺿﺎﻓﻪ ﻣﻲﻛﻨﺪ و ﺑﺮاي ﻫﻤﻴﻦ ﺑﻪ‬ ‫‪ 52‬ﺑﺎﻳﺖ از ﺣﺎﻓﻈﻪ ﻧﻴﺎز دارد‪ .‬اﮔﺮ ﺑﻨﻮﻳﺴﻴﺪ‪:‬‬ ‫;‪char* c‬‬

‫‪ c‬ﻳﻚ اﺷﺎره ﮔﺮ اﺳﺖ ﻛﻪ ﺑﻪ ﺟﺎي از ﭘﻴﺶ ﺗﻌﻴﻴﻦ ﺷﺪهاي اﺷﺎره ﻧﺪارد‪ .‬اﻣﺎ ﺑﺎ ﻧﻮﺷﺘﻦ‬ ‫;"‪c = "hello‬‬

‫‪ c‬ﺑﻪ ﻣﻜﺎﻧﻲ از ﺣﺎﻓﻈﻪ اﺷﺎره ﻣﻲﻛﻨﺪ ﻛﻪ ﺣﺎوي رﺷﺘﻪي "‪ "hello‬ﻫﻤﺮاه ﺑﺎ ﻛﺎراﻛﺘﺮ ‪ null‬اﻧﺘﻬﺎﻳﻲ )ﻳﺎ ﻫﻤﺎن‬ ‫‪ (terminating null‬اﺳﺖ‪.‬‬ ‫ﻣﻤﻜﻦ اﺳﺖ ﺑﻪ اﻳﻦ ﻓﻜﺮ ﻛﺮده ﺑﺎﺷﻴﺪ ﻛﻪ ﭼﻪ ﺟﻮري ﺑﻪ ﻛﺎراﻛﺘﺮ ‪n‬ام ﻳﻚ رﺷﺘﻪ دﺳﺘﺮﺳﻲ ﭘﻴﺪا ﻛﻨﻴﻢ‪ .‬ﻛﺎر ﺳﺎدهاي‬ ‫اﺳﺖ‪ .‬اﮔﺮ ‪ c‬ﻳﻚ رﺷﺘﻪ ﺑﺎﺷﺪ‪ ،‬ﻛﺎراﻛﺘﺮ ‪n‬ام آن ]‪ c[n-1‬اﺳﺖ‪ .‬ﻣﺜﻼ ﻛﺎراﻛﺘﺮ اول آن ]‪ c[0‬و ﻛﺎراﻛﺘﺮ دوم آن‬ ‫]‪ c[1‬اﺳﺖ )ﺑﻪ ‪ 0‬ﻳﺎ ‪ 1‬در اﻳﻦ ﺟﺎ ‪ offset‬ﻣﻲﮔﻮﻳﻴﻢ(‪ .‬ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻧﺤﻮهي اﺳﺘﻔﺎده از ‪ offset‬را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;"‪char* c = "hello‬‬ ‫‪cout<< c[4]; // the final character‬‬ ‫;]‪cout<< c[3‬‬ ‫;]‪cout<< c[2‬‬ ‫;]‪cout<< c[1‬‬ ‫;‪cout<< c[0] << endl‬‬ ‫)'‪if(c[5] == '\0‬‬ ‫;"‪cout<< "c[5] is the terminating null‬‬ ‫;)(‪getch‬‬

‫‪34‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫}‬

‫‪Output:‬‬ ‫‪olleh‬‬ ‫‪c[5] is the terminating null‬‬

‫ﻛﻠﻤﻪي ‪ hello‬ﺑﺮﻋﻜﺲ ﺷﺪه‪ .‬در ﺿﻤﻦ ]‪ c[5‬ﻛﺎراﻛﺘﺮ ‪ null‬اﻧﺘﻬﺎﻳﻲ اﺳﺖ‪.‬‬ ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻫﻢ ﺷﻜﻞ دﻳﮕﺮ ﻫﻤﻴﻦ ﺑﺮﻧﺎﻣﻪ اﺳﺖ وﻟﻲ اﺻﻼ ﺗﻮﺻﻴﻪ ﻧﻤﻲﺷﻮد‪ .‬ﭼﻮن ﺣﺎﻓﻈﻪي زﻳﺎد ﺗﺮي ﻧﻴﺎز دارد ) ﻣﮕﺮ‬ ‫ﺗﺤﺖ ﺷﺮاﻳﻂ ﺧﺎﺻﻲ(‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪cout<< "hello"[4]; // the final character‬‬ ‫;]‪cout<< "hello"[3‬‬ ‫;]‪cout<< "hello"[2‬‬ ‫;]‪cout<< "hello"[1‬‬ ‫;‪cout<< "hello"[0] << endl‬‬ ‫)'‪if("hello"[5] == '\0‬‬ ‫;"‪cout<< "it is the terminating null‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪olleh‬‬ ‫‪it is the terminating null‬‬

‫در ‪ BDS 2006‬ﺣﺠﻢ ﻓﺎﻳﻞ ‪ .exe‬اﻳﻦ ﺑﺮﻧﺎﻣﻪ از ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ ﺑﻴﺶ ﺗﺮ اﺳﺖ‪) .‬اﮔﺮ از ﻗﺒﻞ ﻧﻤﻲداﻧﺴﺘﻴﺪ ﺣﺘﻤﺎ ﺗﺎ ﺑﻪ‬ ‫ﺣﺎل ﻣﺘﻮﺟﻪ ﺷﺪهاﻳﺪ ﻛﻪ ﻧﺘﻴﺠﻪ اﺟﺮاي ﻫﺮ ﺑﺮﻧﺎﻣﻪ ﻳﻚ ﻓﺎﻳﻞ اﺟﺮاﻳﻲ ﺑﺎ ﭘﺴﻮﻧﺪ ‪ .exe‬اﺳﺖ‪ .‬در آﻳﻨﺪه‬

‫ﺑﻴﺶ ﺗﺮ‬

‫ﺗﻮﺿﻴﺢ ﺧﻮاﻫﻢ داد(‪.‬‬ ‫ﻣﻲﺷﻮد ﺗﻨﻈﻴﻤﺎت ‪compiler‬ﻫﺎي ‪ BDS 2006‬و ‪) Visual C++ 2005‬و ‪compiler‬ﻫﺎي دﻳﮕﺮ( را ﻃﻮري‬ ‫ﺗﻐﻴﻴﺮ داد ﻛﻪ ﺑﺎ ﻫﺮ ﺑﺎر ﻧﻮﺷﺘﻦ "‪ "hello‬ﺣﺎﻓﻈﻪاي ﺟﺪﻳﺪ ﺑﺮاي آن اﺧﺼﺎص داده ﺑﺸﻮد‪ .‬ﺑﺮاي ﺗﻐﻴﻴﺮ ﺗﻨﻈﻴﻤﺎت در‬ ‫‪ BDS 2006‬ﻣﺴﻴﺮ زﻳﺮ را از ﻃﺮﻳﻖ ﻣﻨﻮﻫﺎ ﻃﻲ ﻛﻨﻴﺪ‪:‬‬ ‫‪Project | Options… | C++ Compiler (bcc32) | Compiling‬‬ ‫و اﮔﺮ ﺟﻠﻮي )‪ Merge duplicate strings (-d‬ﻋﻼﻣﺖ ﺗﻴﻚ ﻫﺴﺖ آن را ﭘﺎك ﻛﻨﻴﺪ‪:‬‬

‫‪35‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

:‫ اﻳﻦ ﻣﺴﻴﺮ را ﻃﻲ ﻛﻨﻴﺪ‬Visual C++ 2005 ‫در‬ Project | console Properties… :

| Configuration Properties | C/C++ | General | Debug Information Format | Disabled:

36

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫ﺣﺎل در ﻫﻤﻴﻦ ﭘﻨﺠﺮه ﻣﻄﻤﺌﻦ ﺷﻮﻳﺪ ﻛﻪ ﺟﻠﻮي‬ Configuration Properties | C/C++ | Code Generation | Enable String Pooling :‫ ﮔﺬاﺷﺘﻪ ﺷﺪه اﺳﺖ‬No

37

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

-‫ اﻳﻦ ﺗﻨﻈﻴﻤﺎت را ﺑﻪ ﺣﺎﻟﺖ اوﻟﻴﻪ ﺑﺮﮔﺮداﻧﻴﺪ ﭼﻮن ﺑﻘﻴﻪ‬،‫ را ﻓﺸﺎر دﻫﻴﺪ و ﺑﺮﻧﺎﻣﻪي زﻳﺮ را اﺟﺮا ﻛﻨﻴﺪ )ﺑﻌﺪ از اﺟﺮا‬OK :(‫ﻫﺎ اﺟﺮا ﻣﻲﺷﻮﻧﺪ‬compiler ‫ي ﺑﺮﻧﺎﻣﻪﻫﺎي اﻳﻦ ﻧﻮﺷﺘﻪ ﺗﺤﺖ ﺗﻨﻈﻴﻤﺎت اوﻟﻴﻪي‬ #include <conio.h> #include <iostream> using namespace std; int main() { char* c1 = "hello"; char* c2 = "hello"; if(c1 != c2) cout<< "c1 and c2 are different"; if(c1 == c2) cout<< "c1 == c2"; getch(); }

Output (BDS 2006): c1 and c2 are different Output (Visual C++ 2005): c1 and c2 are different

38

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺧﺮوﺟﻲ اﻳﻦ ﺑﺮﻧﺎﻣﻪ ‪ shortcut‬ﺑﻮدن ‪ c1‬و ‪ c2‬را ﻛﺎﻣﻼ ﺛﺎﺑﺖ ﻣﻲﻛﻨﺪ‪ .‬ﺷﺎﻳﺪ ﺑﭙﺮﺳﻴﺪ ﭘﺲ ﭼﮕﻮﻧﻪ ﻣﺴﺎوي ﺑﻮدن‬ ‫ﺧﻮد دو رﺷﺘﻪ )و ﻧﻪ ‪shortcut‬ﻫﺎي آنﻫﺎ( را ﺑﺮرﺳﻲ ﻛﻨﻴﻢ؟ ﺟﻮاب اﻳﻦ اﺳﺖ ﻛﻪ ﭼﺎرهاي ﻧﻴﺴﺖ ﺑﻪ ﺟﺰ اﻳﻦ ﻛﻪ‬ ‫ﻣﺴﺎوي ﺑﻮدن ﻛﺎراﻛﺘﺮﻫﺎ را ﻳﻜﻲ ﻳﻜﻲ ﺑﺮرﺳﻲ ﻛﻨﻴﻢ‪ .‬اﻳﻦ ﻛﺎر را در ﺑﺮﻧﺎﻣﻪي زﻳﺮ اﻧﺠﺎم دادهام‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;"‪char* c1 = "hen‬‬ ‫;"‪char* c2 = "hen‬‬ ‫)]‪if(c1[0] == c2[0‬‬ ‫)]‪if(c1[1] == c2[1‬‬ ‫)]‪if(c1[2] == c2[2‬‬ ‫)]‪if(c1[3] == c2[3‬‬ ‫;"‪cout<< "strings are equal‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪strings are equal‬‬

‫ﺷﺎﻳﺪ اﻳﻦ اﺳﺘﻔﺎدهي ﭘﻴﭽﻴﺪه و ﺗﻮ در ﺗﻮ از ‪ ،if‬ﺑﺮﻧﺎﻣﻪ را ﺳﺮﻳﻊ ﺗﺮ ﻛﻨﺪ اﻣﺎ ﭼﻮن ﻓﻬﻢ ﺑﺮﻧﺎﻣﻪ ﻣﺸﻜﻞ ﺗﺮ ﻣﻲﺷﻮد اﺻﻼ‬ ‫ﻣﻨﺎﺳﺐ ﻧﻴﺴﺖ و دﻟﻴﻞ اﻳﻦ ﻛﻪ ﻣﻦ آن را ﺑﻪ ﻛﺎر ﺑﺮدهام اﻳﻦ اﺳﺖ ﻛﻪ ﻫﻨﻮز && را ﻣﻌﺮﻓﻲ ﻧﻜﺮدهام‪ .‬اﻟﺒﺘﻪ در ﻣﻮاردي‬ ‫اﻳﻦ ﺷﻜﻞ از ﺑﻪ ﻛﺎرﮔﻴﺮي ﺗﻮ در ﺗﻮي ‪ ،if‬ﺑﺮﻧﺎﻣﻪ را آن ﻗﺪر ﺳﺮﻳﻊ ﺗﺮ ﻣﻲﻛﻨﺪ ﻛﻪ از آن ﻧﻤﻲﺷﻮد ﮔﺬﺷﺖ‪ .‬در اﻳﻦ‬ ‫ﺟﺎ اﻳﻦ ﻃﻮر ﻧﻴﺴﺖ‪.‬‬ ‫اﺟﺮاي ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﺧﻄﺮﻧﺎك اﺳﺖ )ﺑﻪ ﺧﺼﻮص در ‪compiler‬ﻫﺎي ﻗﺪﻳﻤﻲ(‪ .‬ﺣﺘﻲ ﻣﻤﻜﻦ اﺳﺖ )ﺑﺴﺘﻪ ﺑﻪ ﻧﻮع‬ ‫‪ compiler‬و ﺗﻨﻈﻴﻤﺎت آن( در ﺣﻴﻦ اﺟﺮا‪ ،‬ﺑﺮﻧﺎﻣﻪ ﺑﺎ ﻳﻚ ‪) exception‬ﻛﻪ ﻧﻮﻋﻲ ‪ error‬اﺳﺖ( ﻣﺘﻮﻗﻒ ﺷﻮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪char* c‬‬ ‫;‪c[0] = 5‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output: empty‬‬

‫‪39‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻋﻠﺖ ﻣﺨﺮب ﺑﻮدن اﻳﻦ ﺑﺮﻧﺎﻣﻪ اﻳﻦ اﺳﺖ ﻛﻪ ﻣﻌﻠﻮم ﻧﻴﺴﺖ ‪ c‬ﺑﻪ ﻛﺠﺎ اﺷﺎره ﻣﻲﻛﻨﺪ و ﻣﻤﻜﻦ اﺳﺖ ﺑﻪ ﺟﺎي ﺣﺴﺎﺳﻲ از‬ ‫ﺣﺎﻓﻈﻪ اﺷﺎره ﻛﻨﺪ‪ .‬ﻣﻦ ﻣﻘﺪار اوﻟﻴﻦ ﺑﺎﻳﺖ از ﺣﺎﻓﻈﻪاي را ﻛﻪ ﺑﻪ آن اﺷﺎره دارد ﺗﻐﻴﻴﺮ دادهام ﻛﻪ ﻛﺎر ﺧﻄﺮﻧﺎﻛﻲ اﺳﺖ‬ ‫ﭼﻮن ﻣﻌﻠﻮم ﻧﻴﺴﺖ ﻛﺠﺎي ﺣﺎﻓﻈﻪ را دﺳﺘﻜﺎري ﻛﺮدهام‪ .‬اﮔﺮ ﺧﻮد وﻳﻨﺪوز ﻳﺎ ﺑﺮﻧﺎﻣﻪاي دﻳﮕﺮ در ﺣﺎل اﺳﺘﻔﺎده از اﻳﻦ‬ ‫ﺑﺎﻳﺖ ﺑﺎﺷﺪ ﻛﺎر وﻳﻨﺪوز ﻳﺎ آن ﺑﺮﻧﺎﻣﻪ ﻣﺨﺘﻞ ﻣﻲﺷﻮد‪ .‬ﭼﻮن ‪compiler‬ﻫﺎي ﻗﺪﻳﻤﻲ اﺻﻼ ﻣﺮاﻗﺐ ﻫﻴﭻ ﭼﻴﺰ ﻧﻴﺴﺘﻨﺪ‬ ‫اﺣﺘﻤﺎل ‪ crash‬زﻳﺎد اﺳﺖ‪ ) .‬ﻣﻨﻈﻮر ﻣﻦ از ‪ crash‬ﻫﻤﺎن ﻫﻨﮓ ﻛﺮدن اﺳﺖ(‪compiler .‬ﻫﺎي ﺟﺪﻳﺪ ﺑﻴﺶ ﺗﺮ‬ ‫ﻣﺮاﻗﺒﻨﺪ‪ .‬در ﻫﺮ ﺣﺎل ‪ BDS 2006‬ﺑﺮﻧﺎﻣﻪ ﺑﺎﻻ را ﺑﺪون ﻫﻴﭻ اﻋﺘﺮاﺿﻲ اﺟﺮا ﻣﻲﻛﻨﺪ وﻟﻲ اﮔﺮ ﺧﻮد ﻣﻦ ﻣﻘﺪار‬ ‫ﻧﺎﻣﺮﺑﻮﻃﻲ ﺑﻪ ‪ c‬ﺑﺪﻫﻢ ‪ BDS 2006‬ﻫﻢ ﻳﻚ ‪ raise ،exception‬ﻣﻲﻛﻨﺪ )ﭼﻪ ﻗﺪر ﻓﺎرﺳﻲ را ﭘﺎس ﻣﻲدارم ﻣﻦ؟!‬ ‫اﺻﻼ ﺑﻬﺘﺮ ﺑﻮد ﻳﻪ دﻓﻌﻪ ﻣﻲﻧﻮﺷﺘﻢ ‪It raises an exception‬‬

‫(‪ .‬ﺑﻨﺎﺑﺮاﻳﻦ ﺑﺮﻧﺎﻣﻪي زﻳﺮ در ‪) BDS 2006‬و‬

‫‪ (Visual C++ 2005‬ﺑﺎﻋـﺚ ﺑﺮوز ‪ exception‬ﻣﻲﺷﻮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪char* c = (char *) 1000‬‬ ‫;‪cout<< c‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output: It raises an exception.‬‬

‫ﻧﻜﺘﻪي ﻗﺎﺑﻞ ﺗﻮﺟﻪ ﻣﻘﺪار دادن ﺑﻪ ‪ c‬اﺳﺖ‪ .‬ﮔﻔﺘﻢ ‪ c‬ﭼﻬﺎر ﺑﺎﻳﺘﻲ اﺳﺖ‪ .‬ﺑﺮاي ﻣﻘﺪار دادن ﺑﻪ ‪ c‬ﻛﺎﻓﻲ اﺳﺖ ﺑﻪ اﻳﻦ ﭼﻬﺎر‬ ‫ﺑﺎﻳﺖ ﻣﻘﺪار ﺑﺪﻫﻴﻢ‪ .‬ﻣﻲﺗﻮاﻧﻴﻢ ﻃﻮري ﺑﻪ اﻳﻦ ﭼﻬﺎر ﺑﺎﻳﺖ ﻣﻘﺪار ﺑﺪﻫﻴﻢ ﻛﻪ ﻣﻌﺎدل ﻋﺪدي آن ‪ 1000‬ﺑﺎﺷﺪ‪ .‬در‬ ‫‪compiler‬ﻫﺎي ‪ Borland‬ﻫﻨﮕﺎم ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪي ‪) C‬ﻧﻪ ‪ (C++‬ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻢ‪:‬‬ ‫;‪char* c = 1000‬‬

‫اﻣﺎ در ‪ C++‬و ‪ compiler‬ﻫﺎي ﺟﺪﻳﺪ ﻛﻪ ﺧﻴﻠﻲ ﻫﻢ ادﻋﺎي ‪) type-safety‬ﻳﻌﻨﻲ اﻣﻨﻴﺖ ﻧﻮع( دارﻧﺪ ﺑﺎﻳﺪ ﻧﻮﺷﺖ‪:‬‬ ‫;‪char* c = (char *) 1000‬‬

‫ﻳﻌﻨﻲ ﺑﺎﻳﺪ ﺑﺎ ﻧﻮﺷﺘﻦ )* ‪ (char‬ﺗﺎﻳﻴﺪ ﻛﻨﻴﻢ ﻛﻪ واﻗﻌﺎ ﻣﻲﺧﻮاﻫﻴﻢ ‪ 1000‬ﺑﻪ ﻳﻚ *‪ char‬ﺗﺒﺪﻳﻞ ﺷﻮد و ﭼﻴﺰي را‬ ‫اﺷﺘﺒﺎﻫﺎ ﻧﻨﻮﺷﺘﻪاﻳﻢ‪ .‬در ﺣﻘﻴﻘﺖ ‪ compiler‬از ﻣﺎ اﻣﻀﺎي رﺳﻤﻲ ﺑﺮاي ﺗﺎﻳﻴﺪ ﻣﻲﺧﻮاﻫﺪ‪.‬‬ ‫ﺑﻪ ﺗﺒﺪﻳﻞﻫﺎﻳﻲ از اﻳﻦ دﺳﺖ »ﺗﺒﺪﻳﻞ ﻧﻮع« ﮔﻔﺘﻪ ﻣﻲﺷﻮد ﻛﻪ ﺑﻌﺪا‬

‫درﺑﺎرهي آن ﺑﻴﺶ ﺗﺮ ﺗﻮﺿﻴﺢ ﻣﻲدﻫﻢ‪ .‬ﻓﻌﻼ ﺗﻨﻬﺎ‬

‫ﭼﻴﺰ ﻣﻬﻢ اﻳﻦ اﺳﺖ ﭼﮕﻮﻧﻪ ﺑﻪ ‪ c‬ﻣﻘﺪار ﻣﻨﺎﺳﺒﻲ ﺑﺪﻫﻴﻢ ﻛﻪ ‪ raise ،exception‬ﻧﺸﻮد‪ .‬ﺑﺎﻳﺪ اول ﺣﺎﻓﻈﻪي ﻣﻨﺎﺳﺐ را‬

‫‪40‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺗﺨﺼﻴﺺ ﺑﺪﻫﻴﻢ وﺳﭙﺲ ﺑﻪ ‪ c‬ﻃﻮري ﻣﻘﺪار ﺑﺪﻫﻴﻢ ﻛﻪ ﺑﻪ آن ﺣﺎﻓﻄﻪ اﺷﺎره ﻛﻨﺪ ﺗﺎ دﻳﮕﺮ ‪ raise ،exception‬ﻧﺸﻮد‪.‬‬ ‫ﺑﺮاي اﻳﻦ ﻛﺎر دو راه وﺟﻮد دارد‪:‬‬ ‫‪ (1‬اﺳﺘﻔﺎده از آراﻳﻪ‪.‬‬ ‫‪ (2‬اﺳﺘﻔﺎده از ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪.new‬‬ ‫‪ (1‬ا‪ ."#‬د از )را ‬

‫آراﻳﻪﻫﺎ ﺑﻪ ﺷﻤﺎ اﻣﻜﺎن ﺗﺨﺼﻴﺺ ﺣﺎﻓﻈﻪ روي ‪ stack‬را ﻣﻲدﻫﻨﺪ‪ stack .‬ﺑﺨﺸﻲ از ﺣﺎﻓﻈﻪ اﺳﺖ ﻛﻪ ﻣﻌﻤﻮﻻ‬ ‫ﺑﺮاي ﻣﺘﻐﻴﺮﻫﺎي درون ﻳﻚ ﺗﺎﺑﻊ ﺑﻪ ﻛﺎر ﻣﻲرود‪ .‬ﺑﺎ ﺧﺮوج ﻛﺎﻣﻞ از ﺗﺎﺑﻊ ﺣﺎﻓﻈﻪﻫﺎي ﺗﺨﺼﻴﺺ داده ﺷﺪه در ﺗﺎﺑﻊ‬ ‫از ‪ stack‬ﺧﻮد ﺑﻪ ﺧﻮد از ﺑﻴﻦ ﻣﻲروﻧﺪ‪.‬‬ ‫ﺑﺮاي اﻳﻦ ﻛﻪ ‪ 20‬ﺑﺎﻳﺖ از ﺣﺎﻓﻈﻪي ‪ stack‬را درﻳﺎﻓﺖ ﻛﻨﻴﻢ ﻣﻲﻧﻮﻳﺴﻴﻢ‪:‬‬ ‫;]‪char a[20‬‬

‫ﺣﺎﻻ ﻣﻲﺗﻮﻧﻴﻢ ﺑﮕﻮﻳﻴﻢ ‪ a‬از ﻧﻮع *‪ char‬اﺳﺖ و ﺑﻪ ﺣﺎﻓﻈﻪاي ﺑﻪ اﻧﺪازهي ‪ 20‬ﺑﺎﻳﺖ اﺷﺎره دارد‪ .‬ﺑﻪ ‪ a‬ﻳﻚ‬ ‫آراﻳﻪ ﺑﻪ ﻃﻮل ‪ 20‬از ‪char‬ﻫﺎ ﻣﻲﮔﻮﻳﻴﻢ‪ .‬ﻣﺜﺎل زﻳﺮ ﻧﺤﻮهي اﺳﺘﻔﺎده از آراﻳﻪ را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪void f‬‬ ‫{‬ ‫;]‪char a[20‬‬ ‫;'‪a[0] = 'b‬‬ ‫;'‪a[1] = 'a‬‬ ‫;'‪a[2] = 'd‬‬ ‫;'‪a[3] = '\0‬‬ ‫;‪cout<< a‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪f‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪bad‬‬

‫ﻫﻤﻴﻦ ﺑﺮﻧﺎﻣﻪ را ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻪ ﺷﻜﻞ ﺳﺎده ﺗﺮي ﻫﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪41‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)(‪void f‬‬ ‫{‬ ‫;"‪char a[20] = "bad‬‬ ‫;‪cout<< a‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪f‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪bad‬‬

‫اﻣﺎ در اﻳﻦ ﺟﺎ ﺑﺮاي ﻳﻚ ﻛﻠﻤﻪي ﺳﻪ ﺣﺮﻓﻲ ‪ 20‬ﺑﺎﻳﺖ اﺧﺘﺼﺎص داده ﺷﺪه ﻛﻪ زﻳﺎد اﺳﺖ‪ .‬اﮔﺮ ﺑﺨﻮاﻫﻴﻢ دﻗﻴﻘﺎ‬ ‫ﺗﻌﺪاد ﻻزم از ﺑﺎﻳﺖﻫﺎ اﺧﺼﺎص داده ﺑﺸﻮد ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻪ ﺟﺎي‬ ‫;"‪char a[20] = "bad‬‬

‫ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;"‪char a[] = "bad‬‬

‫ﻳﺎ ﻣﺜﻞ ﻗﺒﻞﻫﺎ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;"‪char* a = "bad‬‬

‫وﻟﻲ در ﻫﻤﻪي َاﺷﻜﺎل ِ آراﻳﻪاي ﺑﺮاي ﮔﺮﻓﺘﻦ ﺣﺎﻓﻈﻪ‪ ،‬ﺑﻌـﺪ از ﺧﺮوج از ﺗﺎﺑﻊ ‪ ،f‬ﺣﺎﻓﻈﻪ ﺗﺨﺼﻴﺺ داده ﺷﺪه ﭘﺎك‬ ‫ﻣﻲﺷﻮد‪ .‬ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ اﺳﺖ ﻛﻪ ﺑﺮﻧﺎﻣﻪ زﻳﺮ ﺧﺎﻟﻲ از ا‪‬ﺷﻜﺎل ﻧﻴﺴﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪char* f‬‬ ‫{‬ ‫;"‪char a[20] = "bad‬‬ ‫;‪return a‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪cout<< f‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪bad‬‬ ‫‪Output (BDS 2006):‬‬ ‫@◄‪ÿ‬‬

‫‪42‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪Output (Visual C++ 2005):‬‬ ‫↕‪╠╠╠╠(²‬‬

‫اﻳﻦ ﺑﺮﻧﺎﻣﻪ دو ﺑﺎر ﺑﺎ ‪ BDS 2006‬و ﻳﻚ ﺑﺎر ﺑﺎ ‪ Visual C++ 2005‬اﺟﺮا ﺷﺪه اﺳﺖ‪ .‬ﻧﺘﺎﻳﺞ را ﻣﻲﺑﻴﻨﻴﺪ‪.‬‬ ‫ﻋﻠﺖ اﻳﻦ ﻧﺘﺎﻳﺞ ﻋﺠﻴﺐ و ﻏﺮﻳﺐ اﻳﻦ اﺳﺖ ﻛﻪ ﺑﺎ ﺧﺮوج از ﺗﺎﺑﻊ ‪ f‬ﺣﺎﻓﻈﻪي اﺧﺘﺼﺎص ﻳﺎﻓﺘﻪ آزاد ﻣﻲﺷﻮد و‬ ‫دﻳﮕﺮ ﺗﺤﺖ ﻛﻨﺘﺮل ﺑﺮﻧﺎﻣﻪ ﻧﻴﺴﺖ‪ .‬در ﺿﻤﻦ ‪ compiler‬ﻳﻚ ‪ warning‬ﻣﻲﮔﻴﺮد )ﻳﻌﻨﻲ ﺻﺎدر ﻣﻲﻛﻨﺪ‬

‫(‪.‬‬

‫اﻣﺎ ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻧﻪ ‪ error‬دارد و ﻧﻪ ‪:warning‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪char* f‬‬ ‫{‬ ‫;"‪char* a = "bad‬‬ ‫;‪return a‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪cout<< f‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪bad‬‬

‫از اﻳﻦ ﻣﻲﺗﻮاﻧﻴﻢ ﻧﺘﻴﺠﻪ ﺑﮕﻴﺮﻳﻢ ﻛﻪ وﻗﺘﻲ درون ﺑﺮﻧﺎﻣﻪ ﻧﻮﺷﺘﻪ ﺷﺪ "‪ "bad‬ﺣﺎﻓﻈﻪاي ﺑﻪ آن اﺧﺘﺼﺎص داده ﻣﻲ‪-‬‬ ‫ﺷﻮد ﻛﻪ ﺗﺎ آﺧﺮ اﺟﺮاي ﺑﺮﻧﺎﻣﻪ ﺗﺤﺖ اﺧﺘﻴﺎر اﺳﺖ‪.‬‬ ‫‪ (2‬ا‪ ."#‬د از ‪new‬‬

‫ﺑﻪ ﺟﺎي‬ ‫;]‪char a[10‬‬

‫ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;]‪char* a = new char [10‬‬

‫اﻣﺎ وﻗﺘﻲ از ‪ new‬اﺳﺘﻔﺎده ﻣﻲﺷﻮد ﺣﺎﻓﻈﻪ‪ ،‬از ‪ heap‬ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد‪ .‬ﺧﺎﺻﻴﺖ ﺣﺎﻓﻈﻪي ‪ heap‬اﻳﻦ اﺳﺖ ﻛﻪ ﺑﺎ‬ ‫ﺧﺮوج از ﺗﺎﺑﻊ آزاد ﻧﻤﻲﺷﻮد‪ .‬ﺑﺮاي آزاد ﻛﺮدن ﺣﺎﻓﻈﻪاي ﻛﻪ از ‪ heap‬ﮔﺮﻓﺘﻪ ﺷﺪه و ‪ a‬ﺑﻪ آن اﺷﺎره دارد ﺑﺎﻳﺪ‬ ‫ﻧﻮﺷﺖ‪:‬‬ ‫;‪delete [] a‬‬

‫ﻣﺜﺎل زﻳﺮ ﻧﺤﻮهي اﺳﺘﻔﺎده از ‪ new‬را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬

‫‪43‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪char* f‬‬ ‫{‬ ‫;]‪char* a = new char [20‬‬ ‫;'‪a[0] = 'b‬‬ ‫;'‪a[1] = 'o‬‬ ‫;'‪a[2] = 'y‬‬ ‫;'‪a[3] = '\0‬‬ ‫;‪return a‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪char* c = f‬‬ ‫;‪cout<< c‬‬ ‫;‪delete [] c‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪boy‬‬

‫ﻫﺮ ﺣﺎﻓﻈﻪاي ﻛﻪ از ‪ heap‬ﮔﺮﻓﺘﻪ ﺷﺪه ﺑﺎﻳﺪ ﺑﻪ آن ﺑﺮﮔﺮدد و ﮔﺮﻧﻪ ﻣﻤﻜﻦ اﺳﺖ ﺑﺎ ﻛﻤﺒﻮد ﺣﺎﻓﻈﻪ ﻣﻮاﺟﻪ ﺑﺸﻮﻳﻢ‬ ‫و ﺑﺮﻧﺎﻣﻪي ﻣﺎ ﻧﺘﻮاﻧﺪ ﺑﺮاي ﻣﺪت ﻃﻮﻻﻧﻲ در ﺣﺎل اﺟﺮا و ﻛﺎر ﺑﺎﺷﺪ )ﻫﺮ ﭘﻮﻟﻲ ﻫﻢ ﻛﻪ از ﻛﺴﻲ ﻗﺮض ﻣﻲﮔﻴﺮﻳﻢ‬ ‫ﺑﺎﻳﺪ ﺑﻬﺶ ﺑﺮﮔﺮدوﻧﻴﻢ وﮔﺮﻧﻪ ﻣﻤﻜﻨﻪ دﻓﻌﻪي ﺑﻌﺪ ﺑﻬﻤﻮن ﭘﻮل ﻧﺪه‬

‫(‬

‫ﭼﻨﺪ ﻧﻜﺘﻪ در ﻣﻮرد رﺷﺘﻪﻫﺎ و ﻛﺎراﻛﺘﺮﻫﺎ‪:‬‬ ‫‪ (1‬ﺑﺮاي ﻛﺎراﻛﺘﺮ ‪ tab‬از'‪'\t‬اﺳﺘﻔﺎده ﻛﻨﻴﺪ‪.‬‬ ‫‪ (2‬اﮔﺮ ﺧﻮاﺳﺘﻴﺪ درون ﺑﺮﻧﺎﻣﻪ رﺷﺘﻪاي را در ﭼﻨﺪ ﺧﻂ ﺑﻨﻮﻳﺴﻴﺪ از \ در آﺧﺮ ﻫﺮ ﺧﻂ اﺳﺘﻔﺎده ﻛﻨﻴﺪ ﻣﺜﻼ‬ ‫\ ‪char* c = "I have a marvelous demonstration \n‬‬ ‫\‪of this proposition which this margin‬‬ ‫;"‪is too narrow to contain‬‬

‫ﺧﻮد \ ﺟﺰء رﺷﺘﻪ ﻗﺮار ﻧﻤﻲﮔﻴﺮد )راه دﻳﮕﺮي ﻫﻢ ﻫﺴﺖ ﺑﻌﺪا ﻣﻲﮔﻮﻳﻢ(‪.‬‬ ‫‪ (3‬ﺑﺮاي ﻗﺮار دادن ﻛﺎراﻛﺘﺮ ‪ (\ (backslash‬از '\\' اﺳﺘﻔﺎده ﻛﻨﻴﺪ ﻣﺜﻼ‪:‬‬ ‫;"‪char* c = "C:\\Program Files\\Borland\\BDS\\4.0\\Bin‬‬

‫‪44‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ (4‬ﺑﺮاي ﻛﺎراﻛﺘﺮ »"« از '"\' اﺳﺘﻔﺎده ﻛﻨﻴﺪ‪.‬‬ ‫‪ (5‬ﺑﺮاي ﻛﺎراﻛﺘﺮ »'« از ''\' اﺳﺘﻔﺎده ﻛﻨﻴﺪ‪.‬‬

‫ا ر ! ه و )را ه ‬ ‫ﺣﺎل ﻛﻪ ﺑﺎ رﺷﺘﻪﻫﺎ آﺷﻨﺎ ﺷﺪﻳﺪ ﻓﺮﺻﺖ ﺧﻴﻠﻲ ﺧﻮﺑﻲ اﺳﺖ ﻛﻪ اﺷﺎرهاي ﻫﻢ ﺑﻪ اﺷﺎره ﮔﺮﻫﺎ ﺑﻜﻨﻢ‪ .‬دﻳﺪﻳﺪ ﻛﻪ ‪char‬‬

‫ﻣﻌﺮف ﻳﻚ ﻛﺎراﻛﺘﺮ اﺳﺖ و *‪ char‬ﻣﻲﺗﻮاﻧﺪ ﺑﻪ دﺳﺘﻪاي از ‪char‬ﻫﺎ ﻛﻪ در ﺣﺎﻓﻈﻪ ﭘﺸﺖ ﺳﺮﻫﻢ ﻗﺮار ﮔﺮﻓﺘﻪاﻧﺪ‬ ‫اﺷﺎره ﻛﻨﺪ‪ .‬اﻳﻦ ﻣﺨﺼﻮص ‪ char‬ﻧﻴﺴﺖ‪ int* .‬ﻫﻢ ﺑﻪ دﺳﺘﻪاي از ‪int‬ﻫﺎ ﻛﻪ در ﺣﺎﻓﻈﻪ ﭘﺸﺖ ﺳﺮ ﻫﻢ ﻗﺮار ﮔﺮﻓﺘﻪ‪-‬‬ ‫اﻧﺪ اﺷﺎره ﻣﻲﻛﻨﺪ و *‪ bool‬ﻫﻢ ﺑﻪ دﺳﺘﻪاي از ‪bool‬ﻫﺎ اﺷﺎره ﻣﻲﻛﻨﺪ و‪...‬‬ ‫ﺟﺎﻟﺐ ﺗﺮ از ﻫﻤﻪ اﻳﻦ ﻛﻪ ﻣﺜﻼ **‪ int‬ﺑﻪ دﺳﺘﻪاي از *‪int‬ﻫﺎ ﻛﻪ در ﺣﺎﻓﻈﻪ ﭘﺸﺖ ﺳﺮ ﻫﻢ ﻗﺮار دارﻧﺪ اﺷﺎره ﻣﻲ‪-‬‬ ‫ﻛﻨﺪ‪ .‬آراﻳﻪﻫﺎ ﻫﻢ ﻣﻲﺗﻮاﻧﻨﺪ از ﻫﺮ ﻧﻮﻋﻲ ﺳﺎﺧﺘﻪ ﺑﺸﻮﻧﺪ‪ .‬ﻣﺜﻼ اﮔﺮ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;]‪int a[10‬‬

‫ﭼﻬﻞ ﺑﺎﻳﺖ از ﺣﺎﻓﻈﻪي ‪ stack‬ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد و ‪ a‬ﺑﻪ اﻳﻦ ﺑﺎﻳ ﺖﻫﺎ اﺷﺎره دارد‪ a[0] .‬ﺑﻪ اوﻟﻴﺖ ﭼﻬﺎر ﺑﺎﻳﺖ‪a[1] ،‬‬

‫ﺑﻪ دوﻣﻴﻦ ﭼﻬﺎر ﺑﺎﻳﺖ و‪ ...‬اﺷﺎره دارد‪ .‬ﻫﺮ ]‪ a[i‬ﻳﻚ ﻣﺘﻐﻴﺮ از ﻧﻮع ‪ int‬اﺳﺖ‪ .‬ﻧﻮع ‪ a‬را ﻣﻲﺗﻮان *‪ int‬ﮔﺮﻓﺖ‪.‬‬ ‫ﺑﻪ ﻣﺜﺎل زﻳﺮ ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪void f(int* b‬‬ ‫{‬ ‫;‪b[0] = 1‬‬ ‫;‪b[1] = 2‬‬ ‫;‪b[2] = 3‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;]‪int* a = new int [10‬‬ ‫;)‪f(a‬‬ ‫;‪cout<< a[0] << endl‬‬ ‫;‪cout<< a[1] << endl‬‬ ‫;‪cout<< a[2] << endl‬‬ ‫;‪delete [] a‬‬ ‫;]‪int b[10‬‬ ‫;)‪f(b‬‬ ‫;‪cout<< b[0] << endl‬‬

‫‪45‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪cout<< b[1] << endl‬‬ ‫;‪cout<< b[2] << endl‬‬ ‫;‪cout<< b[3] << endl‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪846764765‬‬

‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻳﻚ ﺑﺎر از ‪ heap‬و ﺑﺎر دﻳﮕﺮ از ‪ stack‬ﺣﺎﻓﻈﻪ ﻣﻲﮔﻴﺮﻳﻢ و ‪ shortcut‬آنﻫﺎ را ﺑﻪ ﺗﺎﺑﻊ ‪ f‬ﻣﻲ‪-‬‬ ‫ﻓﺮﺳﺘﻴﻢ‪ f .‬از ﻃﺮﻳﻖ اﻳﻦ ‪shortcut‬ﻫﺎ ﺑﻪ ﺳﺮاغ ﺣﺎﻓﻈﻪﻫﺎﻳﻲ ﻣﻲرود ﻛﻪ ‪shortcut‬ﻫﺎ ﺑﻪ آنﻫﺎ اﺷﺎره دارﻧﺪ و ﻣﻘﺪار‬ ‫ﭼﻨﺪ ‪ int‬اول از آنﻫﺎ را ﺗﻐﻴﻴﺮ ﻣﻲدﻫﺪ‪ .‬ﺳﭙﺲ از ‪ f‬ﺧﺎرج ﻣﻲﺷﻮﻳﻢ‪) .‬در ﺣﻘﻴﻘﺖ ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ از ‪ f‬ﺧﺎرج‬ ‫ﻣﻲﺷﻪ وﮔﺮﻧﻪ ﻣﺎ ﻛﻪ روي ﺻﻨﺪﻟﻲ و ﭘﺸﺖ ﻣﻴﺰ ﻧﺸﺴﺴﻴﻢ و از ﻫﻴﭻ ﺟﺎ ﺧﺎرج ﻧﻤﻲﺷﻴﻢ‬

‫(‪ .‬ﺑﻪ ﺳﺮاغ ﺣﺎﻓﻈﻪﻫﺎي‬

‫ﺗﺨﺼﻴﺺ داده ﺷﺪه ﻣﻲروﻳﻢ و ﭼﻨﺪ ‪ int‬اول آنﻫﺎ را ﭼﺎپ ﻣﻲﻛﻨﻴﻢ‪ .‬ﻋﻠﺖ ﻇﺎﻫﺮ ﺷﺪن ﻋﺪد ﻋﺠﻴﺐ ‪846764765‬‬

‫اﻳﻦ اﺳﺖ ﻛﻪ ]‪ b[3‬را ﻛﻪ ﻫﻴﭻ ﻣﻘﺪاري ﺑﻪ آن ﻧﺪاده ﺑﻮدﻳﻢ ﭼﺎپ ﻛﺮدهاﻳﻢ‪ .‬ﻣﻮﻗﻊ ﮔﺮﻓﺘﻦ ﺣﺎﻓﻈﻪ‪ b[3] ،‬ﺑﺎ ﻫﻤﻴﻦ‬ ‫ﻣﻘﺪار از ‪ stack‬ﮔﺮﻓﺘﻪ ﺷﺪه ﺑﻮد و ﻣﺎ اﺻﻼ آن را ﺗﻐﻴﻴﺮ ﻧﺪادﻳﻢ‪.‬‬ ‫ﺑﻪ ﻣﺘﻐﻴﺮﻫﺎﻳﻲ از ﻧﻮع *‪ int* ،char‬و‪ pointer ، ...‬ﻳﺎ اﺷﺎره ﮔﺮ ﻣﻲﮔﻮﻳﻴﻢ‪ .‬ﻳﻚ آراﻳﻪ ﻣﺜﻞ‬ ‫;]‪int a[25‬‬

‫را ﻣﻲﺗﻮان ﻳﻚ *‪int‬ي ﻏﻴﺮ ﻗﺎﺑﻞ ﺗﻐﻴﻴﺮ )ﻳﻌﻨﻲ ﺛﺎﺑﺖ( ﮔﺮﻓﺖ‪ .‬ﺑﻪ اﻳﻦ ﻣﻌﻨﻲ ﻛﻪ ﻣﺴﺘﻘﻴﻤﺎ ﻣﻘﺪار ‪ a‬را ﻧﻤﻲﺗﻮان ﺗﻐﻴﻴﺮ‬ ‫داد‪ .‬ﻳﻌﻨﻲ ﻧﻮﺷﺘﻦ‬ ‫;]‪int* a = new int [10‬‬ ‫;]‪int b[10‬‬ ‫;‪b = a‬‬

‫ﻳﻚ ‪ error‬ﺑﻪ وﺟﻮد ﻣﻲآورد وﻟﻲ ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;]‪int* a = new int [10‬‬ ‫;]‪int b[10‬‬ ‫;‪a = b‬‬

‫ﻧﻜﺘﻪي دﻳﮕﺮ در ﻣﻮرد آراﻳﻪﻫﺎ دادن ﻣﻘﺪار اوﻟﻴﻪ اﺳﺖ‪ .‬ﺑﻪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬

‫‪46‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;}‪int a[10] = {1,2‬‬ ‫;}‪int b[] = {1,2‬‬ ‫;}'‪char c[3] = {'a','b','\0‬‬ ‫]‪cout<< a[0] << a[1] << a[2] << a[3] << a[4‬‬ ‫;‪<< a[5] << a[6] << a[7] << a[8] << a[9] << endl‬‬ ‫;‪cout<< b[0] << b[1] << endl‬‬ ‫;‪cout<< c‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1200000000‬‬ ‫‪12‬‬ ‫‪ab‬‬

‫ﻓﻘﻂ ﺑﮕﻮﻳﻢ ﻛﻪ ﺑﺎ ﻧﻮﺷﺘﻦ‬ ‫;}‪int a[10] = {1,2‬‬

‫ﻫﻤﻪي ‪ int 10‬ﻣﻮﺟﻮد در اﻳﻦ آراﻳﻪ ﺑﻪ ﺟﺰ دو ﺗﺎي اول ﺻﻔﺮ ﻣﻲﺷﻮﻧﺪ‪ .‬در ﺿﻤﻦ ‪ b‬ﺑﻪ دو ‪ int‬ﭘﺸﺖ ﺳﺮ ﻫﻢ‪،‬‬ ‫اﺷﺎره دارد‪ .‬ﻫﻢ ﭼﻨﻴﻦ ﺑﻪ ﺟﺎي‬ ‫;}'‪char c[3] = {'a','b','\0‬‬

‫ﺧﻴﻠﻲ راﺣﺖ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;"‪char c[3] = "ab‬‬

‫‪pointer‬ﻫﺎ ﺣﺘﻤﺎ ﻻزم ﻧﻴﺴﺖ ﺑﻪ دﺳﺘﻪاي ﭼﻨﺪﺗﺎﻳﻲ از ﻣﺘﻐﻴﺮﻫﺎ در ﺣﺎﻓﻈﻪ اﺷﺎره ﻛﻨﻨﺪ‪ .‬ﻳﻚ ‪ pointer‬ﻣﻲﺗﻮاﻧﺪ ﺣﺘﻲ‬ ‫ﺑﻪ ﻓﻘﻂ ﻳﻚ ﻣﺘﻐﻴﺮ )ﻛﻪ ﺣﺎﻓﻈﻪي آن ﺗﺤﺖ اﺧﺘﻴﺎر اﺳﺖ( اﺷﺎره ﻛﻨﺪ‪.‬‬ ‫اﮔﺮ ‪ a‬ﻣﺘﻐﻴﺮي ﺑﺎ ﻧﻮع ‪ int‬ﺑﺎﺷﺪ و ﺑﺨﻮاﻫﻴﻢ ﻳﻚ ‪ pointer‬ﺑﻪ آن داﺷﺘﻪ ﺑﺎﺷﻴﻢ از ‪ &a‬اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ ﻛﻪ ﻳﻚ‬ ‫‪ pointer‬ﺑﻪ ‪ a‬اﺳﺖ‪ .‬ﺑﻨﺎﺑﺮاﻳﻦ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪int* p = &a‬‬

‫ﺣﺎل اﮔﺮ ﺑﺨﻮاﻫﻴﻢ از ‪ p‬ﺑﻪ ‪ a‬ﺑﺮﺳﻴﻢ ﻛﺎﻓﻲ اﺳﺖ از ‪ *p‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ .‬ﻳﻌﻨﻲ ‪ *p‬ﻫﻤﺎن ‪ a‬اﺳﺖ ﺑﺎ ﻫﻤﺎن ﻣﻜﺎن از‬ ‫ﺣﺎﻓﻈﻪ‪ .‬ﻣﺜﺎل زﻳﺮ اﻳﻦ ﺷﻜﻞ از ﻛﺎرﺑﺮد ‪pointer‬ﻫﺎ را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a = 2‬‬

‫‪47‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪int* p = &a‬‬ ‫;‪*p = 5‬‬ ‫;‪cout<< a‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬

‫از ﺧﺮوﺟﻲ ﻣﻲﺗﻮان ﻓﻬﻤﻴﺪ ﻛﻪ واﻗﻌﺎ ﻣﻜﺎن ‪ *p‬و ‪ a‬در ﺣﺎﻓﻈﻪ ﻳﻜﻲ اﺳﺖ وﮔﺮﻧﻪ ﺧﺮوﺟﻲ ﺑﺎﻳﺪ ‪ 2‬ﻣﻲﺑﻮد‪ .‬در ﺿﻤﻦ‬ ‫ﺑﻪ ﺟﺎي‬ ‫;‪*p = 5‬‬

‫ﻣﻲﺗﻮاﻧﺴﺘﻴﻢ ﻣﺎﻧﻨﺪ ﻗﺒﻞ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪p[0] = 5‬‬

‫ﭼﻮن ‪ p‬ﺑﻪ ﻣﻜﺎﻧﻲ از ﺣﺎﻓﻈﻪ ﺷﺎﻣﻞ ﻓﻘﻂ ﻳﻚ ‪ int‬اﺷﺎره دارد و اﻳﻦ ﺑﺎ وﻗﺘﻲ ﻛﻪ ‪ p‬ﺑﻪ ﻣﻜﺎﻧﻲ ﺷﺎﻣﻞ ﭼﻨﺪ ‪ int‬اﺷﺎره‬ ‫داﺷﺘﻪ ﺑﺎﺷﺪ ﻓﺮﻗﻲ ﻧﻤﻲﻛﻨﺪ‬

‫‪.‬‬

‫ﺗﺎ ﺑﻪ ﺣﺎل ﻣﺘﻐﻴﺮﻫﺎ را روي ‪ stack‬درﺳﺖ ﻣﻲﻛﺮدﻳﻢ و ﺑﻪ ﻫﻤﻴﻦ ﻋﻠﺖ ﺑﺎ ﺧﺮوج از ﺗﺎﺑﻌﻲ ﻛﻪ آنﻫﺎ را ﺳﺎﺧﺘﻪ‪ ،‬ﺣﺎﻓﻈﻪ‬ ‫ﺧﻮد ﺑﻪ ﺧﻮد آزاد ﻣﻲﺷﺪ‪ .‬ﺣﺎﻻ ﻣﻲﺗﻮاﻧﻴﻢ ﻳﻚ ﻣﺘﻐﻴﺮ را روي ‪ heap‬ﺑﺴﺎزﻳﻢ و ﻫﺮ وﻗﺖ ﺧﻮدﻣﺎن ﺧﻮاﺳﺘﻴﻢ آن را آزاد‬ ‫ﻛﻨﻴﻢ‪ .‬در ﻣﺜﺎل زﻳﺮ اﻳﻦ ﻛﺎر را اﻧﺠﺎم دادهام‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;]‪int* p = new int [1‬‬ ‫;‪*p = 4‬‬ ‫;‪cout<< *p‬‬ ‫;‪delete [] p‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪4‬‬

‫درواﻗﻊ ‪ *p‬ﻫﻤﺎن ﻣﺘﻐﻴﺮي اﺳﺖ ﻛﻪ ﻣﻦ ﺳﺎﺧﺘﻪام‪ .‬ﻫﻤﻴﻦ ﺑﺮﻧﺎﻣﻪ را ﻣﻲﺗﻮان ﺑﺎ ﺣﺬف ][ﻫﺎ ﺑﻪ ﺻﻮرت ﺳﺎده ﺗﺮ زﻳﺮ‬ ‫ﻧﻮﺷﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int* p = new int‬‬

‫‪48‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪*p = 4‬‬ ‫;‪cout<< *p‬‬ ‫;‪delete p‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪4‬‬ ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ‪ delete‬ﻫﻢ ][ ﻧﺪارد‪ .‬وﻗﺘﻲ ﺗﻨﻬﺎ ﻳﻚ ﻣﺘﻐﻴﺮ ﻣﻲﺳﺎزﻳﻢ ﻻزم ﻧﻴﺴﺖ از ][ ﺑﺮاي ‪ new‬و ‪delete‬‬

‫اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ .‬اﻟﺒﺘﻪ ﻳﺎ ﻫﺮ دو را ﺑﺎﻳﺪ ﺑﺪون ][ ﻧﻮﺷﺖ ﻳﺎ ﻫﺮدو را ﺑﺎ ][ ﻧﻪ اﻳﻦ ﻛﻪ ﺑﺮاي ﻳﻜﻲ ][ ﺑﻨﻮﻳﺴﻴﻢ و ﺑﺮاي‬ ‫دﻳﮕﺮي ﻧﻨﻮﻳﺴﻴﻢ‪ .‬اﮔﺮ در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺑﺨﻮاﻫﻴﻢ ﻧﺎم ﺳﺎده ﺗﺮي )ﻣﺜﻼ ‪ (a‬ﺑﻪ ‪ *p‬ﺑﺪﻫﻴﻢ ﺑﺎﻳﺪ از &‪ int‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int* p = new int‬‬ ‫;‪int& a = *p‬‬ ‫;‪*p = 4‬‬ ‫;‪cout<< a‬‬ ‫;‪delete p‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪4‬‬ ‫ﻛﻪ در آن ‪ *p‬و ‪ a‬دﻗﻴﻘﺎ ﻳﻚ ﻣﻜﺎن در ﺣﺎﻓﻈﻪ دارﻧﺪ و ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ وﻗﺘﻲ ﻣﻘﺪار ‪ *p‬را ‪ 4‬ﻗﺮار دادﻳﻢ‪ ،‬ﻣﻘﺪار ‪a‬‬

‫ﻫﻢ ‪ 4‬ﺷﺪ‪ a .‬روي ‪ heap‬ﻗﺮار دارد‪ .‬در ﺿﻤﻦ ﭘﺲ از دﺳﺘﻮر‬ ‫;‪delete p‬‬

‫اﺳﺘﻔﺎده از ‪ a‬ﺧﻄﺮﻧﺎك اﺳﺖ زﻳﺮا ‪ a‬ﺑﺨﺸﻲ از ﺣﺎﻓﻈﻪ اﺳﺖ ﻛﻪ آزاد ﺷﺪه و دﻳﮕﺮ ﺗﺤﺖ ﻛﻨﺘﺮل ﺑﺮﻧﺎﻣﻪ ﻧﻴﺴﺖ و‬ ‫اﺳﺘﻔﺎده از آن ﻣﻤﻜﻦ اﺳﺖ ﻣﻮﺟﺐ ‪ crash‬ﺷﻮد‪ .‬ﻣﻌﻨﻲ ‪ crash‬را ﻗﺒﻼ در ﺻﻔﺤﻪي ‪ 31‬ﮔﻔﺘﻪام‪) .‬اﻳﻦ ارﺟﺎع ﻣﻦ ﺑﻪ‬ ‫ﺻﻔﺤﻪي ‪ 31‬ﻛﻤﻲ ﻏﻴﺮ ﻋﺎﻗﻼﻧﻪ اﺳﺖ‬

‫زﻳﺮا ﮔﻔﺘﻦ ﻣﻌﻨﻲ ‪ crash‬ﺟﺎﻳﻲ ﻛﻢ ﺗﺮي ﻣﻲﮔﺮﻓﺖ‬

‫و اﻳﻦ ﻛﺎر ﻣﻦ‬

‫ﻣﺜﻞ اﺳﺘﻔﺎده از ﻳﻚ ‪ pointer‬ﺑﻪ ﻳﻚ ﻛﺎراﻛﺘﺮ اﺳﺖ‪ .‬ﭼﻮن ﺣﺠﻢ ‪ pointer‬ﭼﻬﺎر ﺑﺮاﺑﺮ ﺧﻮد ﻛﺎراﻛﺘﺮ ﻣﻲﺷﻮد‪.‬‬ ‫(‬ ‫ﺑﻪ ﻣﺘﻐﻴﺮي ﻣﺜﻞ ‪ a‬در ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ ﻛﻪ ﺑﺎ &‪ int‬ﺗﻌﺮﻳﻒ ﺷﺪه ‪ reference‬ﻣﻲﮔﻮﻳﻨﺪ‪ .‬ﻳﺎدﺗﺎن ﻫﺴﺖ ﻛﻪ ﻗﺒﻼ از‬ ‫&‪ int‬در ﺗﻌﺮﻳﻒ ﭘﺎراﻣﺘﺮﻫﺎي ﻳﻚ ﺗﺎﺑﻊ اﺳﺘﻔﺎده ﻛﺮدﻳﻢ ﺗﺎ آن ﺗﺎﺑﻊ ﺑﺘﻮاﻧﺪ ﻣﻘﺪار آرﮔﻮﻣﺎن را ﺗﻐﻴﻴﺮ دﻫﺪ‪.‬‬

‫‪49‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪reference‬ﻫﺎ ﻣﺨﺼﻮص ‪ C++‬ﻫﺴﺘﻨﺪ و در زﺑﺎن ‪ C‬ﻣﻮﺟﻮد ﻧﻴﺴﺘﻨﺪ‪ .‬در زﺑﺎن ‪ C‬ﺑﺮاي اﻳﺠﺎد اﻳﻦ ﻗﺎﺑﻠﻴﺖ در ﺗﺎﺑﻊﻫﺎ‬ ‫از ‪pointer‬ﻫﺎ اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪.‬‬

‫ا اد ‪/ 01‬‬

‫ﺑﺮاي ﻧﺸﺎن دادن ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ ﻧﻮعﻫﺎي ﻣﺨﺘﻠﻔﻲ ﻫﺴﺖ‪:‬‬ ‫ﺗﻌﺪاد ﺑﺎﻳﺖ‬

‫ﻧﻮع‬

‫‪4‬‬ ‫‪2‬‬ ‫‪4‬‬ ‫‪8‬‬

‫‪Int‬‬ ‫‪Short‬‬ ‫‪Long‬‬ ‫‪__int64‬‬

‫ﺑﻪ ﺟﺎي ‪ long‬ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ ‪ ،long int‬ﺑﻪ ﺟﺎي ‪ short‬ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ ‪ short int‬و ﺑﻪ ﺟﺎي‬ ‫‪ __int64‬ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ ‪ .long long‬در ‪compiler‬ﻫﺎي ﺧﻴﻠﻲ ﻗﺪﻳﻤﻲ ‪ int‬دو ﺑﺎﻳﺘﻲ اﺳﺖ وﻟﻲ‬ ‫اﻣﺮوزه ﭼﻬﺎر ﺑﺎﻳﺘﻲ اﺳﺖ‪ .‬در ‪ Visual C++ 2005‬ﻣﻲﺷﻮد از ‪ __int128‬ﻫﻢ اﺳﺘﻔﺎده ﻛﺮد اﻣﺎ ﻫﻨﻮز ﺑﻪ ﻃﻮر‬ ‫ﻛﺎﻣﻞ ﺟﺎ ﻧﻴﻔﺘﺎده ﻣﺜﻼ )‪ sizeof(__int128‬ﺧﻄﺎ اﻳﺠﺎد ﻣﻲﻛﻨﺪ‪.‬‬

‫ا اد ا ‪ 5‬ر ‬

‫ﮔﻔﺘﻢ ﻣﺘﻐﻴﺮي ﻛﻪ ﻧﻮع ﻣﺘﻐﻴﺮي را ﻛﻪ ﻗﺮار اﺳﺖ ﻋﺪدﻫﺎي اﻋﺸﺎري را در ﺧﻮدش ذﺧﻴﺮه ﻛﻨﺪ‪ double ،‬ﻣﻲﮔﻴﺮﻳﻢ‪.‬‬ ‫‪ 8 double‬ﺑﺎﻳﺘﻲ اﺳﺖ‪ .‬ﻧﻮع دﻳﮕﺮي ﻫﺴﺖ ﻛﻪ ﺣﺠﻢ ﻛﻢ ﺗﺮي دارد‪ float .‬ﻳﻚ ﻧﻮع ‪ 4‬ﺑﺎﻳﺘﻲ اﺳﺖ و ﻣﺜﻞ‬ ‫‪ double‬ﺑﺮاي ذﺧﻴﺮهي اﻋﺪاد اﻋﺸﺎري ﺑﻪ ﻛﺎر ﻣﻲرود‪.‬‬ ‫در اﻳﻦ ﺟﺎ ﻣﻲﺧﻮاﻫﻢ ﻛﻤﻲ در ﻣﻮرد ﻧﺤﻮهي ذﺧﻴﺮه ﺷﺪن ﻳﻚ ﻋﺪد اﻋﺸﺎري ﺣﺮف ﺑﺰﻧﻢ‪ .‬ﻫﺮ ﻋﺪدي اﻋﺸﺎري را ﻣﻲ‪-‬‬ ‫ﺷﻮد ﺑﻪ ﺷﻜﻞ ﻧﺸﺎن داد ﻛﻪ ﻳﻚ ﻋﺪد اﻋﺸﺎري در ﻣﺒﻨﺎي ‪ 2‬ﺑﻴﻦ ‪ .‬و ‪ .‬اﺳﺖ و ﻳﻚ ﻋﺪد‬ ‫ﺻﺤﻴﺢ در ﻣﺒﻨﺎي ‪ 2‬اﺳﺖ‪ .‬ﻣﺜﻼ ﻣﻲﺗﻮاﻧﺪ ‪ .‬ﺑﺎﺷﺪ و ﻣﻲﺗﻮاﻧﺪ ﺑﺎﺷﺪ‪ .‬ﺑﻪ ﻣﺎﻧﺘﻴﺲ‬ ‫)‪ (mantissa‬و ﺑﻪ ﻧﻤﺎ )‪ (exponent‬ﻣﻲﮔﻮﻳﻨﺪ‪ .‬ﺑﺮاي ذﺧﻴﺮه ﻛﺮدن ﻳﻚ ﻋﺪد اﻋﺸﺎري از ﻫﻤﻴﻦ ﺷﻜﻞ ﻧﻤﺎﻳﺶ‬ ‫اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪ .‬ﻳﻌﻨﻲ ﺑﻪ ﺟﺎي ذﺧﻴﺮه ﻛﺮدن ﺧﻮد ﻋﺪد‪ ،‬اول آن را ﺑﻪ ﺷﻜﻞ ﻣﻲﻧﻮﻳﺴﻴﻢ و و را‬ ‫‪50‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ذﺧﻴﺮه ﻣﻲﻛﻨﻴﻢ‪ .‬ﭼﻮن ﻫﻤﻴﺸﻪ ﺑﺎ »‪ « .‬ﺷﺮوع ﻣﻲﺷﻮد‪ ،‬ﻧﻴﺎزي ﺑﻪ ذﺧﻴﺮه ﻛﺮدن »‪ « .‬ﻧﻴﺴﺖ و ﻛﺎﻓﻲ اﻋﺪاد ﺑﻌﺪ از‬ ‫ﻣﻤﻴﺰ را ذﺧﻴﺮه ﻛﻨﻴﻢ‪ .‬ﻳﻚ ﺑﻴﺖ ﻫﻢ ﺑﺎﻳﺪ ﺑﺮاي ﻣﺸﺨﺺ ﻛﺮدن ﻋﻼﻣﺖ ﻣﺜﺒﺖ ﻳﺎ ﻣﻨﻔﻲ ﻛﻨﺎر ﮔﺬاﺷﺘﻪ ﺷﻮد‪ .‬ﺟﺪول زﻳﺮ‬ ‫ﺗﻌﺪاد ﺑﻴﺖﻫﺎﻳﻲ ﻛﻪ ﺑﺮاي ﻣﺎﻧﺘﻴﺲ و ﻧﻤﺎ ﺑﻪ ﻛﺎر ﻣﻲرود ﻧﺸﺎن ﻣﻲﻫﺪ‪:‬‬ ‫ﺗﻌﺪاد ﺑﻴﺖﻫﺎي ﻣﺎﻧﺘﻴﺲ‬

‫ﺗﻌﺪاد ﺑﻴﺖﻫﺎي ﻧﻤﺎ‬

‫ﻧﻮع‬

‫‪23‬‬ ‫‪52‬‬

‫‪8‬‬ ‫‪11‬‬

‫‪float‬‬ ‫‪double‬‬

‫ﭘﺲ ﺑﺰرگ ﺗﺮﻳﻦ ﻋﺪدي را ﻛﻪ در ﻳﻚ ﻣﺘﻐﻴﺮ ‪ float‬ﻣﻲﺷﻮد ذﺧﻴﺮه ﻛﺮد اﻳﻦ اﺳﺖ‪:‬‬ ‫ ‪ .‬‬ ‫ ‪ .‬‬ ‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﻧﻤﺎ ﻣﻲﺗﻮاﻧﺪ ﻣﺜﺒﺖ ﻳﺎ ﻣﻨﻔﻲ ﺑﺎﺷﺪ‪ .‬ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﺑﻴﺶﺗﺮﻳﻦ ﻣﻘﺪارش ‪ 127‬اﺳﺖ‪ .‬اﮔﺮ از اﻳﻦ‬ ‫ﻣﺤﺎﺳﺒﺎت آﺧﺮي ﺧﻴﻠﻲ ﺳﺮ در ﻧﻤﻲآورﻳﺪ ﻣﻬﻢ ﻧﻴﺴﺖ! اﻳﻦ ﺑﺨﺶ ﺑﻴﺶ ﺗﺮ ﺑﻪ درد اﻃﻼﻋﺎت ﻋﻤﻮﻣﻲ ﻣﻲﺧﻮرد ﺗﺎ‬ ‫ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ‪ .‬اﻟﺒﺘﻪ ﺑﻌﺪا اﺷﺎرهﻫﺎﻳﻲ ﺑﻪ اﻳﻦ ﺟﺎ ﻣﻲﻛﻨﻢ‪.‬‬ ‫ﺑﻪ ﻧﻤﺎﻳﺶ ﻣﻤﻴﺰ ﺷﻨﺎور )‪ (floating point‬ﻣﻲﮔﻮﻳﻨﺪ‪ .‬ﺟﺰﺋﻴﺎت زﻳﺎدي درﺑﺎرهي دﻗﺖ و ﺟﻤﻊ و ﺿﺮب‬ ‫دو ﻋﺪد ﺑﻪ ﺻﻮرت ﻣﻤﻴﺰ ﺷﻨﺎور ﻫﺴﺖ‪ .‬ﻣﻦ وارد ﺟﺰﺋﻴﺎت ﻧﻤﻲﺷﻮم‪.‬‬ ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ را ﺑﺒﻴﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪double r = 123456789123456789‬‬ ‫;‪cout<< r‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪1.23457e+17‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫‪1.23457e+017‬‬

‫‪51‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﮔﺮﭼﻪ ‪ double‬ﻣﻲﺗﻮاﻧﺪ اﻋﺪاد ﺧﻴﻠﻲ ﺑﺰرﮔﻲ را دﺧﻮدش ﺟﺎ ﺑﺪﻫﺪ وﻟﻲ ﻫﺮ ﭼﻪ ﻋﺪد ﺑﺰرگ ﺗﺮ ﺷﺪ دﻗﺖ ﻛﻢ و ﻛﻢ‬ ‫ﺗﺮ ﻣﻲﺷﻮد‪ .‬در ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ ﺧﺮوﺟﻲ ﻣﻲﮔﻮﻳﺪ ﻛﻪ ﻋﺪد ﺑﻪ ﺷﻜﻞ ‪ .‬ذﺧﻴﺮه ﺷﺪه ﻛﻪ اﻳﻦ ﻳﻌﻨﻲ‬ ‫ﺑﻪ ﺟﺎي ‪ 123456789123456789‬ﺑﺎ ﺗﻘﺮﻳﺐ ﻋﺪد ‪ 123457000000000000‬در ﻧﻈﺮ ﮔﺮﻓﺘﻪ ﺷﺪه‪ .‬ﺑﻪ‬ ‫ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﻫﻨﮕﺎم ‪ compile‬ﻛﺮدن ﻳﻚ ‪ warning‬ﻫﻢ درﻳﺎﻓﺖ ﻣﻲﻛﻨﻴﻢ‪.‬‬ ‫در ‪ Visual C++ 2005‬ﺑﻪ ﺟﺎي ‪ double‬ﻣﻲﺗﻮان ﻧﻮﺷﺖ ‪ .long float‬ﻧﻮع ‪ long double‬ﻫﻢ‬ ‫دارﻳﻢ ﻛﻪ در ‪ 10 ،BDS 2006‬ﺑﺎﻳﺖ اﺳﺖ اﻣﺎ در ‪ Visual C++ 2005‬ﻣﺜﻞ ‪ 8 double‬ﺑﺎﻳﺖ اﺳﺖ‪.‬‬

‫'‪ 6 ,‬ع‬

‫ﻫﺮ ﻣﺘﻐﻴﺮ در ﺗﻌﺪادي از ﺑﺎﻳﺖﻫﺎي ﻣﻮﺟﻮد در ﺣﺎﻓﻈﻪ ﻗﺮار ﻣﻲﮔﻴﺮد‪ .‬ﺳﻮال اﻳﻦ اﺳﺖ ﻛﻪ ﭘﺲ ﭼﻪ ﻓﺮﻗﻲ وﺟﻮد دارد‬ ‫ﺑﻴﻦ ﻳﻚ ﻣﺘﻐﻴﺮ ﺑﺎ ﻧﻮع ‪ int‬ﻛﻪ ﭼﻬﺎر ﺑﺎﻳﺖ اﺳﺖ و ﻳﻚ ﻣﺘﻐﻴﺮ ﺑﺎ ﻧﻮع *‪ char‬ﻛﻪ آن ﻫﻢ ﭼﻬﺎر ﺑﺎﻳﺖ اﺳﺖ؟ ﻣﻲ‪-‬‬ ‫ﺷﻮد ﮔﻔﺖ ﻫﻴﭻ ﻓﺮﻗﻲ ﻧﻴﺴﺖ وﻟﻲ ‪ compiler‬ﺑﻴﻦ آنﻫﺎ ﻓﺮق ﻣﻲﮔﺬارد‪ compiler .‬اﺻﻼ اﺟﺎزه ﻧﻤﻲدﻫﺪ ﻛﻪ ﺑﻲ‬ ‫ﻣﻘﺪﻣﻪ ﻳﻚ ‪ int‬ﺑﻪ ﻋﻨﻮان *‪ char‬اﺳﺘﻔﺎده ﺷﻮد‪ .‬ﻗﺒﻼ ﮔﻔﺘﻪ ﺑﻮدم ﻛﻪ ‪compiler‬ﻫﺎي ‪ C‬اﻳﻦ اﺟﺎزه را ﻣﻲدﻫﻨﺪ‬ ‫وﻟﻲ در ‪ C++‬ﺑﺎﻳﺪ ﺑﻪ وﺳﻴﻠﻪي ‪ casting‬ﻳﻚ ﺗﺒﺪﻳﻞ ﻧﻮع آﺷﻜﺎر اﻧﺠﺎم ﺑﺸﻮد‪ .‬اﮔﺮ ﻳﺎدﺗﺎن ﺑﺎﺷﺪ ﻗﺒﻼ ﮔﻔﺘﻪ ﺑﻮدم ﻛﻪ‬ ‫ﺗﻘﺮﻳﺒﺎ ﻫﺮ ﺑﺮﻧﺎﻣﻪي ‪ C‬ﻳﻚ ﺑﺮﻧﺎﻣﻪي ‪ C++‬اﺳﺖ‪ .‬ﺑﺮﺧﻲ ﺑﺮﻧﺎﻣﻪﻫﺎي ‪ C‬ﺑﺮاي اﺟﺮا ﺷﺪن در ‪ C++‬ﻧﻴﺎز ﺑﻪ ﺗﻐﻴﻴﺮاﺗﻲ‬ ‫ﺟﺰﺋﻲ دارﻧﺪ‪ .‬ﺑﺮاي ﻣﺜﺎل ﻧﻮﺷﺘﻦ‬ ‫;‪int* a = 5000‬‬

‫در ‪ C‬ﻫﻴﭻ ﺧﻄﺎﻳﻲ ﻧﺪارد اﻣﺎ در ‪ C++‬ﺑﺎﻳﺪ ﻧﻮﺷﺖ‪:‬‬ ‫;‪int* a =(int*) 5000‬‬

‫ﻧﻮﺷﺘﻦ )*‪(int‬ﺟﻠﻮي ‪ 5000‬ﺑﺎﻋـﺚ ﻣﻲﺷﻮد ﻛﻪ ‪ 5000 ،compiler‬را ﻳﻚ *‪ int‬ﺑﮕﻴﺮد‪ .‬ﺑﻪ اﻳﻦ ﺷﻜﻞ از‬ ‫ﺗﺒﺪﻳﻞ ﻧﻮع‪ casting ،‬ﻣﻲﮔﻮﻳﻨﺪ‪ .‬ﻻزم ﻧﻴﺴﺖ ﺣﺘﻤﺎ ﺗﻌﺪاد ﺑﺎﻳﺖﻫﺎي دو ﻧﻮﻋﻲ ﻛﻪ ﺑﻪ ﻫﻢ ﺗﺒﺪﻳﻞ ﻣﻲﺷﻮﻧﺪ ﺑﺮاﺑﺮ ﺑﺎﺷﻨﺪ؛‬ ‫اﮔﺮ ﭼﻴﺰي زﻳﺎد ﺑﻴﺎﻳﺪ ﺣﺬف ﻣﻲﺷﻮد و اﮔﺮ ﭼﻴﺰي ﻛﻢ ﺑﻴﺎﻳﺪ ﺑﻪ ﺟﺎﻳﺶ ﺻﻔﺮ ﮔﺬاﺷﺘﻪ ﻣﻲﺷﻮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪c; // char* --> int‬‬

‫‪52‬‬

‫‪www.pupuol.com‬‬

‫;"‪= "a‬‬ ‫)‪= (int‬‬

‫)(‪int main‬‬ ‫{‬ ‫‪char* c‬‬ ‫‪int‬‬ ‫‪a‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪char ch1 = (char) c; // char* --> char‬‬ ‫‪char ch2 = (char) a; // int‬‬ ‫‪--> char‬‬ ‫;‪cout<< (int) ch1 << endl << a << endl << (int) ch2‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪-78‬‬ ‫‪4219058‬‬ ‫‪-78‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫‪76‬‬ ‫‪4290124‬‬ ‫‪76‬‬

‫در اﻳﻦ ﻣﺜﺎل ﺳﻌﻲ ﻛﺮدهام ﻧﺸﺎن دﻫﻢ وﻗﺘﻲ از ﭼﻬﺎر ﺑﺎﻳﺖ از ﺣﺎﻓﻈﻪ ﺣﺮف ﻣﻲزﻧﻴﻢ ﻧﻴﺎزي ﺑﻪ ﺑﻴﺎن ﻧﻮع ﻧﻴﺴﺖ‪ .‬اﻳﻦ‬ ‫‪ compiler‬اﺳﺖ ﻛﻪ روي ﻧﻮع ﺣﺴﺎس اﺳﺖ وﮔﺮﻧﻪ ﺑﺎﻳﺖﻫﺎي ﺣﺎﻓﻈﻪ از ﺻﻔﺮ و ﻳﻚ درﺳﺖ ﺷﺪهاﻧﺪ و ﻧﻮع ﺑﺮاي‬ ‫آنﻫﺎ ﻣﻌﻨﻲ ﻧﺪارد‪ .‬ﻗﺒﻞ از ﺗﻮﺿﻴﺢ ﻣﺜﺎل ﺑﺎﻻ ﻻزم اﺳﺖ ﺑﺪاﻧﻴﺪ ﻛﻪ ﻫﺮ ﻛﺎراﻛﺘﺮ ﻳﻚ ﺑﺎﻳﺖ اﺳﺖ و ﺑﻪ ﻣﻘﺪار ﻋﺪدي اﻳﻦ‬ ‫ﺑﺎﻳﺖ ﻛﺪ ‪) ASCII‬ﺑﺨﻮاﻧﻴﺪ اَﺳﻜﻲ( ﻛﺎراﻛﺘﺮ ﻣﻲﮔﻮﻳﻨﺪ‪ .‬ﻣﺜﻼ ﻛﺪ ‪ ASCII‬ﻛﺎراﻛﺘﺮ '‪ 'a‬ﻋﺪد ‪ 97‬اﺳﺖ‪.‬‬ ‫‪ ASCII‬ﻣﺨﻔﻒ‬ ‫‪American Standard Code for Information Interchange‬‬ ‫اﺳﺖ‪ .‬وﻗﺘﻲ ﺑﺎ ‪ cout‬ﻣﺘﻐﻴﺮي از ﻧﻮع ‪ char‬ﺑﺎ ﻣﻘﺪار ‪ 97‬را ﭼﺎپ ﻣﻲﻛﻨﻴﻢ‪ cout ،‬اول ﻧﻮع آن را ﺗﺸﺨﻴﺺ ﻣﻲ‪-‬‬ ‫دﻫﺪ و ﭼﻮن ﻣﻲﺑﻴﻨﺪ ﻛﺎراﻛﺘﺮ اﺳﺖ ﺑﻪ ﺟﺎي ﻋﺪد ‪ 97‬ﺷﻜﻞ ﻛﺎراﻛﺘﺮي آن )ﻳﻌﻨﻲ ‪ (a‬را ﭼﺎپ ﻣﻲﻛﻨﺪ‪ .‬اﻣﺎ اﮔﺮ‬ ‫ﺑﺨﻮاﻫﻴﻢ ﻣﻘﺪار ﻋﺪدي )ﻳﻌﻨﻲ ﻫﻤﺎن ﻛﺪ ‪ (ASCII‬را ﭼﺎپ ﻛﻨﻴﻢ ﺑﺎﻳﺪ ﺑﺎ ‪ casting‬آن ﻛﺎراﻛﺘﺮ را ﺑﻪ ‪ int‬ﺗﺒﺪﻳﻞ‬ ‫ﻛﻨﻴﻢ ﺑﻌﺪ ﭼﺎﭘﺶ ﻛﻨﻴﻢ‪ .‬ﻣﺜﻼ ﺧﺮوﺟﻲ‬ ‫;'‪cout<< (int) 'a‬‬

‫اﻳﻦ اﺳﺖ‪:‬‬ ‫‪97‬‬

‫در ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ ﻳﻚ ‪ pointer‬ﻛﻪ ﭼﻬﺎر ﺑﺎﻳﺖ دارد ﺑﻪ وﺟﻮد آﻣﺪه‪ .‬اول ﺑﻪ ‪ a‬ﻛﻪ ﭼﻬﺎر ﺑﺎﻳﺘﻲ اﺳﺖ ‪ cast‬ﺷﺪه‪ .‬ﺑﻌﺪ‬ ‫ﻫﻤﺎن ‪ pointer‬ﺑﻪ ‪ cast ،ch1‬ﺷﺪه ﻛﻪ ﭼﻮن ‪ ch1‬ﻳﻚ ﺑﺎﻳﺖ ﺑﻴﺶ ﺗﺮ ﻧﺪارد ﺗﻨﻬﺎ ﺑﺎﻳﺖ اول ‪ c‬درش ﻗﺮار ﮔﺮﻓﺘﻪ‪.‬‬ ‫ﺑﻌﺪ ‪ a‬ﺑﻪ ‪ cast ،ch2‬ﺷﺪه‪ .‬ﺑﺎز ﻫﻢ ﭼﻮن ‪ ch2‬ﻳﻚ ﺑﺎﻳﺖ ﺑﻴﺶ ﺗﺮ ﻧﺪارد ﺗﻨﻬﺎ ﺑﺎﻳﺖ اول ‪ a‬درش ﻗﺮار ﮔﺮﻓﺘﻪ‪ .‬در‬ ‫ﭘﺎﻳﺎن ﻣﻘﺪار اﻳﻦ ﻣﺘﻐﻴﺮﻫﺎ ﺑﻪ ﺻﻮرت ﻋﺪدي ﭼﺎپ ﺷﺪهاﻧﺪ‪ .‬ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻣﻘﺪار ‪ ch1‬ﺑﺎ ‪ ch2‬ﻳﻜﻲ اﺳﺖ‪ .‬ﻋﻠﺘﺶ اﻳﻦ‬ ‫اﺳﺖ ﻛﻪ ﭼﻬﺎر ﺑﺎﻳﺖ ‪ a‬ﻛﺎﻣﻼ ﺑﺎ ﭼﻬﺎر ﺑﺎﻳﺖ ‪ c‬ﻳﻚ ﺟﻮر اﺳﺖ )ﮔﺮﭼﻪ ﻧﻮع اﻳﻦ دو ﺗﺎ ﻣﺘﻐﻴﺮ از ﻧﻈﺮ ‪compiler‬‬

‫‪53‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻣﺘﻔﺎوت اﺳﺖ(‪ .‬ﭘﺲ ﺑﺎﻳﺖ اول ‪ a‬و ‪ c‬ﻫﻢ ﻳﻚ ﺟﻮر اﺳﺖ‪ .‬ﺑﺎﻳﺖ اول ‪ c‬در ‪ ch1‬و ﺑﺎﻳﺖ اول ‪ a‬در ‪ ch2‬ﻗﺮار‬ ‫ﮔﺮﻓﺘﻪ اﺳﺖ‪ .‬ﺑﻨﺎﺑﺮاﻳﻦ ﺑﺎﻳﺪ ﻣﻘﺪار ‪ ch1‬و ‪ ch2‬ﻳﻜﻲ ﺑﺎﺷﺪ ﻛﻪ ﻣﻲﺑﻴﻨﻴﻢ ﻫﺴﺖ‪.‬‬ ‫در ‪ C++‬ﻫﻢ ﻣﺜﻞ ‪ C‬ﻧﻴﺎز ﻧﻴﺴﺖ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪= (char) 97‬‬

‫‪char ch‬‬

‫و ﻛﺎﻓﻲ اﺳﺖ ﺑﻪ ﺟﺎي آن ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪char ch = 97‬‬

‫ﮔﺮﭼﻪ ﻓﺮم اول ﻫﻢ درﺳﺖ اﺳﺖ‪ .‬در واﻗﻊ ﺗﺒﺪﻻت ﺑﻴﻦ ‪ char‬و ‪ int‬و ﺑﺮﺧﻲ اﻧﻮاع دﻳﮕﺮ ﺧﻴﻠﻲ ﺳﺎده و ﺑﻪ ﻃﻮر‬ ‫ﺧﻮدﻛﺎر اﻧﺠﺎم ﻣﻲﺷﻮد‪ .‬ﺑﻪ ﻣﺜﺎل زﻳﺮ دﻗﺖ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a = 1025‬‬ ‫;‪char ch = a‬‬ ‫;‪a = ch‬‬ ‫;‪cout<< a‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ‪ a‬در ﻃﻲ اﻳﻦ ﺗﺒﺪﻳﻞ ﻧﻮعﻫﺎ ﺑﺎﻳ ﺖﻫﺎي ﻣﻔﻴﺪ ﺧﻮد را از دﺳﺖ داده اﺳﺖ‪ .‬ﻣﻨﻈﻮر ار ﺑﺎﻳﺖ ﻣﻔﻴﺪ‪ ،‬ﺑﺎﻳﺖ ﻏﻴﺮ‬ ‫ﺻﻔﺮ اﺳﺖ‪ a .‬اول ﺑﻪ اﻳﻦ ﺷﻜﻞ اﺳﺖ‪:‬‬

‫‪0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1‬‬

‫وﻗﺘﻲ ﺑﻪ ‪ cast ،ch‬ﺷﺪ‪ ch ،‬ﺑﻪ اﻳﻦ ﺷﻜﻞ اﺳﺖ‪:‬‬ ‫‪0 0 0 0 0 0 0 0 0 1‬‬

‫ﺑﻌﺪ ‪ ch‬ﺑﻪ ‪ assign ،a‬ﻣﻲﺷﻮد و ‪ a‬ﺑﻪ اﻳﻦ ﺷﻜﻞ در ﻣﻲآﻳﺪ‪:‬‬ ‫‪0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1‬‬

‫‪54‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻛﻪ ﺑﺎﻳﺖ اول آن ﻣﺜﻞ ‪ ch‬اﺳﺖ و ﺑﻘﻴﻪ ﺑﺎﻳﺖﻫﺎ ﺻﻔﺮﻧﺪ‪ .‬ﺗﺒﺪﻳﻞ ﻧﻮﻋﻲ ﻛﻪ در‬ ‫;‪a = ch‬‬

‫اﻧﺠﺎم ﻣﻲﺷﻮد ﻣﺨﻔﻲ )‪ (implicit‬اﺳﺖ‪ .‬ﺗﺒﺪﻳﻞ ﻧﻮع در‬ ‫;‪a = (int) ch‬‬

‫اﮔﺮ ﺑﺨﻮاﻫﻴﻢ آﺷﻜﺎر )‪ (explicit‬اﺳﺖ‪ .‬ﺑﺮاي ﺗﺒﺪﻳﻞ ﻧﻮع آﺷﻜﺎر ﻣﻲﺗﻮاﻧﻴﻢ از ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪static_cast‬‬

‫ﻫﻢ اﺳﺘﻔﺎده ﻛﻨﻴﻢ و ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;)‪a = static_cast<int>(ch‬‬

‫ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ را ﺗﻐﻴﻴﺮ دادهام و ﺗﺒﺪﻳﻞ ﻧﻮعﻫﺎ را ﺑﺎ ‪ explicit ،static_cast‬ﻛﺮدهام‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a = 1025‬‬ ‫;)‪char ch = static_cast<char>(a‬‬ ‫;)‪a = static_cast<int>(ch‬‬ ‫;‪cout<< a‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬

‫ﻗﺒﻼ ﺑﺎ ﺷﻜﻞ ﭘﻴﭽﻴﺪهي ذﺧﻴﺮهي ﻳﻚ ﻋﺪد اﻋﺸﺎري آﺷﻨﺎ ﺷﺪﻳﺪ‪ .‬ﻓﻜﺮ ﻣﻲﻛﻨﻴﺪ اﮔﺮ ﻳﻚ ﻣﺘﻐﻴﺮ ﺑﺎ ﻧﻮع ‪ double‬ﻳﺎ‬ ‫‪ float‬ﺑﻪ ﻳﻚ ‪ int cast‬ﺑﺸﻮد ﻧﺘﻴﺠﻪ ﭼﻴﺴﺖ؟ ﻳﺎ اﮔﺮ ‪ float‬ﺑﻪ ‪ double cast‬ﺑﺸﻮد؟‬ ‫وﻗﺘﻲ ﭘﺎي اﻋﺪاد اﻋﺸﺎري در ﻣﻴﺎن ﺑﺎﺷﺪ ‪ compiler‬ﻧﻈﺎرت ﺑﻴﺶ ﺗﺮي ﺑﺮ ‪ casting‬اﻧﺠﺎم ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪float fl = 1234.5678‬‬ ‫;‪int in = fl‬‬ ‫;‪cout<< in << endl‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1234‬‬

‫‪55‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫اوﻻ ﺗﺒﺪﻳﻞ ﻧﻮع در اﻳﻦ ﺟﺎ ‪) implicit‬ﭘﻨﻬﺎن( اﺳﺖ‪ .‬ﻳﻌﻨﻲ ﻋﺪد اﻋﺸﺎري را ﻣﻲﺷﻮد ﺑﻪ ﺷﻜﻞ ‪ implicit‬ﺑﻪ ﻳﻚ ﻋﺪد‬ ‫ﺻﺤﻴﺢ ‪ cast‬ﻛﺮد‪ .‬ﻧﺘﻴﺠﻪي اﻳﻦ ‪ cast‬ﻛﺮدن ﺣﺬف ﺷﺪن ﻗﺴﻤﺖ اﻋﺸﺎري ﻋﺪد اﺳﺖ‪ .‬در ﻣﺜﺎل ﺑﺎﻻ ﻋﺪد اﻋﺸﺎري‬ ‫‪ 1234.5678‬ﺑﻪ ﻳﻚ ‪ int cast‬ﺷﺪه و ﻧﺘﻴﺠﻪ ‪ 1234‬ﻳﻌﻨﻲ ﻗﺴﻤﺖ ﺻﺤﻴﺢ ‪ 1234.5678‬اﺳﺖ‪ .‬ﻣﻲداﻧﻴﻢ ﻛﻪ‬ ‫‪ float‬و ‪ int‬ﻫﺮ دو ﭼﻬﺎرﺑﺎﻳﺘﻲ ﻫﺴﺘﻨﺪ‪ .‬اﻣﺎ آﻳﺎ در ﻣﺜﺎل ﺑﺎﻻ ﺗﺮﻛﻴﺐ ﺻﻔﺮ و ﻳﻚﻫﺎ در ‪ fl‬و ‪ in‬ﻳﻜﻲ اﺳﺖ؟‬ ‫ﻣﺴﻠﻤﺎ اﻳﻦ ﺟﻮري ﻧﻴﺴﺖ ﭼﻮن ﻧﻈﺎرت ‪ compiler‬ﺑﺎﻋﺚ ﻣﻲﺷﻮد در ‪ casing‬ﺗﺮﻛﻴﺐ ﺻﻔﺮو ﻳﻚﻫﺎ ﻋﻮض ﺑﺸﻮد‪.‬‬ ‫‪ compiler‬ﻫﻢ ﭼﻨﻴﻦ ﻧﻈﺎرﺗﻲ را ﻣﻮﻗﻊ ‪ cast‬ﻛﺮدن *‪ char‬ﺑﻪ ‪ int‬اﻧﺠﺎم ﻧﻤﻲدﻫﺪ‪ .‬در ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﺳﻌﻲ ﻛﺮدهام‬ ‫ﻳﻚ ﺟﻮري ﻧﻈﺎرت ‪ compiler‬ﺑﻪ ‪ casting‬از ‪ float‬ﺑﻪ ‪ int‬را دور ﺑﺰﻧﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪float fl = 1234.5678‬‬ ‫;‪int* s = (int*) &fl‬‬ ‫;‪int in = *s‬‬ ‫;‪cout<< in << endl‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1150964267‬‬

‫اﻳﻦ ﻣﺜﺎل ﻫﻤﺎن ﻣﺜﺎل ﻗﺒﻞ اﺳﺖ ﻓﻘﻂ دﻳﮕﺮ ﻧﻈﺎرﺗﻲ ﺑﺮ ﺗﺒﺪﻳﻞ ﻧﻮع اﻧﺠﺎم ﻧﻤﻲﺷﻮد )ﻳﻌﻨﻲ ﺑﻴﺖﻫﺎ دﺳﺖ ﻧﻤﻲﺧﻮرﻧﺪ(‪ .‬در‬ ‫اﻳﻦ ﺟﺎ ‪ &fl‬ﻛﻪ ﻧﻮع *‪ float‬دارد ﺑﻪ ‪ int* cast‬ﺷﺪه‪ *(&fl) .‬دﻗﻴﻘﺎ )ﻫﻢ از ﻧﻈﺮ ﻣﻜﺎن ﺣﺎﻓﻈﻪ ﻫﻢ ﻣﻘﺪار(‬ ‫ﻫﻤﺎن ‪ fl‬اﺳﺖ‪ *s .‬ﻫﻢ ﻫﻤﺎن ‪ fl‬اﺳﺖ ﺑﺎ ﻣﻘﺪار و ﻣﻜﺎن ﻳﻚ ﺟﻮر اﻣﺎ ‪ *s‬از ﻧﻈﺮ ‪ compiler‬ﻧﻮع ‪ int‬دارد‬ ‫ﺑﺮاي ﻫﻤﻴﻦ ﻣﻮﻗﻊ ﭼﺎپ ﺑﻪ ﻋﻨﻮان ‪ int‬ﭼﺎپ ﻣﻲﺷﻮد‪ .‬ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻣﻘﺪار ﭼﺎپ ﺷﺪه ﺑﺎ ﻣﺜﺎل ﻗﺒﻞ ﻓﺮق دارد‪ .‬اﻳﻦ ﺑﻪ‬ ‫ﺧﺎﻃﺮ ﺣﺬف ﻧﻈﺎرت ‪ compiler‬اﺳﺖ‪.‬‬

‫ﻧﻮع ﺧﺮوﺟﻲ ﻋﻤﻠﮕﺮي ﻣﺜﻞ ﺗﻘﺴﻴﻢ )‪ (/‬ﺑﻪ آرﮔﻮﻣﺎنﻫﺎﻳﺶ ﺑﺴﺘﮕﻲ دارد‪ .‬اﻳﻦ ﻣﺜﺎل را ﺑﺒﻴﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬

‫‪56‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪double r = 3/2‬‬ ‫;‪cout<< r‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬

‫اﻣﺎ ﺷﺎﻳﺪ اﻧﺘﻈﺎر داﺷﺘﻴﺪ ﺑﻪ ﺟﺎي ‪ 1‬ﻋﺪد ‪ 1.5‬ﭼﺎپ ﺷﻮد‪ .‬اﻣﺎ ‪ 1‬ﭼﺎپ ﺷﺪه‪ .‬ﻓﻜﺮ ﻣﻲﻛﻨﻴﺪ ﭼﺮا؟ ‪ compiler‬ﻧﻮع ‪ 3‬و‬ ‫ﻧﻮع ‪ 2‬را ‪ int‬ﻣﻲداﻧﺪ‪ .‬ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﻧﻮع ‪ 3/2‬را ﻫﻢ ‪ int‬ﻣﻲﮔﻴﺮد و ﻗﺴﻤﺖ اﻋﺸﺎري ﻧﺎدﻳﺪه ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد و‬ ‫ﻓﻘﻂ ‪ 1‬ﭼﺎپ ﻣﻲﺷﻮد‪ .‬ﻋﻠﺖ اﻳﻦ اﺳﺖ ﻛﻪ ﻧﻮع ﺧﺮوﺟﻲ ﻋﻤﻠﮕﺮ ﺗﻘﺴﻴﻢ ﻛﺎﻣﻼ ﺑﻪ ﻧﻮع ﻋﺪدﻫﺎﻳﻲ ﻛﻪ ﺑﺮ ﻫﻢ ﺗﻘﺴﻴﻢ ﻣﻲ‪-‬‬ ‫ﺷﻮد ﺑﺴﺘﮕﻲ دارد‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﺧﺮوﺟﻲ ‪ 1.5‬ﺑﺸﻮد ﻣﻲﺗﻮاﻧﻴﻢ ﺑﺮﻧﺎﻣﻪ را ﺑﻪ ﺻﻮرت زﻳﺮ ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪double r =((double)3)/2‬‬ ‫;‪cout<< r‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1.5‬‬

‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﺟﺎي‬ ‫;‪double r =((double)3)/2‬‬

‫ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪double r =(double)3/2‬‬

‫ﻳﺎ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪double r = 3.0/2‬‬

‫ﻳﺎ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪double r = 3/2.0‬‬

‫در ﭘﺎﻳﺎن ﮔﻔﺘﻦ اﻳﻦ ﺿﺮوري اﺳﺖ ﻛﻪ ‪ (double)2‬ﻧﻮع ‪ double‬دارد و ‪ (char*)2‬ﻫﻢ ﻧﻮع *‪char‬‬

‫دارد‪ .‬ﺑﻪ ﺟﺎي ‪ (double)2‬ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ )‪.double(2‬‬

‫‪57‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ‪unsigned‬‬

‫ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ ﺑﺎ ﻧﻮع ‪ int‬ﻣﻲﺗﻮاﻧﺪ ﻣﺜﺒﺖ ﻳﺎ ﻣﻨﻔﻲ ﺑﻪ ﺣﺴﺎب ﺑﻴﺎﻳﺪ اﮔﺮﭼﻪ ﺻﻔﺮ و ﻳﻚ ﺑﻮدن ﺑﻴﺖﻫﺎ ﻣﺜﺒﺖ ﻳﺎ‬ ‫ﻣﻨﻔﻲ ﻧﻤﻲﺷﻨﺎﺳﺪ‪ .‬وﻗﺘﻲ ‪ compiler‬ﻣﻲداﻧﺪ ﻳﻚ ﻣﺘﻐﻴﺮ ‪ 32‬ﺑﻴﺘﻲ ﻧﻮع ‪ int‬دارد ﻣﻮﻗﻊ ﭼﺎپ آن‪ ،‬ﻳﺎ ﻣﻮﻗﻊ اﻧﺠﺎم‬ ‫ﻛﺎرﻫﺎي دﻳﮕﺮ ﻣﺮﺑﻮط ﺑﻪ آن‪ ،‬ﻃﻮري ﺑﺮﺧﻮرد ﻣﻲﻛﻨﺪ ﻛﻪ اﻧﮕﺎر ﻋﺪد ﺻﺤﻴﺤﻲ اﺳﺖ ﻛﻪ ﻣﻲﺗﻮاﻧﺪ ﻣﻨﻔﻲ ﻳﺎ ﻣﺜﺒﺖ ﺑﺎﺷﺪ‪.‬‬ ‫اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ‪ compiler‬ﻫﻤﻮاره آن را ﻋﺪدي ﻣﺜﺒﺖ )در واﻗﻊ ﻧﺎﻣﻨﻔﻲ( ﺑﻪ ﺣﺴﺎب ﺑﻴﺎورد ﺑﺎﻳﺪ آن را ﺑﻪ ﺟﺎي ‪int‬‬

‫ﻳﻚ ‪ unsigned int‬ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪unsigned int a = -1‬‬ ‫‪cout<< a << endl; // 4294967295‬‬ ‫‪cout<< (int) a << endl; // -1‬‬ ‫‪cout<< a + 1; // 0‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪4294967295‬‬ ‫‪-1‬‬ ‫‪0‬‬

‫در اﻳﻦ ﺟﺎ ﻣﺘﻐﻴﺮ ‪ a ِ unsigned‬ﺑﺎ ﻣﻘﺪار اوﻟﻴﻪي ‪ -1‬ﺑﻪ وﺟﻮد آﻣﺪه‪ .‬ﺑﺎ ‪ cout‬ﭼﺎپ ﺷﺪه‪ .‬اﻣﺎ ﭼﻮن ‪،a‬‬ ‫‪ unsigned‬اﺳﺖ‪ ،‬ﺷﻜﻞ ﺑﺪون ﻋﻼﻣﺘﺶ ﻳﻌﻨﻲ ‪ 4294967295‬ﭼﺎپ ﺷﺪه‪ a .‬را ﺑﻪ ‪ cast ،int‬ﻛﺮدهام و آن‬ ‫را ﭼﺎپ ﻛﺮدهام‪ .‬اﻳﻦ ﺑﺎر ﺷﻜﻞ ﻋﻼﻣﺖ دارش ﭼﺎپ ﺷﺪه‪ a+1 .‬ﻣﻘﺪار ﺻﻔﺮ دارد ﭼﻮن ﺷﻜﻞ ﭼﺎپ و ﻋﻼﻣﺖ دار ﻳﺎ‬ ‫ﺑﻲ ﻋﻼﻣﺖ ﺑﻮدن ﺑﺮ ﻋﻤﻠﮕﺮﻫﺎﻳﻲ ﻣﺜﻞ ﺟﻤﻊ ﺗﺄﺛﻴﺮي ﻧﺪارد‪.‬‬ ‫ﺑﻪ ﺟﺎي ‪ unsigned int‬ﻣﻲﺷﻮد ﻧﻮﺷﺖ ‪) unsigned‬ﺣﺘﻲ در ‪ ِ compiler‬ﺳﺨﺖ ﮔﻴﺮي ﻣﺜﻞ ‪Visual‬‬ ‫‪ .(C++ 2005‬ﺑﻪ ﻋﻼوه ﺑﻪ ﺟﺎي ‪ int‬ﻣﻲﺷﻮد ﻧﻮﺷﺖ ‪ signed int‬ﻳﺎ ‪ .signed‬ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻳﻚ‬ ‫‪ warning‬ﻣﻲدﻫﺪ ﻛﻪ ﭼﺮا ‪ signed‬ﺑﺎ ‪ unsigned‬ﻣﻘﺎﻳﺴﻪ ﺷﺪه اﺳﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪signed a = 2‬‬ ‫;‪unsigned b = -1‬‬

‫‪58‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)‪if(a < b‬‬ ‫;"‪cout<< "a warning‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪a warning‬‬

‫ا‪ +‬ا‪ / 01‬را ا* ا ‪ .‬از ‪ compiler‬ﻳﻚ ‪ warning‬درﻳﺎﻓﺖ ﻣﻲﻛﻨﻴﺪ‪.‬‬ ‫‪ unsigned char‬و ‪ unsigned __int64‬ﻫﻢ دارﻳﻢ‪ unsigned char .‬ﺑﺮاي اﻳﻦ ﺑﻪ ﻛﺎر ﻣﻲرود‬ ‫ﻛﻪ ﻛﺪ ‪ ASCII‬ﻳﻚ ﻛﺎراﻛﺘﺮ از ‪ 0‬ﺗﺎ ‪ 255‬ﺣﺴﺎب ﺷﻮد ﻧﻪ از ‪ -127‬ﺗﺎ ‪ .127‬ﺧﻮد ﻛﻠﻤﻪي ‪ unsigned‬ﻳﻌﻨﻲ‬ ‫»ﺑﺪون ﻋﻼﻣﺖ )ﻣﻨﻬﺎ(«‪.‬‬

‫)(‪getch‬‬

‫ﻣﻲداﻧﺴﺘﻴﺪ ﻛﻪ ﻛﺎر )(‪ getch‬ﮔﺮﻓﺘﻦ ﻳﻚ ﻛﺎراﻛﺘﺮ اﺳﺖ؟ ﻣﺜﺎل زﻳﺮ ﻛﺎر )(‪ getch‬را ﻧﺸﺎن ﻣﻲدﻫﺪ‪ .‬ﺑﺎ ﻓﺸﺎر‬ ‫ﻳﻚ ﻛﻠﻴﺪ از ‪ keyboard‬ﻛﺎراﻛﺘﺮ ﻣﺮﺑﻮط ﺑﻪ آن ﻓﻮرا ﭼﺎپ ﻣﻲﺷﻮد‪ .‬ﺑﺎ ﻓﺸﺎر دوﺑﺎرهي ﻳﻚ ﻛﻠﻴﺪ اﺟﺮاي ﺑﺮﻧﺎﻣﻪ‬ ‫ﭘﺎﻳﺎن ﻣﻲﻳﺎﺑﺪ‪.‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪char ch‬‬ ‫;)(‪ch = getch‬‬ ‫;‪cout<< ch‬‬ ‫;)(‪getch‬‬ ‫}‬

‫)‪Output: (Shift + b‬‬ ‫‪B‬‬

‫)(‪ ِ getch‬ﭘﺎﻳﺎﻧﻲ ﻛﻪ در آﺧﺮ اﻳﻦ ﺑﺮﻧﺎﻣﻪ و ﺑﺮﻧﺎﻣﻪﻫﺎي دﻳﮕﺮ ﻧﻮﺷﺘﻪ ﻣﻲﺷﻮد ﺑﻪ ﺧﺎﻃﺮ اﻳﻦ اﺳﺖ ﻛﻪ ﺑﺮﻧﺎﻣﻪ ﻗﺒﻞ از‬ ‫ﭘﺎﻳﺎن اﺟﺮا‪ ،‬ﻣﻨﺘﻈﺮ ﻓﺸﺎر دادن ﻳﻚ ﻛﻠﻴﺪ ﺑﻤﺎﻧﺪ ﺗﺎ آن ﭼﻪ ﭼﺎپ ﺷﺪه ﻓﻮرا از دﻳﺪ ﻛﺎرﺑﺮ ﻣﺤﻮ ﻧﺸﻮد‪.‬‬ ‫ﺑﻪ ﺟﺎي )(‪ getch‬ﻣﻲﺗﻮاﻧﻴﻢ از )(‪ _getch‬ﻫﻢ اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ Visual C++ 2005 .‬ﺣﺘﻲ ﺑﺮاي اﺳﺘﻔﺎده از‬ ‫)(‪ getch‬ﻳﻚ ‪ warning‬ﻣﻲﮔﻴﺮد و ﻣﻲﮔﻮﻳﺪ از )(‪ _getch‬اﺳﺘﻔﺎده ﻛﻨﻴﺪ‪.‬‬

‫‪59‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ‪7‬ار "‪ %‬ه و ' &ه ‬

‫ ا‪ 34‬ا‪ 5 6 ,‬و ‪ .78‬و‪ ;1!/ / <4!6 ...‬ا‪ :8/‬ب =!د ‪ identifier‬ﻣﻲﮔﻮﻳﻨﺪ‪.‬‬ ‫) ‪ identifier‬را»آي دن ﺗﻲ ﻓﺎﻳﺮ« ﻳﺎ ﺗﺨﺼﺼﻲ ﺗﺮ ‪ /aI'dentIfaIər/‬ﺗﻠﻔﻆ ﻛﻨﻴﺪ‬

‫( ‪ .‬ﻧﻤﻲﺧﻮاﻫﻢ ﻫﻤﻪي‬

‫ﻗﻮاﻧﻴﻦ ﺣﺎﻛﻢ ﺑﺮ اﻧﺘﺨﺎب ‪identifier‬ﻫﺎ را ﺑﮕﻮﻳﻢ )ﻗﻮاﻧﻴﻨﻲ ﻣﺜﻞ اﻳﻦ ﻛﻪ ﻧﺒﺎﻳﺪ ﺑﺎ ﻋﺪد ﺷﺮوع ﺷﻮﻧﺪ‪ ،‬ﻧﺒﺎﻳﺪ ﺗﻜﺮاري‬ ‫ﺑﺎﺷﻨﺪ‪ ،‬ﻧﺒﺎﻳﺪ ﻛﻠﻤﻪي ﻛﻠﻴﺪي ﺑﺎﺷﻨﺪ و‪ (...‬ﭼﻮن اﻳﻦ ﻗﻮاﻧﻴﻦ ﺑﻪ ﻣﺤﺾ ﻧﻘﺾ ﺷﺪن ﺑﻪ وﺳﻴﻠﻪي ‪ compiler‬ﺗﺬﻛﺮ داده‬ ‫ﻣﻲﺷﻮﻧﺪ‪ .‬ﺣﺘﻤﺎ در ﻛﺎر ﺑﺎ ‪ compiler‬ﺧﻮد ﻣﺘﻮﺟﻪ ﺷﺪهاﻳﺪ ﻛﻪ ‪ C++‬ﺑﺮﻋﻜﺲ زﺑﺎنﻫﺎﻳﻲ ﻣﺜﻞ ‪case- ،BASIC‬‬ ‫‪ sensitive‬اﺳﺖ ﻳﻌﻨﻲ در ‪C++ identifier‬ﻫﺎي ‪ Id‬و ‪ id‬و ‪ ID‬و ‪ iD‬ﻛﺎﻣﻼ ﻣﺘﻔﺎوت ﻫﺴﺘﻨﺪ و ﻣﺜﻼ ﺑﺮ‬ ‫ﻋﻜﺲ ِ ‪ If ،if‬ﻳﻚ ﻛﻠﻤﻪي ﻛﻠﻴﺪي ﻧﻴﺴﺖ‪.‬‬ ‫‪identifier‬ﻫﺎﻳﻲ ﻛﻪ ﺗﺎ ﺑﻪ ﺣﺎل ﻣﻦ در ﻣﺜﺎلﻫﺎ ﺑﻪ ﻛﺎر ﺑﺮد هام ﻳﻚ ﻳﺎ دو ﺣﺮف ﺑﻴﺶ ﺗﺮ ﻧﺪاﺷﺘﻨﺪ‪ .‬اﻣﺎ ﻳﻚ‬ ‫‪ identifier‬ﻣﻲﺗﻮاﻧﺪ ﺧﻴﻠﻲ ﻃﻮﻻﻧﻲﺗﺮ ﺑﺎﺷﺪ‪ .‬در ﮔﺬﺷﺘﻪ اﺳﻢﻫﺎي اﻧﺘﺨﺎﺑﻲ ﻛﻮﺗﺎه ﺑﻮدﻧﺪ و ﻣﻌﻨﻲ آنﻫﺎ ﺑﺮاي ﻛﺴﻲ ﻛﻪ‬ ‫ﺑﺎر اول آنﻫﺎ را ﻣﻲدﻳﺪ روﺷﻦ ﻧﺒﻮد ﻣﺜﻞ )(‪.getch‬‬ ‫اﺳﻢﻫﺎﻳﻲ ﻛﻪ اﻣﺮوزه ﺑﻪ ﻋﻨﻮان ‪ identifier‬اﻧﺘﺨﺎب ﻣﻲﺷﻮد ﺧﻴﻠﻲ ﻛﺎﻣﻞ ﺗﺮ و اﻏﻠﺐ زﻳﺒﺎ ﺗﺮﻫﺴﺘﻨﺪ ﻣﺜﻞ‬ ‫‪ SetFilePointer‬ﻳﺎ ‪ CreateWindow‬ﻳﺎ ‪.is_file_created‬‬ ‫ﭼﻨﺪ روش ﺑﺮاي اﻧﺘﺨﺎب ‪ identifier‬وﺟﻮد‪ .‬آنﻫﺎ ﺑﻪ ﺗﺮﺗﻴﺐ زﻳﺒﺎﻳﻲ ﻣﺮﺗﺐ ﻛﺮدهام‪:‬‬ ‫‪ (1‬ﺑﺰرگ ﮔﺮﻓﺘﻦ ﺣﺮف اول ﻛﻠﻤﺎت‪ :‬ﻣﺜﻞ ‪ SetFilePointer‬ﻳﺎ ‪ .MinimizeAllWindows‬اﻳﻦ‬ ‫روش ﺑﻴﺶ ﺗﺮ در ﻣﻮرد ﺗﺎﺑ ﻊﻫﺎ ﻳﻪ ﻛﺎر ﻣﻲرود‪.‬‬ ‫‪ (2‬ﻧﻤﺎد ﮔﺬاري ﺷﺘﺮي )‪ :(camel-notation‬در اﻳﻦ روش اوﻟﻴﻦ ﻛﻠﻤﻪ ﺑﺎ ﺣﺮفﻫﺎي ﻛﻮﭼﻚ و ﺣﺮف‬ ‫اول ﺑﻘﻴﻪي ﻛﻠﻤﻪﻫﺎ ﺑﺎ ﺣﺮف ﺑﺰرگ ﻧﻮﺷﺘﻪ ﻣﻲﺷﻮد ﻣﺜﻞ ‪ newString‬ﻳﺎ ‪ myCarClass‬ﻳﺎ‬ ‫‪ .itsLength‬ﻓﻜﺮ ﻣﻲﻛﻨﻴﺪ ﭼﺮا اﺳﻢ اﻳﻦ ﺷﻴﻮه ﻧﻤﺎد ﮔﺬاري را ﺷﺘﺮي ﮔﺬاﺷﺘﻪاﻧﺪ ؟‬ ‫‪ (3‬اﺳﺘﻔﺎده از ‪ :underscore‬اﺳﻢﻫﺎﻳﻲ ﻛﻪ ﺗﻮﺿﻴﺢ ﺑﻴﺶ ﺗﺮ ﻣﻲﺧﻮاﻫﻨﺪ و ﻛﺎرﺑﺮد زﻳﺎدي ﻧﺪارﻧﺪ ﺑﺎ اﻳﻦ روش‬ ‫اﻧﺘﺨﺎب ﻣﻲﺷﻮﻧﺪ‪ .‬در اﻳﻦ روش ﭼﻨﺪ ﻛﻠﻤﻪ ﻛﻪ ﺑﺎ ﺣﺮوف ﻛﻮﭼﻚ ﻧﻮﺷﺘﻪ ﺷﺪهاﻧﺪ ﺑﺎ ‪) underscore‬ﻳﻌﻨﻲ‬ ‫»_«(‬

‫ﺑﻪ‬

‫ﻫﻢ‬

‫وﺻﻞ‬

‫ﻣﻲﺷﻮﻧﺪ‪.‬‬

‫ﻣﺜﻞ‬

‫‪.the_number_of_instances‬‬

‫‪60‬‬

‫‪www.pupuol.com‬‬

‫‪is_the_window_maximized‬‬

‫ﻳﺎ‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ (4‬ﻧﻤﺎدﮔﺬاري ﻣﺠﺎري )ﻣﺠﺎرﺳﺘﺎﻧﻲ(‪ :‬در ا‪ 01‬روش ‪ 3/‬د‪?+‬ار‪ .78 ،,‬ه ‪!/ ,‬ع ‪ int‬ﺑﺎ ‪ i‬ﺷﺮوع ﻣﻲ‪-‬‬ ‫ﺷﻮﻧﺪ‪ ،‬ﻣﺘﻐﻴﺮﻫﺎي ﺑﺎ ﻧﻮع ‪ long‬ﺑﺎ ‪ l‬ﺷﺮوع ﻣﻲﺷﻮﻧﺪ و‪ . ...‬ﻣﺜﻼ‬ ‫;‪int ia‬‬ ‫;‪bool bx‬‬ ‫;‪long lr‬‬

‫اﻳﻦ روش ﺑﺮاي زﺑﺎنﻫﺎي ‪ C‬و ‪ C++‬ﺧﻴﻠﻲ ﺧﻮب ﻧﻴﺴﺖ و ﺑﻬﺘﺮ اﺳﺖ از آن اﺳﺘﻔﺎده ﻧﻜﻨﻴﻢ ﭼﻮن ﻛﺴﻲ‬ ‫ﻛﻪ ﺑﺎ ﺑﺮﻧﺎﻣﻪ ﺷﻤﺎ آﺷﻨﺎﻳﻲ ﻛﻤﻲ دارد ﺑﺎ دﻳﺪن ﭼﻨﺪ ﻣﺘﻐﻴﺮ ﻛﻪ ﻣﺜﻼ ﺑﺎ ‪ i‬ﺷﺮوع ﻣﻲﺷﻮﻧﺪ ﮔﻴﺞ ﻣﻲﺷﻮد‪ .‬در ﻛﻞ‬ ‫اﮔﺮ اول ﻫﻤﻪي اﺳﻢﻫﺎ ﻳﻚ ﺟﻮر ﻧﺒﺎﺷﺪ ﺧﻮاﻧﺪن ﺑﺮﻧﺎﻣﻪ راﺣﺖ ﺗﺮ اﺳﺖ‪.‬‬ ‫ﺷﺎﻳﺪ ﻣﻦ در اﻳﻦ ﻧﻮﺷﺘﻪ ﺧﻴﻠﻲ ﺳﺮاغ اﻳﻦ روشﻫﺎ ﻧﺮوم‪ .‬ﺑﺮﻧﺎﻣﻪﻫﺎي اﻳﻦ ﻧﻮﺷﺘﻪ ﺑﺎ ﻫﺪف آﻣﻮزش زﺑﺎن ‪ C++‬ﻧﻮﺷﺘﻪ‬ ‫ﺷﺪهاﻧﺪ و ﺑﺴﻴﺎر ﻛﻮﺗﺎﻫﻨﺪ و ﺑﺎﻳﺪ ﺑﺴﻴﺎر ﺳﺎده ﺑﺎﺷﻨﺪ ﺗﺎ ﺧﻮاﻧﻨﺪه اﺣﺴﺎس ﭘﻴﭽﻴﺪﮔﻲ ﻧﻜﻨﺪ )ﻳﺎ اﺣﺴﺎس دل ﭘﻴﭽﻪ‪ ،‬ﺳﺮدرد‬ ‫و ﻣﺎﻧﻨﺪ اﻳﻦﻫﺎ‬

‫(‪ .‬وﻟﻲ ﻧﺪاﺷﺘﻦ روش ﻧﺎﻣﮕﺬاري ﺛﺎﺑﺖ در ﺑﺮﻧﺎﻣﻪﻫﺎي ﻃﻮﻻﻧﻲ ﺑﺪون ﺷﻚ ﻣﺴﺎﻟﻪ ﺳﺎز اﺳﺖ‪ .‬اﻟﺒﺘﻪ در‬

‫ﺑﺮﻧﺎﻣﻪﻫﺎي ﻛﻮﺗﺎه ﻳﺎ درون ﺗﺎﺑﻊﻫﺎي ﻛﻮﺗﺎه ﻳﺎ ﻫﺮﺟﺎ ﻛﻪ ﻣﺘﻐﻴﺮ ﻧﻘﺶ ﻛﻮﺗﺎﻫﻲ دارد اﺳﺘﻔﺎده از ﻣﺘﻐﻴﺮﻫﺎي ﺗﻚ ﺣﺮﻓﻲ‬ ‫ﻣﻨﺎﺳﺐ ﺗﺮ اﺳﺖ‪.‬‬ ‫ﻧﻜﺘﻪي آﺧﺮ اﻳﻦ ﻛﻪ ﻣﻌﻤﻮﻻ ‪compiler‬ﻫﺎ‪ ،‬ﻳﻚ ﺣﺪاﻛﺜﺮ ﻃﻮل ﻣﺆﺛﺮ ﺑﺮاي ‪identifier‬ﻫﺎ دارﻧﺪ‪ .‬اﮔﺮ اﺳﻤﻲ ﻛﻪ‬ ‫ﺷﻤﺎ اﻧﺘﺨﺎب ﻣﻲﻛﻨﻴﺪ از آن ﺣﺪاﻛﺜﺮ‪ ،‬ﻃﻮﻻﻧﻲ ﺗﺮ ﺑﺎﺷﺪ ‪ compiler‬ﻃﻮل اﺿﺎﻓﻪ را ﻧﺎدﻳﺪه ﻣﻲﮔﻴﺮد ﻣﺜﻼ اﮔﺮ اﻳﻦ ﻃﻮل‬ ‫ﻣﺆﺛﺮ ‪ 20‬ﺑﺎﺷﺪ ‪ a0123456789012345678x‬و ‪ a0123456789012345678y‬از ﻧﻈﺮ ‪compiler‬‬ ‫ﻳﻜﻲ ﻫﺴﺘﻨﺪ‪ .‬ﻧﮕﺮان ﻧﺒﺎﺷﻴﺪ! در ‪compiler‬ﻫﺎي ﺟﺪﻳﺪ اﻳﻦ ﻃﻮل ﻣﺆﺛﺮ در ﺣﺎﻟﺖ ‪) default‬ﻳﻌﻨﻲ دﺳﺖ ﻧﺨﻮرده(‬ ‫ﺑﻴﺶ از ‪ 200‬اﺳﺖ و در ﺿﻤﻦ ﺷﻤﺎ ﻣﻲﺗﻮاﻧﻴﺪ اﻳﻦ ﻃﻮل را ﺑﻪ دﻟﺨﻮاه ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﺪ‪ .‬ﻓﻜﺮ ﻣﻲﻛﻨﻢ در ‪compiler‬ﻫﺎي‬ ‫ﻗﺪﻳﻤﻲ اﻳﻦ ﻃﻮل ﺑﺎﻳﺪ دﺳﺖ ﻛﻢ ‪ 32‬ﺑﺎﺷﺪ‪.‬‬

‫ "‪ %‬ه ‪8‬‬

‫اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻣﺘﻐﻴﺮﻫﺎﻳﻲ داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﻛﻪ ﻫﻤﻪي ﺗﺎﺑﻊﻫﺎ ﺑﻪ آنﻫﺎ دﺳﺘﺮﺳﻲ دارﻧﺪ‪ ،‬ﻣﻲﺗﻮاﻧﻴﻢ آنﻫﺎ را ﺧﺎرج از ﻫﻤﻪي‬ ‫ﺗﺎﺑﻊﻫﺎ و در ﻓﻀﺎي ﻋﻤﻮﻣﻲ ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‪ .‬اﻳﻦ ﻣﺜﺎل را ﺑﺒﻴﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫;‪int a = 25‬‬

‫‪61‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪int b,v,h,l‬‬

‫;‪v << h << l <<endl‬‬ ‫;‪endl‬‬ ‫;‪endl‬‬ ‫;‪endl‬‬ ‫;‪endl‬‬

‫)(‪void f‬‬ ‫{‬ ‫;‪a++‬‬ ‫;‪b = 2‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫<< ‪cout<< l‬‬ ‫;)(‪f‬‬ ‫<< ‪cout<< a‬‬ ‫<< ‪cout<< b‬‬ ‫;‪a = b = 3‬‬ ‫<< ‪cout<< a‬‬ ‫<< ‪cout<< b‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪0000‬‬ ‫‪26‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪3‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻫﻤﻪي ﺗﺎﺑﻊﻫﺎ ﺑﻪ ﻣﺘﻐﻴﺮﻫﺎي ﻋﻤﻮﻣﻲ دﺳﺘﺮﺳﻲ دارﻧﺪ‪ .‬اول‪ ،‬ﺑﺮﻧﺎﻣﻪ ﻣﺘﻐﻴﺮﻫﺎي ﻋﻤﻮﻣﻲ را ﺑﺎ ﻣﻘﺪارﻫﺎي اوﻟﻴﻪ‬ ‫ﺷﺎن ﺑﻪ وﺟﻮد ﻣﻲآورد‪ .‬ﺑﻌﺪا ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ ﺷﺮوع ﻣﻲﻛﻨﺪ ﺑﻪ اﺟﺮاي دﺳﺘﻮرات درون ﺗﺎﺑﻊ )(‪ main‬و ﻳﻜﻲ‬ ‫ﻳﻜﻲ ﺟﻠﻮ ﻣﻲرود‪ .‬وﻗﺘﻲ ﺑﻪ ;)(‪ f‬رﺳﻴﺪ دﺳﺘﻮرات درون ﺗﺎﺑﻊ ‪ f‬را اﺟﺮا ﻣﻲﻛﻨﺪ ﻛﻪ اﻳﻦ ﺑﺎﻋﺚ ﻣﻲﺷﻮد ﻣﻘﺪارﻫﺎي‬ ‫ﻣﺘﻐﻴﺮﻫﺎي ﻋﻤﻮﻣﻲ ﻋﻮض ﺑﺸﻮﻧﺪ‪ .‬ﺗﺎﺑﻊ ‪ main‬اﻳﻦ ﻣﻘﺪارﻫﺎ را ﭼﺎپ ﻣﻲﻛﻨﺪ‪ .‬در ‪ main‬ﺑﺎ دﺳﺘﻮر ;‪ ،a=b=3‬ﻣﻘﺪار‬ ‫ﻣﺘﻐﻴﺮﻫﺎي ‪ a‬و ‪ b‬ﻫﻤﺰﻣﺎن ﺑﻪ ‪ 3‬ﺗﺒﺪﻳﻞ ﻣﻲﺷﻮﻧﺪ و ‪ a‬و ‪ b‬دوﺑﺎره ﭼﺎپ ﻣﻲﺷﻮﻧﺪ‪ .‬ﻣﻲﺗﻮاﻧﻴﺪ;‪ a=b=3‬را ‪ .*!6‬‬ ‫ ‪ .‬؟ ﺑﻪ ﻋﻨﻮان راﻫﻨﻤﺎﻳﻲ ﻣﻲﮔﻮﻳﻢ ﻛﻪ ﻋﻤﻠﮕﺮ = درﺳﺖ ﻣﺜﻞ ﻳﻚ ﺗﺎﺑﻊ ﺧﺮوﺟﻲ دارد‪ .‬ﺧﺮوﺟﻲ ‪ b=3‬ﻫﻢ ‪ 3‬اﺳﺖ‪.‬‬ ‫راﻫﻨﻤﺎﻳﻲ دوم اﻳﻦ ﻛﻪ ‪ b=3‬اول اﺟﺮا ﻣﻲﺷﻮد‪.‬‬

‫ ه ‪ ++‬و ‪--‬‬

‫ﻗﺒﻼ ﮔﻔﺘﻢ ﻛﻪ ‪ a++‬ﻳﻚ واﺣﺪ ﺑﻪ ‪ a‬اﺿﺎﻓﻪ ﻣﻲﻛﻨﺪ‪ ++a .‬ﻫﻢ دارﻳﻢ ﻛﻪ ﻣﺜﻞ ‪ a++‬ﻳﻜﻲ ﺑﻪ ‪ a‬اﺿﺎﻓﻪ ﻣﻲﻛﻨﺪ‪.‬‬ ‫ﻋﻤﻠﮕﺮ ‪ ++‬وﻗﺘﻲ ﻗﺒﻞ از ﻣﺘﻐﻴﺮ ﺑﻪ ﻛﺎر ﺑﺮود‪ prefix ،‬و وﻗﺘﻲ ﺑﻌﺪ از ﻣﺘﻐﻴﺮ ﺑﻪ ﻛﺎر ﻣﻲرود ‪ postfix‬ﻧﺎﻣﻴﺪه ﻣﻲﺷﻮد‪.‬‬

‫‪62‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫وﻗﺘﻲ ‪ ++‬ﺑﺮاي ‪ char ،int‬و‪ ...‬ﺑﻪ ﻛﺎر ﻣﻲرود ﺑﻴﻦ ‪ postfix‬و ‪ prefix‬ﻓﺮﻗﻲ ﻫﺴﺖ‪ .‬اﮔﺮ ‪ a‬ﺑﺎ ﻧﻮع ‪ int‬ﺑﺎﺷﺪ‪،‬‬ ‫ﻣﻘﺪار ‪ ++a‬ﺑﺮاﺑﺮ ﺑﺎ ‪ a+1‬اﺳﺖ وﻟﻲ ﻣﻘﺪار ‪ a++‬ﺑﺮاﺑﺮ ‪ a‬اﺳﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪int‬‬ ‫;‪a = 2‬‬ ‫;‪double b = 2‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪3‬‬ ‫‪3‬‬

‫‪output:‬‬ ‫‪output:‬‬ ‫‪output:‬‬ ‫‪output:‬‬

‫‪//‬‬ ‫‪//‬‬ ‫‪//‬‬ ‫‪//‬‬

‫;‪endl‬‬ ‫;‪endl‬‬ ‫;‪endl‬‬ ‫;‪endl‬‬

‫<<‬ ‫<<‬ ‫<<‬ ‫<<‬

‫‪cout<< a++‬‬ ‫‪cout<< ++b‬‬ ‫‪cout<< a‬‬ ‫‪cout<< b‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪3‬‬ ‫‪3‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ‪ a++‬ﻳﻜﻲ ﺑﻪ ‪ a‬و ‪ ++b‬ﻳﻜﻲ ﺑﻪ ‪ b‬اﺿﺎﻓﻪ ﻛﺮده‪ .‬اﻣﺎ ‪ a++‬ﻣﻘﺪار ‪ 2‬و ‪ ++b‬ﻣﻘﺪار ‪ 3‬دارد‪ .‬ﺑﺮاي اﻳﻦ‬ ‫ﻛﻪ ﺑﻬﺘﺮ ﺑﺎ ﺗﻔﺎوت ﻋﻤﻠﻜﺮد ‪ ++‬ﺑﻪ ﻋﻨﻮان ‪ postfix‬و ‪ prefix‬آﺷﻨﺎ ﺑﺸﻮﻳﺪ دو ﺗﺎﺑﻊ زﻳﺮ را در ﻧﻈﺮ ﺑﮕﻴﺮﻳﺪ‪:‬‬ ‫)‪int preplus(int& a‬‬ ‫{‬ ‫;‪a = a + 1‬‬ ‫;‪return a‬‬ ‫}‬ ‫)‪int postplus(int& a‬‬ ‫{‬ ‫;‪a = a + 1‬‬ ‫;‪return a - 1‬‬ ‫}‬

‫ﺣﺎﻻ ﺑﻪ ﺟﺎي ‪ a++‬ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ )‪ postplus(a‬و ﺑﻪ ﺟﺎي ‪ ++a‬ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ )‪ preplus(a‬و‬ ‫اﻳﻦﻫﺎ ﺑﺎﻫﻢ ﻓﺮﻗﻲ ﻧﺪارﻧﺪ‪.‬‬ ‫ﻣﺸﺎﺑﻪ ﻫﻤﻪي ﭼﻴﺰﻫﺎﻳﻲ ﻛﻪ ﺑﺮاي ‪ ++‬ﮔﻔﺘﻢ ﺑﺮاي ‪ --‬ﻫﻢ درﺳﺘﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬

‫‪63‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <iostream> using namespace std; int main() { int a = 2; int b = 2; cout<< a-cout<< --b cout<< a cout<< b _getch();

<< << << <<

endl; endl; endl; endl;

// // // //

output: output: output: output:

2 1 1 1

}

Output: 2 1 1 1

8 ; <' = #‫ و‬8 ‫ عه‬

‫ ﺧﻮد ﻣﺎ ﻫﻢ ﻣﻲﺗﻮاﻧﻴﻢ ﻧﻮعﻫﺎي ﺟﺪﻳﺪي ﺗﻌﺮﻳﻒ‬...‫ و‬bool ،int ‫ وﺟﻮد دارد ﻣﺜﻞ‬C++ ‫ﻋﻼوه ﺑﺮ ﻧﻮعﻫﺎﻳﻲ ﻛﻪ در‬ :‫ اﺳﺖ ﻣﻲﻧﻮﻳﺴﻴﻢ‬int ‫ ﺑﺮاي ﺗﻌﺮﻳﻒ ﻳﻚ ﻧﻮع ﺟﺪﻳﺪ ﻛﻪ ﺷﺎﻣﻞ دو‬.‫ﻛﻨﻴﻢ‬ struct Point { int x; int y; };

:‫ ﺑﺮﻧﺎﻣﻪي زﻳﺮ روش اﺳﺘﻔﺎده از اﻳﻦ ﻧﻮع را ﻧﺸﺎن ﻣﻲدﻫﺪ‬.‫ دارﻳﻢ‬Point ‫ﺣﺎﻻ ﻣﺎ ﻧﻮع ﺟﺪﻳﺪي ﺑﺎ ﻧﺎم‬ #include <conio.h> #include <iostream> using namespace std; struct Point { int x; int y; }; int main() { Point p = {10, 20};

64

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪cout<< p.x << endl‬‬ ‫;‪cout<< p.y << endl‬‬ ‫;‪p.x = 100‬‬ ‫;‪p.y = 200‬‬ ‫;‪cout<< p.x << endl‬‬ ‫;‪cout<< p.y‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪10‬‬ ‫‪20‬‬ ‫‪100‬‬ ‫‪200‬‬

‫ﻣﺘﻐﻴﺮي ﺑﺎ ﻧﻮع ‪ Point‬ﺗﻌﺮﻳﻒ ﻛﺮدهام و ﺑﻪ ﻣﺆﻟﻔﻪﻫﺎي آن )ﻳﻌﻨﻲ ‪ x‬و ‪ (y‬ﻣﻘﺪار اوﻟﻴﻪ دادهام‪ .‬اﻳﻦ ﻣﻘﺪارﻫﺎي اوﻟﻴﻪ‬ ‫را ﭼﺎپ ﻛﺮدهام‪ .‬ﻣﻘﺪار ﻣﺆﻟﻔﻪﻫﺎ را ﻋـﻮض ﻛﺮدهام و دوﺑﺎره آنﻫﺎ را ﭼﺎپ ﻛﺮدهام‪.‬‬ ‫ﺷﺎﻳﺪ ﺑﺮاﻳﺘﺎن ﺟﺎﻟﺐ ﺑﺎﺷﺪ ﻛﻪ ﺑﺪاﻧﻴﺪ ﺧﻂ‬ ‫;}‪Point p = {10, 20‬‬

‫در زﺑﺎن ‪ error ،C‬دارد و ﺑﻪ ﺟﺎي آن ﺑﺎﻳﺪ ﻧﻮﺷﺖ‪:‬‬ ‫;}‪struct Point p = {10, 20‬‬

‫اﻳﻦ ﺷﻜﻞ دوم در ‪ C++‬ﻫﻢ ﻗﺎﺑﻞ اﺳﺘﻔﺎده اﺳﺖ‪.‬‬ ‫در ‪ C++‬ﻧﻮعﻫﺎﻳﻲ ﻛﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﺗﻌﺮﻳﻒ ﻣﻲﻛﻨﺪ ﻣﻲﺗﻮاﻧﺪ ﺷﺎﻣﻞ ﺗﺎﺑﻊ ﻫﻢ ﺑﺎﺷﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪struct Point‬‬ ‫{‬ ‫;‪int x‬‬ ‫;‪int y‬‬ ‫دادن او[‪VWX YZ‬ار ‪void SetInitialValue(int a, int b)//‬‬ ‫{‬ ‫;‪x = a‬‬ ‫;‪y = b‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;}‪Point p = {10, 20‬‬ ‫;‪cout<< p.x << endl‬‬ ‫;‪cout<< p.y << endl‬‬ ‫;)‪p.SetInitialValue(100,200‬‬ ‫;‪cout<< p.x << endl‬‬ ‫;‪cout<< p.y‬‬ ‫;)(‪getch‬‬

‫‪65‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫}‬

‫‪Output:‬‬ ‫‪10‬‬ ‫‪20‬‬ ‫‪100‬‬ ‫‪200‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻳﻚ ‪ comment‬ﻓﺎرﺳﻲ در ﺑﺮﻧﺎﻣﻪ ﻫﺴﺖ‪ .‬در ﺟﺎﻳﻲ ﻛﻪ اﻳﻦ ‪ comment‬ﻗﺮار دارد ﺗﺎﺑﻊ‬ ‫‪ SetInitialValue‬ﺗﻌﺮﻳﻒ ﺷﺪه ﻛﻪ ﻛﺎر آن دادن ﻣﻘﺪار ﺑﻪ ‪ x‬و ‪ y‬اﺳﺖ‪ .‬ﺑﺎ اﺳﺘﻔﺎده از اﻳﻦ ﺗﺎﺑﻊ در ‪main‬‬

‫ﻣﻘﺪار ‪ p.x‬و ‪ p.y‬را ﻋﻮض ﻛﺮدهام‪ .‬ﺑﻪ ﻧﺤﻮهي ﺑﻪ ﻛﺎرﮔﻴﺮي ﺗﺎﺑﻊ ﻳﺎد ﺷﺪه ﺧﻮب دﻗﺖ ﻛﻨﻴﺪ‪.‬‬

‫ز ‪ 8 ,‬و > ا ‪ 8‬‬

‫ﮔﻔﺘﻢ ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ ﺑﺎﻳﺪ زﻳﺒﺎ و ﺧﻮب ﻧﻮﺷﺘﻪ ﺷﻮد‪ .‬ﺷﺎﻳﺪ اﺻﺮار ﻣﻦ ﺑﻪ زﻳﺒﺎ ﻧﻮﺷﺘﻦ و ﺧﻮب ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ ﺑﺮاﻳﺘﺎن ﻏﻴﺮ‬ ‫ﻋﺎدي ﺑﺎﺷﺪ‪ .‬اوﻻ ﺑﮕﻮﻳﻢ ﻣﻨﻈﻮر از ﺑﺮﻧﺎﻣﻪ دو ﭼﻴﺰ اﺳﺖ‪:‬‬ ‫‪ (1‬ﻓﺎﻳﻞ ‪ .exe‬اﺳﺖ ﻛﻪ از ‪ compile‬ﺷﺪن ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ ﺑﻪ وﺟﻮد ﻣﻲآﻳﺪ‪.‬‬ ‫‪ (2‬ﻣﺘﻦ ﺑﺮﻧﺎﻣﻪ ﻛﻪ ﻫﻤﺎن ﺧﻄﻮط و دﺳﺘﻮرات ﺑﺮﻧﺎﻣﻪ اﺳﺖ و ‪ source code‬ﻧﺎم دارد‪.‬‬ ‫ﻓﺎﻳﻞ ‪ .exe‬در ﻧﻬﺎﻳﺖ در دﺳﺖ ﻛﺴﺎﻧﻲ اﺳﺖ ﻛﻪ از ﺷﻤﺎ و از ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ و از ﺧﻴﻠﻲ ﭼﻴﺰﻫﺎي دﻳﮕﺮ ﺑﻲ اﻃﻼع‬ ‫ﻫﺴﺘﻨﺪ‪ .‬وﻗﺘﻲ آنﻫﺎ ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ را ﻣﻲﺑﻴﻨﻨﺪ )ﺑﺮاي ﺧﺮﻳﺪ‪ ،‬اﺳﺘﻔﺎده و‪ (...‬اوﻟﻴﻦ ﭼﻴﺰي ﻛﻪ آنﻫﺎ را ﺑﻪ ﺧﻮدش ﺟﺬ ب‬ ‫ﻣﻲﻛﻨﺪ زﻳﺒﺎﻳﻲ ﻇﺎﻫﺮي ﺑﺮﻧﺎﻣﻪ ﺷﻤﺎﺳﺖ‪ .‬زﻳﺒﺎﻳﻲ ﻇﺎﻫﺮي ﺑﺎ زﻳﺒﺎﻳﻲ ﻣﺘﻦ ﺑﺮﻧﺎﻣﻪ و ﻣﺮﺗﺐ ﻧﻮﺷﺘﻦ ‪ source code‬ﻓﺮق‬ ‫ﻣﻲﻛﻨﺪ وﻟﻲ ﺑﻲ ارﺗﺒﺎط ﺑﺎ آن ﻧﻴﺴﺖ‪ .‬دوﻣﻴﻦ ﭼﻴﺰي ﻛﻪ ﻛﺎرﺑﺮان ِ ﺑﺮﻧﺎﻣﻪ‪ ،‬ﺑﻪ آن ﺗﻮﺟﻪ دارﻧﺪ ﻛﺎراﻳﻲ ﺑﻲ ﻧﻘﺺ و‬ ‫راﺣﺖ آن اﺳﺖ و اﻳﻦ ﺑﺎﻋـﺚ ﻣﻲﺷﻮد آنﻫﺎ از ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ ﺧﺴﺘﻪ ﻧﺸﻮﻧﺪ‪.‬‬ ‫ﺑﺮاي اﻳﻦ ﻛﻪ ﺑﻪ اﻳﻦ دو ﻫﺪف )ﻳﻌﻨﻲ زﻳﺒﺎﻳﻲ ﻇﺎﻫﺮي و ﻛﺎراﻳﻲ ﺑﻲ ﻧﻘﺺ( ﺑﺮﺳﻴﺪ ﺑﺎﻳﺪ ﺑﻪ زﻳﺒﺎﻳﻲ ﻣﺘﻦ ﺑﺮﻧﺎﻣﻪ ﻳﻌﻨﻲ‬ ‫ﻣﺮﺗﺐ ﻧﻮﺷﺘﻦ ‪ source code‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪ .‬وﻗﺘﻲ ‪ source code‬را ﻣﺮﺗﺐ و زﻳﺒﺎ ﻣﻲﻧﻮﻳﺴﻴﺪ ﺑﻪ ﻃﻮر ﻗﺎﺑﻞ ﻣﻼﺣﻈﻪ‪-‬‬ ‫اي اﺣﺘﻤﺎل ﺧﻄﺎ و ﻧﻘﺺ را ﻛﻢ ﻣﻲﻛﻨﻴﺪ ﭼﻮن در اﻳﻦ ﺣﺎﻟﺖ ﺑﻬﺘﺮ ﺑﻪ ﺳﺎﺧﺘﺎر ﺑﺮﻧﺎﻣﻪ ﺗﺴﻠﻂ دارﻳﺪ‪ .‬از ﻃﺮف دﻳﮕﺮ‬ ‫زﻳﺒﺎﻳﻲ ﺑﺮﻧﺎﻣﻪ ﺑﺎﻋـﺚ ﻣﻲﺷﻮد ﻛﻪ ﺑﺮﻧﺎﻣﻪ را ﺧﻴﻠﻲ ﺑﻴﺶ ﺗﺮ دوﺳﺖ داﺷﺘﻪ ﺑﺎﺷﻴﺪ‪ .‬اﮔﺮ ﺧﻮد ﺷﻤﺎ ﺑﺮﻧﺎﻣﻪي ﺧﻮدﺗﺎن را‬ ‫دوﺳﺖ ﻧﺪاﺷﺘﻪ ﺑﺎﺷﻴﺪ ﭼﮕﻮﻧﻪ از دﻳﮕﺮان اﻧﺘﻈﺎر ﺧﻮاﻫﻴﺪ داﺷﺖ ﻛﻪ ﺑﻪ آن ﻋﻼﻗﻪ ﭘﻴﺪا ﻛﻨﻨﺪ؟‬

‫‪66‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺷﺎﻳﺪ اﺣﺴﺎس ﻣﻲﻛﻨﻴﺪ زﻳﺒﺎ ﻧﻮﺷﺘﻦ در دوﺳﺖ داﺷﺘﻦ ﺷﻤﺎ ﻧﻘﺸﻲ ﻧﺪارد‪ .‬ﺑﺎﻳﺪ ﺑﮕﻮﻳﻢ ﺑﻪ اﺣﺘﻤﺎل زﻳﺎد اﺷﺘﺒﺎه ﻣﻲﻛﻨﻴﺪ‪.‬‬ ‫آﻳﺎ ﺗﺎ ﺑﻪ ﺣﺎل ﻧﺸﺪه ﻛﻪ ﭼﻨﺪ ﺗﺎ از رﻓﻘﺎي ﺷﻤﺎ ﺑﻪ ﻫﻤﺮاه ﻛﻮدﻛﺎﻧﺸﺎن ﺑﻪ ﺧﺎﻧﻪي ﺷﻤﺎ ﺑﻴﺎﻳﻨﺪ؟ آﻳﺎ ﺷﻤﺎ ﺑﻪ ﻛﻮدﻛﺎن‬ ‫ﺷﻴﺮﻳﻦ و زﻳﺒﺎ ﺑﻴﺶ ﺗﺮ از ﻛﻮدﻛﺎن ﮔﻮﺷﻪ ﮔﻴﺮ و ﻧﺎﻣﺮﺗﺐ ﺗﻮﺟﻪ ﻧﻜﺮدهاﻳﺪ؟ اﮔﺮ ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ زﻳﺒﺎ ﺑﺎﺷﺪ ﺑﻪ ﻃﻮر‬ ‫ﻧﺎﺧﻮدآﮔﺎه ﺑﻪ آن ﺑﻴﺶ ﺗﺮ ﺗﻮﺟﻪ ﺧﻮاﻫﻴﺪ ﻛﺮد و ﻧﺘﻴﺠﻪي اﻳﻦ ﺗﻮﺟﻪ ﺷﻤﺎ ﺑﺮﻧﺎﻣﻪاي ﺧﻮب و ﭘﺮﻃﺮﻓﺪار اﺳﺖ‪ .‬ﭘﺲ ﻣﺎ‬ ‫ﺑﺎﻳﺪ ﺑﻪ ﺧﻮب‪ ،‬ﻛﺎﻣﻞ و زﻳﺒﺎ ﻧﻮﺷﺘﻦ ‪ source code‬ﺗﻮﺟﻪ زﻳﺎدي داﺷﺘﻪ ﺑﺎﺷﻴﻢ‪ .‬اﻳﻦ ﺑﻪ ﻣﺎ ﻛﻤﻚ ﻣﻲﻛﻨﺪ ﻛﻪ از‬ ‫ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﻟﺬت ﺑﺒﺮﻳﻢ ﻫﻤﺎن ﻃﻮر ﻛﻪ ﻳﻚ ﻧﻘﺎش ﺗﺎﺑﻠﻮﻫﺎي ﺧﻮد را دوﺳﺖ دارد و از ﻧﻘﺎﺷﻲ ﻟﺬت ﻣﻲﺑﺮد‪.‬‬ ‫ﺣﺎﻻ ﺑﮕﺬارﻳﺪ ﭼﻨﺪ ﻧﻜﺘﻪ در ﻣﻮرد ﺧﻮب ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ ﺑﮕﻮﻳﻢ‪:‬‬ ‫‪ (1‬ﻫﺮﮔﺎه ﭘﺮاﻧﺘﺰ‪) brace ،‬ﻳﻌﻨﻲ آﻛﻼد( و‪ ...‬را ﺑﺎز ﻛﺮدﻳﺪ اول آن را ﺑﺒﻨﺪﻳﺪ ﺑﻌﺪ ﺑﻴﻦ آنﻫﺎ ﭼﻴﺰي را ﻛﻪ ﻣﻲ‪-‬‬ ‫ﺧﻮاﻫﻴﺪ ﺑﻨﻮﻳﺴﻴﺪ‪ .‬ﺑﻪ ﻣﺮاﺣﻞ ﻧﻮﺷﺘﻦ زﻳﺮ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‬ ‫|‪if‬‬ ‫|(‪if‬‬ ‫|)(‪if‬‬ ‫)|(‪if‬‬ ‫)|‪if(a‬‬ ‫)|> ‪if(a‬‬ ‫)|‪if(a > 2‬‬ ‫)‪if(a > 2‬‬

‫)‪1‬‬ ‫)‪2‬‬ ‫)‪3‬‬ ‫)‪4‬‬ ‫)‪5‬‬ ‫)‪6‬‬ ‫)‪7‬‬ ‫)‪8‬‬

‫‪brace (2‬ﻫﺎ ﺑﺎﻳﺪ ﻛﺎﻣﻼ در ﻳﻚ ﺳﺘﻮن ﻗﺮار ﺑﮕﻴﺮﻧﺪ و آن ﭼﻪ ﺑﻴﻦ آنﻫﺎﺳﺖ ﺑﺎﻳﺪ ﺑﻪ اﻧﺪازهي ﻳﻚ ‪ tab‬ﺟﻠﻮ‬ ‫ﺗﺮ ﺑﺎﺷﺪ‪ .‬ﻣﺜﻞ‬ ‫)‪void f(int b‬‬ ‫{‬ ‫;‪int a = 2‬‬ ‫;‪cout<< a + b‬‬ ‫}‬

‫در ﻣﺤﻴﻂ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﻳﻚ ‪ tab‬ﺑﻪ ﻃﻮر ‪ default‬ﺑﻪ اﻧﺪازهي ﭼﻬﺎر ‪ =) space‬ﻓﻀﺎي ﺧﺎﻟﻲ( اﺳﺖ‪.‬‬ ‫‪compiler‬ﻫﺎ ﻣﻌﻤﻮﻻ اﺟﺎزهي ﺗﻐﻴﻴﺮ ﻃﻮل ‪ tab‬را ﺑﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻣﻲدﻫﻨﺪ‪.‬‬ ‫‪ (3‬ﺧﻂ ﺑﻌﺪي ﺑﺮاي دﺳﺘﻮراﺗﻲ ﻣﺜﻞ ‪ if‬ﺑﺎﻳﺪ ﺑﻪ اﻧﺪازهي ﻳﻚ ‪ tab‬ﺟﻠﻮﺗﺮ ﺷﺮوع ﺑﺸﻮد ﻣﺜﻞ‬ ‫)‪if(a > 2‬‬ ‫;‪a = 2‬‬

‫‪ (4‬ﮔﺎﻫﻲ ﺑﺮاي زﻳﺒﺎﻳﻲ ﻣﻲﺗﻮاﻧﻴﻢ ﻃﺮحﻫﺎي ﺧﻼﻗﺎﻧﻪاي ﺑﻪ ﻛﺎر ﺑﺒﺮﻳﻢ ﻣﺜﻞ‬ ‫;‪= 2‬‬

‫‪67‬‬

‫‪www.pupuol.com‬‬

‫‪limo‬‬

‫‪int‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪= 4‬‬ ‫;‪= 8‬‬

‫‪limousine‬‬ ‫‪RedLimousine‬‬

‫‪char‬‬ ‫‪double‬‬

‫‪ (5‬در دو ﻃﺮف ﻋﻤﻠﮕﺮﻫﺎﻳﻲ ﻣﺜﻞ =‪ + ،‬و‪ ...‬ﻳﻚ ‪ space‬ﻗﺮار دﻫﻴﺪ و آنﻫﺎ را ﻧﭽﺴﺒﺎﻧﻴﺪ‪:‬‬ ‫;‪int c = a + b‬‬

‫در ﭘﺎﻳﺎن ﻣﻲﮔﻮﻳﻢ ﻛﻪ در ﻣﻮاردي ﺑﻴﻦ ﻧﺤﻮهي ﻧﻮﺷﺘﻦ ﻳﻚ ﭼﻴﺰ ﺑﻴﻦ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲﻫﺎ اﺧﺘﻼف وﺟﻮد دارد ﻣﺜﻼ در‬ ‫ﻣﻮرد ﻧﻜﺘﻪ )‪ (2‬در ﺑﺎﻻ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﺑﺒﻴﻨﻴﺪ ﭼﻪ ﻗﺪر اﻳﻦ ﭼﻴﺰﻫﺎ ﺑﺮاي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲﻫﺎي ﺣﺮﻓﻪاي ﻣﻬﻢ اﺳﺖ ﺑﻪ‬ ‫ﻳﻜﻲ از ﺳﺎﻳﺖﻫﺎي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﺷﻠﻮغ در ‪ internet‬ﺳﺮي ﺑﺰﻧﻴﺪ و در ﻣﻮرد ﻧﻜﺘﻪي )‪ (2‬از آنﻫﺎ ﻧﻈﺮ‬ ‫ﺑﺨﻮاﻫﻴﺪ و ﻣﻨﺘﻈﺮ ﺑﻤﺎﻧﻴﺪ و ﺑﺒﻨﻴﺪ ﻛﻪ ﭼﮕﻮﻧﻪ دهﻫﺎ ﭘﻴﺎم از ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲﻫﺎي ﻣﺨﺘﻠﻒ داده ﻣﻲﺷﻮد ﻛﻪ ﻫﻤﻪ ﺑﺎ ﻫﻢ‬ ‫ﻣﺘﻨﺎﻗﻀﻨﺪ‪.‬‬ ‫در اﻳﻦ ﻓﺼﻞ ﺳﻌﻲ ﻛﺮدم ﺗﻘﺮﻳﺒﺎ ﺗﻤﺎم ﻣﻄﺎﻟﺐ ﻣﻬﻢ در ‪ C++‬را ﻣﺮور ﻛﻨﻢ‪ .‬اﻻن ﺷﻤﺎ در ﺳﻄﺢ ﻣﻨﺎﺳﺒﻲ ﺑﺮاي‬ ‫درك ﺟﺰﺋﻴﺎت ﺑﻴﺶ ﺗﺮ ﻗﺮار دارﻳﺪ‪ .‬در ﻓﺼﻞﻫﺎي آﻳﻨﺪه ﺑﻌﻀﻲ از ﻣﻄﺎﻟﺐ اﻳﻦ ﻓﺼﻞ ﺗﻜﺮار ﻣﻲﺷﻮﻧﺪ‪ .‬ﭘﺲ از ﻳﻜﻲ‬ ‫دو روز اﺳﺘﺮاﺣﺖ دوﺑﺎره ﺑﺎ ﻣﻦ ﻫﻤﺮاه ﺑﺸﻮﻳﺪ‬

‫‪.‬‬

‫@? ' ‬

‫‪ (1‬ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﺪ دو ﻋﺪد ﺻﺤﻴﺢ را از ﻛﺎرﺑﺮ ﺑﮕﻴﺮد و ﻣﻴﺎﻧﮕﻴﻦ آنﻫﺎ را ﭼﺎپ ﻛﻨﺪ‪.‬‬ ‫‪ (2‬ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ رﺷﺘﻪاي ﺑﻪ ﻃﻮل ‪ 10‬ﻛﺎراﻛﺘﺮ را درﻳﺎﻓﺖ ﻛﻨﺪ و ﻃﻮل رﺷﺘﻪ را ﻧﺼﻒ ﻛﻨﺪ و آن را‬ ‫ﭼﺎپ ﻛﻨﺪ‪.‬‬ ‫)راﻫﻨﻤﺎﻳﻲ‪ :‬ﻛﺎراﻛﺘﺮ ‪ null‬را در ﻣﻜﺎن ﻣﻨﺎﺳﺒﻲ از رﺷﺘﻪ ﺑﮕﺬارﻳﺪ(‬ ‫‪ (3‬ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ‪ 10‬ﺗﺎ ﻋﺪد ﺻﺤﻴﺢ را از ﻛﺎرﺑﺮ ﺑﮕﻴﺮد و در ﻳﻚ آراﻳﻪ ﻗﺮار ﺑﺪﻫﺪ‪.‬‬ ‫‪ (4‬ﺗﺎﺑﻌﻲ ﺑﺎ اﻳﻦ ‪prototype‬‬ ‫;)‪bool f(bool prop1,bool prop2‬‬

‫ﺑﻨﻮﻳﺴﺪ ﻛﻪ وﻗﺘﻲ ﻫﺮ دوي ‪ prop1‬و ‪ prop2‬ﻣﻘﺪار ‪ true‬داﺷﺘﻪ ﺑﺎﺷﻨﺪ ‪ true‬ﺑﺮﮔﺮداﻧﺪ وﮔﺮﻧﻪ‬ ‫‪ false‬ﺑﺮﮔﺮداﻧﺪ‪.‬‬

‫‪68‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ‪ A# ' B‬‬

‫‪ (1‬ﻣﻲداﻧﻴﺪ ﻛﻪ ‪ 64 __int64‬ﺑﻴﺖ دارد و ‪ 32 int‬ﺑﻴﺖ دارد‪ .‬ﭘﺲ ﻣﻲﺷﻮد ﻫﺮ ﻋﺪد ﺻﺤﻴﺢ ﺑﺎ ﻧﻮع‬ ‫‪ __int64‬را ﺑﺎ دو ﻋﺪد ﺻﺤﻴﺢ ﺑﺎ ﻧﻮع ‪ int‬ﻣﺸﺨﺺ ﻛﺮد‪ .‬ﭼﻮن ‪ long‬ﻫﻢ ‪ 32‬ﺑﻴﺖ دارد‪ ،‬ﻫﺮ ﻋﺪد‬ ‫ﺻﺤﻴﺢ ﺑﺎ ﻧﻮع ‪) long long‬ﻛﻪ ﻫﻤﺎن ‪ __int64‬اﺳﺖ( را ﻫﻢ ﻣﻲﺷﻮد ﺑﺎ دو ﺗﺎ ‪ long‬ﺳﺎﺧﺖ‪.‬‬ ‫اﻟﻒ( ﺗﺎﺑﻌﻲ ﺑﺎ اﻳﻦ ‪:prototype‬‬ ‫;)‪void separate(long long n, long& part1, long& part2‬‬

‫ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ‪ n‬را ﻣﻲﮔﻴﺮد و ﺑﻪ ‪ part1‬و ‪ part2‬ﻣﻲﺷﻜﻨﺪ‪.‬‬ ‫)راﻫﻨﻤﺎﻳﻲ‪ :‬ﺑﻬﺘﺮ اﺳﺖ در ﺗﻌﺮﻳﻒ ﺗﺎﺑﻊ ﻫﻤﻪي اﻋﺪاد را ﺑﺎ ﺑﻪ ﻛﺎر ﺑﺮدن ‪ unsigned‬ﺑﻲ ﻋﻼﻣﺖ ﻛﻨﻴﺪ‪(.‬‬ ‫ب( ﺗﺎﺑﻌﻲ ﺑﺎ اﻳﻦ ‪:prototype‬‬ ‫;)‪long long integrate(long& part1, long& part2‬‬

‫ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻛﺎﻣﻼ ﺑﺮ ﻋﻜﺲ ﺗﺎﺑﻊ ﻗﺒﻠﻲ ﻋﻤﻞ ﻣﻲﻛﻨﺪ‪.‬‬ ‫ج( ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻳﻚ ﻋﺪد ‪ long long‬ﺑﮕﻴﺮد و ﺑﺎ اﺳﺘﻔﺎده از ﺗﺎﺑﻊﻫﺎي ﺑﺎﻻ آن را ﺑﻪ دو‬ ‫‪ long‬ﺑﺸﻜﻨﺪ و دوﺑﺎره آنﻫﺎ را ﺑﻪ ﻫﻢ ﺑﭽﺴﺒﺎﻧﺪ و ﻧﺘﻴﺠﻪ را ﭼﺎپ ﻛﻨﺪ‪.‬‬

‫‪69‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ دوم‬ ‫در اﻳﻦ ﻓﺼﻞ ﻗﺼﺪ دارم ﺷﻤﺎ را ﺑﺎ دﺳﺘﻮرات ﻣﻬﻢ ‪ C++‬آﺷﻨﺎ ﻛﻨﻢ‪ .‬ﺷﺎﻳﺪ ﻻزم ﺑﺎﺷﺪ ﺗﺄﻛﻴﺪ ﻛﻨﻢ ﻛﻪ ﻣﻦ در اﻳﻦ ﻧﻮﺷﺘﻪ‬ ‫ﺷﻤﺎ را ﺑﺎ زﺑﺎن ‪ C++‬آﺷﻨﺎ ﻣﻲﻛﻨﻢ ﻧﻪ ﺑﺎ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﺣﺮﻓﻪاي‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﺧﻮﺑﻲ ﺑﺎﺷﻴﺪ اول ﺑﺎﻳﺪ ﺑﻪ‬ ‫ﺧﻮﺑﻲ ﻳﻚ زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﻣﺜﻞ ‪ C++‬را ﻳﺎد ﮔﺮﻓﺘﻪ ﺑﺎﺷﻴﺪ‪ .‬ﻣﻦ ﻓﻜﺮ ﻣﻲﻛﻨﻢ ﻛﺴﻲ ﻛﻪ اﺳﺘﻌﺪاد ﺧﻮﺑﻲ در ﺑﺮﻧﺎﻣﻪ‬ ‫ﻧﻮﻳﺴﻲ دارد وﻗﺘﻲ ﻳﻚ زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ را ﻳﺎد ﮔﺮﻓﺖ ﻛﻢ ﻛﻢ ﺧﻮدش ﻣﻲﺗﻮاﻧﺪ ﺗﻜﻨﻴﻚﻫﺎي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ را‬ ‫ﭘﻴﺪا ﻛﻨﺪ و ﺑﺮﻧﺎﻣﻪﻫﺎﻳﻲ ﭘﻴﭽﻴﺪه ﺑﻨﻮﻳﺴﺪ‪ .‬ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲﻫﺎ ﻣﺨﺘﺮﻋﺎن ﺗﻨﺒﻠﻲ ﻫﺴﺘﻨﺪ ﻛﻪ ﺑﻪ ﺟﺎي اﻳﻦ ﻛﻪ ﺑﺎ اﺑﺰار ﻓﻴﺰﻳﻜﻲ‬ ‫ﮔﺮان و ﮔﺎه ﺧﻄﺮﻧﺎك وﺳﻴﻠﻪاي ﺑﺴﺎزﻧﺪ‪ ،‬ﺧﻴﻠﻲ راﺣﺖ ﺳﺎﻋـﺖﻫﺎ روي ﻳﻚ ﺻﻨﺪﻟﻲ ﻧﺮم و راﺣﺖ ﻣﻲﻧﺸﻴﻨﻨﺪ و ﻫﺮ‬ ‫ﭼﻨﺪ دﻗﻴﻘﻪ ﻳﻚ ﺑﺎر ﭼﻨﺪ ﻛﻠﻴﺪ از ﺻﻔﺤﻪ ﻛﻠﻴﺪ ﻛﺎﻣﭙﻴﻮﺗﺮ را ﻓﺸﺎر ﻣﻲدﻫﻨﺪ و ﺑﺪون ﻫﻴﭻ ﻣﺸﻜﻠﻲ ﺑﻌﺪ از ﭼﻨﺪ ﻣﺎه ﺑﺮﻧﺎﻣﻪ‪-‬‬ ‫اي ﺗﺎزه ﺗﻮﻟﻴﺪ ﻣﻲﻛﻨﻨﺪ و آن را ﺑﺪون اﻳﻦ ﻛﻪ ﻧﻴﺎز ﺑﻪ ﺳﺎﺧﺖ ﻛﺎرﺧﺎﻧﻪي ﺗﻮﻟﻴﺪ ﺑﺎﺷﺪ ﺑﻪ آﺳﺎﻧﻲ ﺗﻜﺜﻴﺮ ﻣﻲﻛﻨﻨﺪ و ﺑﻪ‬ ‫ﻫﺰاران ﻧﻔﺮ ﻣﻲﻓﺮوﺷﻨﺪ‬

‫‪.‬‬

‫ا اع د‪ "#‬ره در ‪C++‬‬

‫در ‪ C++‬ﺳﻪ ﺟﻮر دﺳﺘﻮر دارﻳﻢ‪:‬‬ ‫‪ (1‬د‪456‬ر ‪Z6‬د‪ /‬ﺷﺎﻣﻞ‬ ‫‪ (a‬ﻓﺮاﺧﻮاﻧﻲ ﺗﺎﺑﻊ ‪:‬‬ ‫)‪1) f(2‬‬ ‫)(‪2) getch‬‬

‫‪ (b‬ﻓﺮاﺧﻮاﻧﻲ ﻋﻤﻠﮕﺮ ‪:‬‬ ‫"‪cout<< "hello‬‬ ‫‪2 + 3‬‬ ‫‪3 == 4‬‬ ‫‪a = 3‬‬

‫)‪1‬‬ ‫)‪2‬‬ ‫)‪3‬‬ ‫)‪4‬‬

‫‪ (c‬ﻣﻘﺪار ‪:‬‬ ‫‪1) 5‬‬ ‫'‪2) 'a‬‬ ‫"‪3) "hello‬‬

‫‪ (d‬ﺗﺮﻛﻴﺐ ‪ :‬ﺗﺮﻛﻴﺐ دﺳﺘﻮرﻫﺎي ﺳﺎدهي ﺑﺎﻻ ﺑﺎ »‪ «,‬ﻣﺜﻞ‬ ‫"‪a = 3, b = 4, cout<< "hello‬‬

‫‪70‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫دﺳﺘﻮر ﺳﺎده ﺷﺎﻣﻞ ﺗﻌﺮﻳﻒ ﻣﺘﻐﻴﺮ ﺟﺪﻳﺪ ﻧﻲ‪ .C4‬ﻣﺜﺎل زﻳﺮ اﻧﻮاع دﺳﺘﻮرﻫﺎي ﺳﺎده را در ﺧﻮدش دارد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪// faraa khaani e amalgar‬‬

‫)(‪void f‬‬ ‫{‬ ‫;"‪cout<< "hello‬‬ ‫}‬

‫)(‪int main‬‬ ‫{‬ ‫'‪f(); // faraa khaani e taabe‬‬ ‫‪2; // meqdaar‬‬ ‫‪'a'; //meqdaar‬‬ ‫‪"hello"; //megdaar‬‬ ‫‪3 == 4; // faraa khaani e amalgar‬‬ ‫‪3, "bye", f() ,3 + 6; // tarkib‬‬ ‫‪f(),getch(); // tarkib‬‬ ‫}‬

‫‪Output:‬‬ ‫‪hellohellohello‬‬

‫در اﻳﻦ ﻣﺜﺎل اﻧﻮاع دﺳﺘﻮرﻫﺎي ﺳﺎده را ﻣﻲﺑﻴﻨﻴﺪ‪ .‬دﺳﺘﻮر ﺗﺮﻛﻴﺐ را در ﻓﺼﻞ ﻗﺒﻞ ﻣﻌﺮﻓﻲ ﻧﻜﺮده ﺑﻮدم‪ .‬ﺑﺮاي ﺗﻮﺿﻴﺢ‬ ‫ﺑﻴﺶ ﺗﺮ ﺑﺎﻳﺪ ﺑﮕﻮﻳﻢ ﺧﻂ‬ ‫;)(‪f(),getch‬‬

‫ﻫﻤﺎن ﻛﺎري را ﻣﻲﻛﻨﺪ ﻛﻪ دو ﺧﻂ‬ ‫;)(‪f‬‬ ‫;)(‪getch‬‬

‫ﻣﻲﻛﻨﻨﺪ‪ .‬ﻳﻌﻨﻲ »‪ «,‬ﻛﺎر ﺧﺎﺻﻲ اﻧﺠﺎم ﻧﻤﻲدﻫﺪ‪ .‬ﺧﻂﻫﺎي‬ ‫;‪2‬‬ ‫;'‪'a‬‬ ‫;"‪"hello‬‬ ‫;‪3 == 4‬‬

‫ﻫﻴﭻ ﻛﺎري ﻧﻤﻲﻛﻨﻨﺪ‪.‬‬ ‫‪ (2‬دﺳﺘﻮر _^]\[ ﺷﺎﻣﻞ‬ ‫‪ (a‬ﺗﻌﺮﻳﻒ ﻣﺘﻐﻴﺮ ‪:‬‬ ‫‪1) int a‬‬ ‫‪2) bool b, prop‬‬

‫‪71‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ (b‬ﺗﻌﺮﻳﻒ و ﻣﻘﺪار اوﻟﻴﻪ دادن ‪:‬‬ ‫;‪1) int a = 2‬‬ ‫;‪2) bool prop = true‬‬

‫‪ (3‬دﺳﺘﻮر ‪ `a‬ﻛﻪ ﻳﻚ دﺳﺘﻮر ﺧﺎﻟﻲ اﺳﺖ ﻛﻪ ﻫﻴﭻ ﻛﺎري ﻧﻤﻲﻛﻨﺪ‪:‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪; // tohi‬‬ ‫}‬

‫‪Output: empty‬‬

‫‪ b4cd (4‬ﺷﺎﻣﻞ دﺳﺘﻪاي از دﺳﺘﻮرات زﻳﺮ ﻛﻪ ﻫﻤﻪ در ﻳﻚ ﺟﻔﺖ ‪) brace‬ﻳﻌﻨﻲ }{( ﻗﺮار دارﻧﺪ‪:‬‬ ‫‪ (a‬دﺳﺘﻮرﻫﺎي ﺗﻌﺮﻳﻒ ﻣﺘﻐﻴﺮ ﺑﺎ »;« در اﻧﺘﻬﺎ‬ ‫‪ (b‬دﺳﺘﻮرﻫﺎي ﺳﺎده ﺑﺎ »;« در اﻧﺘﻬﺎ‬ ‫‪ (c‬دﺳﺘﻮر ﺗﻬﻲ ﺑﺎ »;«‬ ‫‪ (d‬ﺧﻮد ﺑﻠﻮكﻫﺎ‬ ‫ﻣﺜﻞ‬ ‫{‬

‫)‪1‬‬

‫;‪int a‬‬ ‫;"‪cout<< "hello‬‬ ‫}‬ ‫{‬

‫)‪2‬‬

‫;‪int a = 3‬‬ ‫{‬ ‫;"‪cout<< "hello‬‬ ‫;‪cout<< a‬‬ ‫}‬ ‫}‬ ‫{‬

‫)‪3‬‬

‫;‪int a = 3‬‬ ‫}‬

‫در ﻣﺜﺎل زﻳﺮ از ﺑﻠﻮكﻫﺎ اﺳﺘﻔﺎده ﺷﺪه اﺳﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬

‫‪72‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫{‬

‫‪// block‬‬ ‫;‪int a = 2‬‬ ‫;‪cout<< a‬‬

‫}‬

‫‪// end of block‬‬ ‫‪// block‬‬ ‫‪// block‬‬ ‫;"‪cout<< "hello\n‬‬ ‫}‬ ‫‪// end of block‬‬ ‫;"‪cout<< "bye\n‬‬

‫{‬

‫{‬

‫}‬ ‫)‪if(2 > 3‬‬ ‫{‬ ‫‪// block‬‬ ‫;"‪cout<< "a block‬‬ ‫}‬ ‫‪// end of block‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪2hello‬‬ ‫‪bye‬‬

‫ﺑﺎ اﺳﺘﻔﺎده از اﻳﻦ ﺗﻘﺴﻴﻢ ﺑﻨﺪي دﺳﺘﻮرات ﻣﻲﺷﻮد ﺑﺮاي ﺧﻴﻠﻲ ﭼﻴﺰﻫﺎ در ‪ C++‬ﻓﺮﻣﻮلﻫﺎﻳﻲ ﻧﻮﺷﺖ‪ .‬ﻣﺜﻼ ﻓﺮﻣﻮل‬ ‫ﺗﺎﺑﻊ )(‪ main‬ﺑﻪ اﻳﻦ ﺻﻮرت اﺳﺖ‪:‬‬ ‫)(‪int main‬‬

‫]‪[b4cd‬‬ ‫ﻛﻪ ﺑﻪ ﺟﺎي ]‪ [b4cd‬ﻣﻲﺷﻮد ﻣﺜﻼ اﻳﻦ را ﮔﺬاﺷﺖ‪:‬‬ ‫{‬ ‫;"‪cout<< "hello‬‬ ‫;)(‪getch‬‬ ‫}‬

‫ﻛﻼ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﺎ اﺳﺘﻔﺎده از ﻛﻠﻤﺎﺗﻲ ﻣﺜﻞ د‪456‬ر ‪Z6‬د‪ ،b4cd ،/‬ا‪4i ،g6‬ع و‪ ...‬ﺑﺮاي اﺟﺰاي ‪C++‬‬ ‫ﻓﺮﻣﻮل ﺑﻨﻮﻳﺴﻴﻢ‪ .‬ﻣﺜﻼ ﻓﺮﻣﻮل ﺗﻌﺮﻳﻒ ﻳﻚ ﺗﺎﺑﻊ را ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻪ اﻳﻦ ﺻﻮرت ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫)]ا‪4i] [g6‬ع[‪] , … ,‬ا‪4i] [g6‬ع[( ]ا‪4i] [g6‬ع[‬ ‫]‪[b4cd‬‬

‫‪73‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫ع‬4i g6‫ع ا‬4i g6‫ع ا‬4i g6‫ا‬

int f(int a, int b) { cout<< a + b; return 0; }

‫ﻣﺜﻼ‬

b4cd

«int n\» ‫« ﻣﻲﻧﻮﻳﺴﻢ‬int ‫ع‬4i Zd ‫ار‬opm n\» ‫« ﻳﺎ‬int ‫ع‬4i Zd ]kl5m n\» ‫ﻣﻦ ﺑﻪ ﺟﺎي‬ ‫ ﺑﺎﻻ‬f ‫ ﻣﺜﻼ ﻓﺮﻣﻮل ﻓﺮاﺧﻮاﻧﻲ ﺗﺎﺑﻊ‬.«char n\» ‫« ﻣﻲﻧﻮﻳﺴﻢ‬char ‫ع‬4i Zd ]kl5m n\» ‫ﻳﺎ ﻣﺜﻼ ﺑﻪ ﺟﺎي‬ :‫ﺑﻪ اﻳﻦ ﺻﻮرت اﺳﺖ‬ f(int n\);

:‫اﻳﻦ ﻳﻌﻨﻲ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‬ f(2);

‫ دارد ﺧﻮد‬int ‫ ﻧﻮع‬f() ‫ از ﻃﺮﻓﻲ ﭼﻮن ﺧﺮوﺟﻲ ﺗﺎﺑﻊ‬.‫ اﺳﺖ‬int ‫ اﺳﺖ ﻳﻌﻨﻲ ﻣﻘﺪاري ﺑﺎ ﻧﻮع‬int n\ 2 ‫ﭼﻮن‬ .«‫ اﺳﺖ‬int n\ ،f(int n\)‫ »ﻫﺮ‬:‫ اﻳﻦ ﺟﻤﻠﻪ ﮔﻴﺞ ﻛﻨﻨﺪه ﺗﺮ اﺳﺖ‬.‫ اﺳﺖ‬int n\ ‫ ﻫﻢ‬f(2) :‫ﭼﻴﺰﻫﺎي ﺗﺎزهاي ﻛﻪ ﮔﻔﺘﻢ در ﻣﺜﺎل زﻳﺮ ﻫﺴﺖ‬ #include <conio.h> #include <iostream> using namespace std; void f(int& a) { cin>> a; // 25 //clrscr(); } int main() { int a; f(a), cout<< a + 1 << endl; // 26 { cout<< a << endl; int a = 4; cout<< a << endl; } cout<< a; // 25 getch();

// block // 25 // 4 // end of block

}

74

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪Output:‬‬ ‫‪25‬‬ ‫‪26‬‬ ‫‪25‬‬ ‫‪4‬‬ ‫‪25‬‬

‫ﺗﺎﺑﻊ )(‪ clrscr‬ﺻﻔﺤﻪي ﻧﻤﺎﻳﺶ را ﭘﺎك ﻣﻲﻛﻨﺪ وﻟﻲ ﭼﻮن ‪ Visual C++ 2005‬آن را ﻧﻤﻲﺷﻨﺎﺳﺪ آن را‬ ‫‪ comment out‬ﻛﺮدهام‪ .‬ﻧﻜﺘﻪي ﻣﻬﻢ ﺑﻌﺪي اﻳﻦ اﺳﺖ ﻛﻪ وﻗﺘﻲ ﻳﻚ ﻣﺘﻐﻴﺮ در ﻳﻚ ﺑﻠﻮك ﺗﻌﺮﻳﻒ ﺷﺪ ﺑﺎ ﺧﺮوج از‬ ‫ﺑﻠﻮك اﻋﺘﺒﺎر ﻣﺘﻐﻴﺮ ﺑﻪ ﭘﺎﻳﺎن ﻣﻲرﺳﺪ‪ .‬اﮔﺮ ﺑﺮاي ﺗﻌﺮﻳﻒ ﻳﻚ ﻣﺘﻐﻴﺮ در ﺑﻠﻮك از ﻧﺎﻣﻲ اﺳﺘﻔﺎده ﻛﻨﻴﻢ ﻛﻪ ﻗﺒﻼ اﺳﺘﻔﺎده‬ ‫ﺷﺪه‪ ،‬از ﺟﺎﻳﻲ ﻛﻪ ﺗﻌﺮﻳﻒ ﺷﺮوع ﻣﻲﺷﻮد ﺗﺎ ﭘﺎﻳﺎن ﺑﻠﻮك ﻣﺘﻐﻴﺮ ﻗﺒﻠﻲ ﻣﺤﻮ ﻣﻲﺷﻮد و آن ﻧﺎم ﺑﺮاي اﺷﺎره ﺑﻪ ﻣﺘﻐﻴﺮ‬ ‫ﺟﺪﻳﺪ ﺑﻪ ﻛﺎر ﻣﻲرود ﻣﺜﻞ ‪ a‬در ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ‪.‬‬ ‫در ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ در ﺧﻂ‬ ‫;‪f(a), cout<< a + 1 << endl‬‬

‫از »‪ «,‬اﺳﺘﻔﺎده ﺷﺪه و‬ ‫{‬ ‫;‪cout<< a << endl‬‬ ‫;‪int a = 4‬‬ ‫;‪cout<< a << endl‬‬ ‫}‬

‫ﻳﻚ ﺑﻠﻮك اﺳﺖ‪ .‬ﺷﺒﺎﻫﺖ ﺑﻠﻮك و »‪ «,‬اﻳﻦ اﺳﺖ ﻛﻪ ﻫﺮ دو از ﭼﻨﺪ دﺳﺘﻮر ﻛﻮﭼﻚ ﺗﺮ ﻳﻚ دﺳﺘﻮر ﺑﺰرگ ﺗﺮ‬ ‫ﻣﻲﺳﺎزﻧﺪ‪.‬‬

‫ ه ?‪8 C‬‬

‫‪ a<0‬ﻳﻌﻨﻲ ‪ a‬ﻛﻢ ﺗﺮ از ﺻﻔﺮ اﺳﺖ‪ .‬ﺣﺎل اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﺑﮕﻮﻳﻴﻢ ‪ a‬ﻛﻦ ﺗﺮ از ﺻﻔﺮ ﻧﻴﺴﺖ ﻣﻲﻧﻮﻳﺴﻴﻢ )‪ .!(a<0‬اﮔﺮ‬ ‫ﺑﺨﻮاﻫﻴﻢ ﺑﮕﻮﻳﻴﻢ ﻫﻢ ‪ a<0‬و ﻫﻢ ‪ -5<a‬ﻣﻲﻧﻮﻳﺴﻴﻢ !« ‪ «(a<0)&&(-5<a).‬و»&&« ﻫﺮ دو ﻋﻤﻠﮕﺮ ﻣﻨﻄﻘﻲ‬ ‫ﻫﺴﺘﻨﺪ‪.‬‬ ‫ﻋﻤﻠﮕﺮﻫﺎي ﻣﻨﻄﻘﻲ ﺑﺮاي ﺗﺮﻛﻴﺐ ﮔﺰارهﻫﺎ و ﺳﺎﺧﺘﻦ ﮔﺰارهﻫﺎي ﭘﻴﭽﻴﺪه ﺗﺮ ﺑﻪ ﻛﺎر ﻣﻲروﻧﺪ‪ .‬ﭼﻨﺪ ﺗﺎ از آنﻫﺎ در اﻳﻦ‬ ‫ﺟﺪول ﻣﻲﺑﻴﻨﻴﺪ‪:‬‬

‫‪75‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ < دل‬ ‫ ?‪8 C‬‬ ‫و‬

‫ ع‬ ‫> و‪8E‬‬

‫ ل ا> ا ‪8‬‬

‫ ‬

‫‪bool‬‬

‫\‪bool n\ && bool n‬‬

‫&&‬

‫)‪(a > 2)||(a < 10‬‬

‫ﻳﺎ‬

‫‪bool‬‬

‫\‪bool n\ || bool n‬‬

‫||‬

‫)‪!(a > 0‬‬

‫ﻧﻘﻴﺾ‬

‫‪bool‬‬

‫\‪!bool n‬‬

‫!‬

‫ﻣﺜﺎل‬ ‫)‪(a > 2)&&(a < 10‬‬

‫)اﻟﺒﺘﻪ ﻋﻤﻠﮕﺮ آﺧﺮي رﺑﻄﻲ ﺑﻪ ﺗﺮﻛﻴﺐ ﻧﺪارد‬

‫(‬

‫)‪ !(a>0‬ﻳﻌﻨﻲ »‪ a‬ﺑﺰرگ ﺗﺮ از ‪ 0‬ﻧﻴﺴﺖ« و ﻣﻌﺎدل اﺳﺖ ﺑﺎ ‪ a<=0‬ﭼﻮن وﻗﺘﻲ ﻳﻚ ﻋﺪد ﺑﺰرگ ﺗﺮ از ﺻﻔﺮ‬ ‫ﻧﺒﺎﺷﺪ ﻳﺎ ﺻﻔﺮ اﺳﺖ ﻳﺎ ﻣﻨﻔﻲ‪ a» 1(a>2)&&(a<10) .‬ﻛﻢ ﺗﺮ از ‪ 10‬و ‪ a‬ﺑﺰرگ ﺗﺮ از ‪ 2‬اﺳﺖ«‪.‬‬ ‫)‪ (a>2)||(a<10‬ﻳﻌﻨﻲ »ﻳﺎ ‪ a‬ﻛﻢ ﺗﺮ از ‪ 10‬اﺳﺖ ﻳﺎ ‪ a‬ﺑﻴﺶ ﺗﺮ از ‪ 2‬اﺳﺖ« ﻛﻪ اﻟﺒﺘﻪ ﻣﻘﺪار ‪ a‬ﻫﺮ ﭼﻪ ﺑﺎﺷﺪ‬ ‫ﮔﺰارهاي درﺳﺖ اﺳﺖ‪ .‬ﺑﻪ ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a, b‬‬ ‫;‪cin>> a‬‬ ‫;‪cin>> b‬‬ ‫)‪if(a >= 0 && b >= 0‬‬ ‫;"‪cout<< "both positive or zero‬‬ ‫;)‪bool prop = !(a >= 0 && b >= 0‬‬ ‫)‪if(prop‬‬ ‫;"‪cout<< "at least one negative‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬ ‫‪-3‬‬ ‫‪at least one negative‬‬

‫ا‪ / 01‬دو ﻋﺪد را از ﻛﺎرﺑﺮ ﻣﻲﮔﻴﺮد‪ .‬اﮔﺮ ﻫﻴﭻ ﻛﺪام ﻣﻨﻔﻲ ﻧﺒﻮدﻧﺪ ﭘﻴﺎم ‪ both positive or zero‬را‬ ‫ﭼﺎپ ﻣﻲﻛﻨﺪ وﮔﺮﻧﻪ ﭘﻴﺎم ‪ at least one negative‬را ﭼﺎپ ﻣﻲﻛﻨﺪ‪ .‬ﻣﻦ ﺑﻪ ﻋﻨﻮان ﻛﺎرﺑﺮ اﻋﺪاد ‪ 5‬و ‪-3‬‬

‫را ﺑﻪ ﺑﺮﻧﺎﻣﻪ دادهام و ﭘﻴﺎم دوم ﭼﺎپ ﺷﺪه‪.‬‬

‫‪76‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫اﮔﺮ ﺧﻮب ﺑﺎ ﻣﻨﻄﻖ‪ ،‬آن ﻃﻮري ﻛﻪ در رﻳﺎﺿﻴﺎت ﺑﻴﺎن ﻣﻲﺷﻮد‪ ،‬آﺷﻨﺎ ﺑﺎﺷﻴﺪ ﺑﺎ ﻣﻨﻄﻖ ‪ C++‬ﻫﻢ ﺧﻴﻠﻲ راﺣﺖ ﻫﺴﺘﻴﺪ‪.‬‬ ‫اﻣﺎ ﭼﻮن ﻓﺮض ﻣﻦ ﺑﺮ اﻳﻦ اﺳﺖ ﻛﻪ ﺷﻤﺎ ﺗﺎزه ﻣﻲﺧﻮاﻫﻴﺪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﻳﺎد ﺑﮕﻴﺮﻳﺪ و ﻫﻴﭻ ﺳﺎﺑﻘﻪاي در ﺷﻨﺎﺧﺖ ﻣﻨﻄﻖ‬ ‫ﻧﺪارﻳﺪ ﺑﺎﻳﺪ ﻛﻤﻲ درﺑﺎره ﮔﺰارهﻫﺎي ﻣﻨﻄﻘﻲ ﺗﻮﺿﻴﺢ ﺑﺪﻫﻢ‪.‬‬ ‫در زﺑﺎن ﻓﺎرﺳﻲ وﻗﺘﻲ ﻛﺴﻲ ﻣﻲﮔﻮﻳﺪ »ﻳﺎ ‪ C++‬ﻳﺎد ﻣﻲﮔﻴﺮم ﻳﺎ ‪ «C#‬ﻣﺎ اﻳﻦ ﺑﺮداﺷﺖ را ﻣﻲﻛﻨﻴﻢ ﻛﻪ او ﻫﺮ دو را‬ ‫ﻳﺎد ﻧﺨﻮاﻫﺪ ﮔﺮﻓﺖ و ﻓﻘﻂ ﻳﻜﻲ را ﻳﺎد ﻣﻲﮔﻴﺮد‪ .‬در ‪» C++‬ﻳﺎ« ﻣﻌﻨﻲ »ﻓﻘﻂ ﻳﻜﻲ« ﻧﺪارد‪ .‬ﺑﻨﺎﺑﺮاﻳﻦ در ‪C++‬‬ ‫ﻋﺒﺎرت )‪ (0<a)||(0<b‬ﻳﻌﻨﻲ »ﻳﺎ ‪ 0<b‬ﻳﺎ ‪ 0<a‬ﻳﺎ ﻫﺮ دو«‪.‬‬ ‫ﭼﻴﺰ دﻳﮕﺮي ﻛﻪ ﺧﻴﻠﻲﻫﺎ را ﺑﻪ ﺷﻚ ﻣﻲاﻧﺪازد اﻳﻦ اﺳﺖ ﻛﻪ آﻳﺎ)‪ (2 <= 3‬درﺳﺖ اﺳﺖ ﻳﺎ ﻏﻠﻂ‪ .‬ﻣﻄﻠﺐ ﺷﻚ‬ ‫ﺑﺮاﻧﮕﻴﺰ اﻳﻦ اﺳﺖ ﻛﻪ ﭼﻮن ‪ 2‬ﺑﺎ ‪ 3‬ﻣﺴﺎوي ﻧﻴﺴﺖ )‪ (2 <= 3‬ﻫﻢ درﺳﺖ ﻧﻴﺴﺖ‪ .‬ﻧﺒﺎﻳﺪ ﭼﻨﻴﻦ ﺑﺮداﺷﺘﻲ ﻛﺮد‪ .‬در‬ ‫واﻗﻊ )‪(2<=3‬ﻣﻌﺎدل اﺳﺖ ﺑﺎ )‪ .(2<3)||(2==3‬ﺑﻨﺎﺑﺮ آن ﭼﻴﺰي ﻛﻪ در ﻣﻮرد || ﮔﻔﺘﻢ‪،‬‬ ‫)‪(2<3)||(2==3‬درﺳﺖ اﺳﺖ )زﻳﺮا ‪ 2<3‬درﺳﺖ اﺳﺖ(‪ .‬ﭘﺲ )‪ (2<=3‬درﺳﺖ اﺳﺖ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﻛﺎﻣﻼ‬ ‫ﻣﻄﻤﺌﻦ ﺑﺸﻮﻳﻢ ﺑﺮﻧﺎﻣﻪي زﻳﺮ را ﻣﻲﻧﻮﻳﺴﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫)‪if(2 <= 3‬‬ ‫;"‪cout<< "2<=3‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪2<=3‬‬

‫اﮔﺮ ‪ 2<=3‬درﺳﺖ ﻧﺒﻮد ﭼﻴﺰي ﭼﺎپ ﻧﻤﻲﺷﺪ‪.‬‬ ‫اﮔﺮ ﺑﺎ ﻣﻨﻄﻖ رﻳﺎﺿﻲ آﺷﻨﺎ ﺑﺎﺷﻴﺪ دو ﻋﻤﻠﮕﺮ ﺗﺮﻛﻴﺒﻲ دﻳﮕﺮ ﻫﻢ وﺟﻮد دارد‪ .‬ﻳﻜﻲ »اﮔﺮ ‪ ...‬آﻧﮕﺎه ‪ «...‬و دﻳﮕﺮي »‪...‬‬ ‫ﻣﻌﺎدل اﺳﺖ ﺑﺎ ‪ .«...‬ﻋﻤﻠﮕﺮ »اﮔﺮ ‪ ...‬آﻧﮕﺎه ‪ «...‬در ‪ C++‬وﺟﻮد ﻧﺪارد و ﻛﺎرﺑﺮدي ﻫﻢ ﻧﺪارد و اﮔﺮ ﺑﺨﻮاﻫﻴﻢ آن را‬ ‫ﺑﺴﺎزﻳﻢ ﺑﺎﻳﺪ از ﻣﻌﺎدلﻫﺎي ﻣﻨﻄﻘﻲ آن اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪.‬‬ ‫ﻋﻤﻠﮕﺮ »‪ ...‬ﻣﻌﺎدل اﺳﺖ ﺑﺎ ‪ «...‬ﻫﻢ در ‪ C++‬ﻧﻴﺴﺖ‪ .‬اﻣﺎ ﺑﮕﺬارﻳﺪ در ﻣﻮرد آن ﻛﻤﻲ ﺣﺮف ﺑﺰﻧﻢ‪ .‬ﻣﻲﮔﻮﻳﻴﻢ دو ﺗﺎ‬ ‫ﮔﺰاره ﻣﺜﻞ ‪ p‬و ‪ q‬ﻣﻌﺎدﻟﻨﺪ اﮔﺮ ﻳﺎ ﻫﺮ دو درﺳﺖ ﺑﺎﺷﻨﺪ ﻳﺎ ﻫﺮ دو ﻏﻠﻂ ﺑﺎﺷﻨﺪ‪ .‬ﻣﺜﻼ ‪ 2<3‬و ‪ 4<5‬ﻫﺮ دو درﺳﺘﻨﺪ و‬ ‫ﺑﻨﺎﺑﺮاﻳﻦ ﻣﻌﺎﻟﻨﺪ‪ 10<10 .‬و ‪ 100<20‬ﻫﺮ دو ﻏﻠﻄﻨﺪ ﭘﺲ ﻣﻌﺎدﻟﻨﺪ‪ .‬وﻗﺘﻲ دو ﺗﺎ ﮔﺰاره ﻣﻌﺎدل ﺑﺎﺷﻨﺪ در دﺳﺘﻮر ‪if‬‬

‫ﻓﺮﻗﻲ ﻧﺪارد ﻛﺪام را اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ‪ .‬ﻳﻌﻨﻲ‬ ‫)‪if(2 < 3‬‬

‫‪77‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;"‪cout<< "hello‬‬

‫ﻫﻤﺎن ﻛﺎري را ﻣﻲﻛﻨﺪ ﻛﻪ‬ ‫)‪if(3 < 4‬‬ ‫;"‪cout<< "hello‬‬

‫ﻣﻲﻛﻨﺪ ﭼﻮن ‪ 2<3‬و ‪ 3<4‬ﻣﻌﺎدﻟﻨﺪ‪.‬‬ ‫اﮔﺮ ﮔﺰارهﻫﺎ ﻧﻮع ‪ bool‬داﺷﺘﻪ ﺑﺎﺷﻨﺪ‪ ...» ،‬ﻣﻌﺎدل اﺳﺖ ﺑﺎ ‪ «...‬ﻫﻤﺎن ﺗﺴﺎوي اﺳﺖ و ﻫﺮ ﺟﺎ ﻻزم ﺑﻮد از ﺗﺴﺎوي‬ ‫اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ وﻟﻲ اﻳﻦ ﺟﺎ ﻳﻚ ﻣﺸﻜﻠﻲ ﻫﺴﺖ و آن اﻳﻦ ﻛﻪ ﻫﻤﻪي ﮔﺰارهﻫﺎ ﻧﻮع ‪ bool‬ﻧﺪارﻧﺪ در واﻗﻊ ﮔﺰرهﻫﺎ‬ ‫ﻣﻲﺗﻮاﻧﻨﺪ ﻫﺮ ﻧﻮﻋﻲ داﺷﺘﻪ ﺑﺎﺷﻨﺪ ﻏﻴﺮ از ﻧﻮعﻫﺎﻳﻲ ﻛﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﺧﻮدش ﻣﻲﺳﺎزد )ﻣﺜﻼ ﺑﺎ ‪ .(struct‬ﻳﻚ ﻣﻘﺪار‬ ‫ﺑﺎ ﻫﺮ ﻧﻮﻋﻲ اﮔﺮ ﻏﻴﺮ ﺻﻔﺮ ﺑﺎﺷﺪ ﮔﺰارهاي درﺳﺖ ﺑﻪ ﺣﺴﺎب ﻣﻲآﻳﺪ و اﮔﺮ ﺻﻔﺮ ﺑﺎﺷﺪ ﮔﺰارهاي ﻏﻠﻂ ﺑﻪ ﺣﺴﺎب ﻣﻲ‪-‬‬ ‫آﻳﺪ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫)"‪if("hello‬‬ ‫;"‪cout<<"hello\n‬‬ ‫;‪double a = 0.141592653‬‬ ‫)‪if(a‬‬ ‫;"‪cout<<"double\n‬‬ ‫)‪if(0‬‬ ‫;"‪cout<<"zero‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪hello‬‬ ‫‪double‬‬

‫"‪ char* n\ "hello‬اﺳﺖ و ﻣﻘﺪارش وﻗﺘﻲ ﺑﻪ ﻋﻨﻮان ﻋﺪد در ﻧﻈﺮ ﮔﺮﻓﺘﻪ ﻏﻴﺮ ﺻﻔﺮ اﺳﺖ ‪ .‬ﺑﻨﺎﺑﺮاﻳﻦ ﻳﻚ‬ ‫ﮔﺰارهي درﺳﺖ ﺑﻪ ﺣﺴﺎب ﻣﻲآﻳﺪ‪ .‬ﻫﻤﻴﻦ ﻃﻮر در ﻣﻮرد ‪.a‬‬ ‫ﻫﺮ ﻋﺪد ﻏﻴﺮ ﺻﻔﺮ ﻳﻚ ﮔﺰاره درﺳﺖ ﺑﻪ ﺣﺴﺎب ﻣﻲآﻳﺪ ﭘﺲ ﻣﻤﻜﻦ اﺳﺖ دو ﺗﺎ ﮔﺰارهي درﺳﺖ ﻧﺎﻣﺴﺎوي ﺑﺎﺷﻨﺪ‪.‬‬ ‫ﻣﺜﻼ ﻋﺪد ‪ 2‬ﻳﻚ ﮔﺰارهي درﺳﺖ اﺳﺖ‪ ،‬ﻋﺪد ‪ 3‬ﻫﻢ ﻳﻚ ﮔﺰارهي درﺳﺖ اﺳﺖ ﺑﻨﺎﺑﺮاﻳﻦ ‪ 2‬و ‪ 3‬ﻣﻌﺎدﻟﻨﺪ وﻟﻲ‬ ‫ﻣﺴﺎوي ﻧﻴﺴﺘﻨﺪ‪ .‬ﭘﺲ ﺑﻬﺘﺮ اﺳﺖ ﺑﺮاي ﻣﻌﺎدل ﺑﻮدن ﮔﺰارهﻫﺎي ‪ p‬و ‪ q‬ﺑﻨﻮﻳﺴﻴﻢ ‪.!p==!q‬‬ ‫ﺑﺮاي اﻳﻦ ﻛﻪ ﺛﺎﺑﺖ ﻛﻨﻴﻢ ‪ !p==!q‬ﻣﻌﺎدل ﺑﻮدن ﺑﻮدن را ﻧﺸﺎن ﻣﻲدﻫﺪ ﺑﺎﻳﺪ ﺛﺎﺑﺖ ﻛﻨﻴﻢ ‪ !p==!q‬ﻓﻘﻂ وﻗﺘﻲ‬ ‫درﺳﺖ اﺳﺖ ﻛﻪ ‪ p‬و ‪ q‬ﻣﻌﺎدل ﺑﺎﺷﻨﺪ ﺑﺮاي اﻳﻦ ﻛﺎر ﺳﻪ ﺣﺎﻟﺖ را در ﻧﻈﺮ ﻣﻲﮔﻴﺮﻳﻢ‪:‬‬

‫‪78‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ p (a‬و ‪ q‬ﻫﺮدو درﺳﺖ ﺑﺎﺷﻨﺪ‪:‬‬ ‫اﮔﺮ ﻣﻘﺪار ‪ 2 ،p‬ﺑﺎﺷﺪ و ﻣﻘﺪار ‪ 1 ،q‬ﺑﺎﺷﺪ ﻫﺮ دو درﺳﺘﻨﺪ و در ﻧﺘﻴﺠﻪ ﻣﻌﺎدﻟﻨﺪ‪ !p==!q ،‬ﻫﻢ ﺑﻪ ﺷﻜﻞ‬ ‫‪ 0==0‬در ﻣﻲآﻳﺪ ﻛﻪ درﺳﺖ اﺳﺖ و ﻣﻌﺎدل ﺑﻮدن را ﻧﺸﺎن ﻣﻲدﻫﺪ‪.‬‬ ‫‪ p (b‬و ‪ q‬ﻫﺮ دو ﻧﺎدرﺳﺖ ﺑﺎﺷﻨﺪ‪:‬‬ ‫اﮔﺮ ﻣﻘﺪارﻫﺎي ‪ p‬و ‪ q‬ﻫﺮ دو ﺻﻔﺮ ﺑﺎﺷﻨﺪ ﻓﺮﻣﻮل ‪ !p==!q‬ﺑﻪ ﺷﻜﻞ ‪ 1==1‬در ﻣﻲآﻳﺪ ﻛﻪ ﺑﺎز ﻣﻌﺎدل‬ ‫ﺑﻮدن را ﻧﺸﺎن ﻣﻲدﻫﺪ‪.‬‬ ‫‪ (c‬ﻳﻜﻲ از ‪ p‬و ‪ q‬ﻏﻠﻂ و دﻳﮕﺮي درﺳﺖ ﺑﺎﺷﺪ‪:‬‬ ‫اﮔﺮ ﻣﻘﺪار ‪ 2 ،p‬ﺑﺎﺷﺪ و ﻣﻘﺪار ‪ 0 ،q‬ﺑﺎﺷﺪ‪ p ،‬و ‪ q‬ﻣﻌﺎدل ﻧﻴﺴﺘﻨﺪ‪ !p==!q .‬ﻫﻢ ﺑﻪ ﺷﻜﻞ ‪ 0==1‬در ﻣﻲ‪-‬‬ ‫آﻳﺪ ﻛﻪ ﻧﺎدرﺳﺖ اﺳﺖ و ﻣﻌﺎدل ﻧﺒﻮدن را ﻧﺸﺎن ﻣﻲدﻫﺪ‪.‬‬ ‫در ﮔﺬﺷﺘﻪ ﺑﻪ ﺟﺎي ‪ bool‬از ‪ int‬اﺳﺘﻔﺎده ﻣﻲﺷﺪ‪ .‬ﻫﻨﻮز ﻫﻢ ﻣﻲﺗﻮاﻧﻴﻢ از ‪ int‬ﺑﻪ ﺟﺎي ‪ bool‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ و‬ ‫ﮔﺎﻫﻲ ﺑﻪ ﺧﺎﻃﺮ وﺟﻮد ﺗﺎﺑﻊﻫﺎي ﻗﺪﻳﻤﻲ ﭼﺎرهاي ﺑﻪ ﺟﺰ اﻳﻦ ﻧﻴﺴﺖ‪ .‬وﻗﺘﻲ ﻳﻚ ‪ int‬ﻏﻴﺮ ﺻﻔﺮ ﺑﺎﺷﺪ درﺳﺖ ﺑﻪ ﺣﺴﺎب‬ ‫ﻣﻲآﻳﺪ و اﮔﺮ ﺻﻔﺮ ﺑﺎﺷﺪ ﻏﻠﻂ ﺑﻪ ﺣﺴﺎب ﻣﻲآﻳﺪ‪ .‬در ﻣﺜﺎل زﻳﺮ ﺑﻪ ﺟﺎي ‪ bool‬از ‪ int‬اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪int prop = (2 <= 3‬‬ ‫;‪cout<< prop << endl‬‬ ‫)‪if(prop‬‬ ‫;‪cout<< "prop is true"<< endl‬‬ ‫;‪int w = -5‬‬ ‫)‪if(w && prop‬‬ ‫;"‪cout<< "w and prop are true‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬ ‫‪prop is true‬‬ ‫‪w and prop are true‬‬

‫در ﻛﺎر ﺑﺎ رﺷﺘﻪﻫﺎ ﮔﺎﻫﻲ از \‪ char n‬ﺑﻪ ﺟﺎي ﮔﺰاره اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪.‬‬

‫‪79‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻣﻦ در ‪ compiler‬ﺷﺮﻛﺖ ‪ Microsoft‬ﻧﺘﻮاﻧﺴﺘﻢ ﺑﻪ \‪ bool n‬ﻏﻴﺮ از ‪ 0‬و ‪ 1‬ﻣﻘﺪار دﻳﮕﺮي ﺑﺪﻫﻢ‪ .‬اﻣﺎ در‬ ‫‪ BDS 2006‬ﻛﻪ ﻣﺤﺼﻮل ﺷﺮﻛﺖ ‪ Borland‬اﺳﺖ ﺑﺎ اﺳﺘﻔﺎده از ﻋﻤﻠﮕﺮ ‪ ++‬اﻳﻦ ﻛﺎر را ﻛﺮدم‪ .‬اﮔﺮ ﺑﭙﺬﻳﺮﻳﻢ ﻛﻪ‬ ‫ﻳﻚ ‪ bool‬ﻏﻴﺮ از ‪ 0‬و ‪ 1‬ﻣﻘﺪار دﻳﮕﺮي ﻧﺪارد ﻣﻲﺗﻮاﻧﻴﻢ ﺑﺮاي ﻣﻌﺎدل ﺑﻮدن ‪bool‬ﻫﺎي ‪ p‬و ‪ q‬ﺑﻨﻮﻳﺴﻴﻢ ‪.p==q‬‬ ‫ﻣﻦ ﻓﻜﺮ ﻣﻲﻛﻨﻢ اﻳﻦ ﺑﺮاي ‪ Borland‬ﻳﻚ ﻧﻘﺺ اﺳﺖ ﻛﻪ اﺟﺎزه ﻣﻲدﻫﺪ ﻛﻪ \‪ bool n‬ﻣﻘﺪاري ﻏﻴﺮ از ‪ 0‬و ‪1‬‬

‫داﺷﺘﻪ ﺑﺎﺷﺪ‪ .‬در ﻫﺮ ﺣﺎل اﺣﺘﻴﺎط در اﻳﻦ ﻻزم اﺳﺖ ﻛﻪ دو ﮔﺰارهي درﺳﺖ ﻫﻤﻴﺸﻪ ﻣﺴﺎوي ﻧﻴﺴﺘﻨﺪ‪.‬‬ ‫ﺣﺎﻻ ﺑﮕﺬارﻳﺪ ﺗﻌﺪادي از ﻣﻌﺎدلﻫﺎي ﻣﻨﻄﻘﻲ ﻣﻬﻢ را ﺑﻴﺎن ﻛﻨﻢ‪ .‬ﻓﺮض ﻛﻨﻴﺪ ‪ p‬و ‪ q‬و ‪ r‬ﮔﺰارهﻫﺎﻳﻲ ﻛﺎﻣﻼ ﺛﺎﺑﺖ ﻳﺎ‬ ‫دﺳﺖ ﻛﻢ ﻏﻴﺮ واﺑﺴﺘﻪ ﺑﺎﺷﻨﺪ‪ .‬ﻣﻌﺎدلﻫﺎي زﻳﺮ را دارﻳﻢ‪:‬‬ ‫ﻣﻌﺎدل‬ ‫‪p‬‬ ‫‪p‬‬ ‫‪!q‬‬ ‫‪!q‬‬ ‫)‪(p && r‬‬

‫&&‬ ‫||‬ ‫||‬ ‫&&‬ ‫||‬

‫ﻣﻌﺎدل‬ ‫‪p && q‬‬ ‫‪p || q‬‬ ‫)‪!(p && q‬‬ ‫)‪!(p || q‬‬ ‫)‪p && (q || r‬‬

‫‪q‬‬ ‫‪q‬‬ ‫‪!p‬‬ ‫‪!p‬‬ ‫)‪(p && q‬‬

‫ﺑﻪ ﻋﻨﻮان ﻣﺜﺎل ﺑﻪ ﺟﺎي )‪ !(a > 0 && b > 0‬ﻣﻲﺷﻮد ﻧﻮﺷﺖ )‪ !(a > 0) || !(b > 0‬و ﺑﻪ ﺟﺎي‬ ‫اﻳﻦ ﻫﻢ ﻣﻲﺷﻮد ﻧﻮﺷﺖ ‪.a <= 0 || b <= 0‬‬ ‫دو ﻣﺜﺎل ﺑﻌﺪي ﺷﺎﻳﺪ ﺑﻴﺶ از ﺣﺪ ﺗﺨﺼﺼﻲ ﺑﺎﺷﻨﺪ وﻟﻲ ﻣﻨﻈﻮر ﻣﻦ را از ﻏﻴﺮ واﺑﺴﺘﻪ ﺑﻮدن ﮔﺰارهﻫﺎ ﻛﻪ ﭘﻴﺶ از ﺟﺪول‬ ‫ﺑﺎﻻ ﺑﻪ آن اﺷﺎره ﻛﺮدم ﻣﺸﺨﺺ ﻣﻲﻛﻨﺪ‪ .‬ﻓﺮق اﻳﻦ دو ﻣﺜﺎل اﻳﻦ اﺳﺖ ﻛﻪ در ﻳﻜﻲ‬ ‫;)(‪bool prop = p() || q‬‬

‫ﻧﻮﺷﺘﻪام و در دﻳﮕﺮي‬ ‫;)(‪bool prop = q() || p‬‬

‫ﻣﺜﺎل اول‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫;‪bool a = true‬‬ ‫)(‪bool p‬‬ ‫{‬ ‫;‪return a‬‬ ‫}‬ ‫)(‪bool q‬‬ ‫{‬ ‫;‪a = false‬‬

‫‪80‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ return a; } int main() { bool prop = p() || q(); if(prop == true) cout<< "it is true"; if(prop == false) cout<< "it is false"; getch(); }

Output: it is true

:‫ﻣﺜﺎل دوم‬ #include <conio.h> #include <iostream> using namespace std; bool a = true; bool p() { return a; } bool q() { a = false; return a; } int main() { bool prop = q() || p(); if(prop == true) cout<< "it is true"; if(prop == false) cout<< "it is false"; getch(); }

Output: it is false

‫ اﺛﺮ ﻣﻲﮔﺬارد و در ﻧﺘﻴﺠﻪ‬p() ‫ روي‬q() ‫ ﻣﻌﺎدل ﻧﻴﺴﺖ ﭼﻮن اﺟﺮاي‬p()||q() ‫ ﺑﺎ‬q()||p() ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬ .‫ اﺟﺮا ﻣﻲﺷﻮد‬p() ‫ و ﺑﻌﺪ‬q() ‫ اول‬q()||p() ‫ ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ در‬.‫اﻳﻦ دو ﮔﺰاره ﻣﺴﺘﻘﻞ ﻧﻴﺴﺘﻨﺪ‬ :‫ ﺑﻪ اﻳﻦ ﻓﺮﻣﻮل ﻧﮕﺎه ﻛﻨﻴﺪ‬.‫در اداﻣﻪي اﻳﻦ ﺑﺨﺶ اﺷﺎرهاي ﻫﻢ ﺑﻪ اوﻟﻮﻳﺖ ﻋﻤﻠﮕﺮﻫﺎ ﻣﻲﻛﻨﻢ‬ p || !q && r

‫اﻳﻦ ﻓﺮﻣﻮل ﺑﻪ ﻋﻨﻮان ﮔﺰاره ﺑﺎ ﻛﺪام ﻳﻚ از ﻓﺮﻣﻮل زﻳﺮ ﻣﻌﺎدل اﺳﺖ؟‬

81

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪(p || (!q)) && r‬‬ ‫)‪p || ((!q) && r‬‬ ‫))‪p || (!(q && r‬‬

‫ﺑﺮاي ﻣﻌﻠﻮم ﺷﺪن اﻳﻦ‪ ،‬ﺑﺎﻳﺪ اوﻟﻮﻳﺖ )‪ (precedence‬اﺛﺮ ﻋﻤﻠﮕﺮﻫﺎي &&‪ || ،‬و ! ﻣﺸﺨﺺ ﺑﺎﺷﺪ‪ .‬ﺑﻪ اﻳﻦ ﺟﺪول‬ ‫ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫ﺗﻮﺿﻴﺤﺎت‬

‫ﻋﻤﻠﮕﺮ‬

‫ﻋﻤﻠﮕﺮ * ﺑﻪ ﻋﻨﻮان ‪indirection‬‬

‫!‬ ‫*‬

‫ﻋﻤﻠﮕﺮ * ﺑﻪ ﻋﻨﻮان ﺿﺮب‬

‫*‬ ‫‪+‬‬ ‫‪-‬‬

‫>>‬ ‫<<‬

‫ﻣﺜﻼ در <<‪cout‬‬

‫<‬ ‫>‬ ‫=<‬ ‫=>‬

‫==‬ ‫&&‬

‫||‬ ‫در ﻳﻚ ﻓﺮﻣﻮل اول ﺑﺎﻳﺪ ﺑﻪ ﺳﺮاغ ﻋﻤﻠﮕﺮﻫﺎي ﺑﺎ اوﻟﻮﻳﺖ ﺑﺎﻻﺗﺮ ﺑﺮوﻳﻢ‪ .‬اﻳﻦ ﺟﺪول اوﻟﻮﻳﺖﻫﺎ را ﻧﺸﺎن ﻣﻲدﻫﺪ‪.‬‬ ‫ﻋﻤﻠﮕﺮﻫﺎﻳﻲ ﻛﻪ ﺑﺎﻻﺗﺮ ﻗﺮار دارﻧﺪ اوﻟﻮﻳﺖ ﺑﻴﺶ ﺗﺮي دارﻧﺪ‪ .‬ﻋﻤﻠﮕﺮﻫﺎﻳﻲ ﻛﻪ در ﻳﻚ ﻣﺴﺘﻄﻴﻞ ﻫﺴﺘﻨﺪ اوﻟﻮﻳﺖ ﻳﻜﺴﺎن‬ ‫دارﻧﺪ و اﻳﻦ ﻳﻌﻨﻲ اوﻟﻮﻳﺖ آنﻫﺎ از ﭼﭗ ﺑﻪ راﺳﺖ ﺑﻪ ﺗﺮﺗﻴﺐ ﻇﺎﻫﺮ ﺷﺪن اﺳﺖ‪ .‬ﺟﺪول ِ ﺧﻴﻠﻲ ﻛﺎﻣﻞ ﺗﺮي را ﻣﻲﺗﻮاﻧﻴﺪ‬ ‫در ‪ compiler ِ help‬ﺧﻮدﺗﺎن ﭘﻴﺪا ﻛﻨﻴﺪ‪ .‬در ﺑﺎﻻ‪ ،‬ﻣﻨﻈﻮر از ‪ indirection‬دﺳﺘﻴﺎﺑﻲ ﺑﻪ ﺣﺎﻓﻈﻪ از ﻃﺮﻳﻖ ‪pointer‬‬ ‫)اﺷﺎره ﮔﺮ( اﺳﺖ ﻣﺜﻼ *ي ﻗﺮﻣﺰ رﻧﮓ در‬ ‫;‪int* p = new int‬‬ ‫;‪*p = 4‬‬

‫ﭼﻮن اوﻟﻮﻳﺖ ! ﺑﻴﺶ ﺗﺮ از && اﺳﺖ‪ ،‬در‬ ‫‪p || !q && r‬‬

‫اول ﺑﻪ ﺳﺮاغ ! ﻣﻲروﻳﻢ و اﻳﻦ ﻓﺮﻣﻮل ﺗﺒﺪﻳﻞ ﻣﻲﺷﻮد ﺑﻪ‬

‫‪82‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪p || (!q) && r‬‬

‫ﺑﻌﺪ ﺑﻪ ﺳﺮاغ && ﻣﻲروﻳﻢ و ﺑﻪ‬ ‫)‪p || ((!q) && r‬‬

‫ﻣﻲرﺳﻴﻢ‪.‬‬ ‫در‬ ‫‪false || true && false && true‬‬

‫اوﻟﻮﻳﺖ ﺑﺎ &&ي اﺳﺖ ﻛﻪ در ﭼﭗ ﻗﺮار دارد‪:‬‬ ‫‪false || (true && false) && true‬‬

‫ﺑﻌﺪ‪ ،‬آن ﭼﻪ ﻛﻪ داﺧﻞ ﭘﺮاﻧﺘﺰ ﻗﺮار دارد ﺑﻪ ﻋﻨﻮان ﻳﻚ واﺣﺪ ﻣﻲﮔﻴﺮﻳﻢ )اﻧﮕﺎر اﺻﻼ ﻫﻴﭻ ﻋﻤﻠﮕﺮي در آن ﻧﺒﺎﺷﺪ( و‬ ‫ﺑﺎز اوﻟﻮﻳﺖ را ﺑﻪ && ﻣﻲدﻫﻴﻢ‪:‬‬ ‫)‪false || ((true && false) && true‬‬

‫ﺣﺎﻻ ﻣﻲﺗﻮاﻧﻴﺪ ﺣﺴﺎب ﻛﻨﻴﺪ ﻣﻘﺪار اﻳﻦ ﻋﺒﺎرت ﭼﻴﺴﺖ؟ ‪ true‬ﻳﺎ ‪false‬؟‬ ‫ﭼﻴﺰ دﻳﮕﺮي ﻛﻪ ﺑﺎﻳﺪ ﺑﻪ آن ﺗﻮﺟﻪ ﻛﺮد ﭘﺮاﻧﺘﺰﻫﺎﺳﺖ‪ .‬ﺑﺎﻳﺪ ﻣﻘﺪار دروﻧﻲ ﺗﺮﻳﻦ ﭘﺮاﻧﺘﺰ اول ﺣﺴﺎب ﺑﺸﻮد و ﺑﻌﺪ ﻣﻘﺪار‬ ‫ﭘﺮاﻧﺘﺰﻫﺎي ﺑﻴﺮوﻧﻲ ﺗﺮ ﺣﺴﺎب ﺑﺸﻮﻧﺪ‪ .‬ﻣﺜﻼ در‬ ‫))‪p && (q || (r || s || t‬‬

‫اول )‪ (r || s || t‬ﺳﭙﺲ ))‪ (q || (r || s || t‬و در ﻧﻬﺎﻳﺖ ﻛﻞ ﻓﺮﻣﻮل ﺑﺎﻳﺪ ﺣﺴﺎب ﺷﻮد‪.‬‬ ‫ﺣﺎل ﺑﺮاي اﻣﺘﺤﺎن آن ﭼﻪ در ﻣﻮرد اوﻟﻮﻳﺖ ﮔﻔﺘﻪ ﺷﺪ ﻧﮕﺎﻫﻲ ﺑﻪ ﻣﺜﺎل زﻳﺮ ﺑﻴﻨﺪازﻳﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫;‪) << endl‬‬ ‫;‪) << endl‬‬ ‫;‪) << endl‬‬

‫; ‪true‬‬ ‫;‪false‬‬ ‫;‪false‬‬ ‫‪p || q && r‬‬ ‫)‪p || (q && r‬‬ ‫‪(p || q) && r‬‬

‫)(‪int main‬‬ ‫{‬ ‫= ‪bool p‬‬ ‫= ‪bool q‬‬ ‫= ‪bool r‬‬ ‫(<<‪cout‬‬ ‫(<<‪cout‬‬ ‫(<<‪cout‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬ ‫‪1‬‬ ‫‪0‬‬

‫‪83‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﭘﺮاﻧﺘﺰ ِ ﺑﻌﺪ از <<‪ cout‬ﻻزم اﺳﺖ ﭼﻮن << اوﻟﻮﻳﺖ ﺑﺎﻻﺗﺮ دارد‪ .‬اﻳﻦ ﻣﺜﺎل اﻫﻤﻴﺖ ﭘﺮاﻧﺘﺰﻫﺎ را روﺷﻦ ﻣﻲﻛﻨﺪ‪.‬‬ ‫ﮔﺮﭼﻪ ﺟﺪوﻟﻲ ﻣﺜﻞ ﺟﺪول ﺑﺎﻻ اوﻟﻮﻳﺖﻫﺎ را ﻣﺸﺨﺺ ﻣﻲﻛﻨﺪ اﻣﺎ ﺑﻬﺘﺮ اﺳﺖ ﻫﺮ ﺟﺎ ﻣﻤﻜﻦ اﺳﺖ اﺑﻬﺎﻣﻲ ﭘﻴﺶ ﺑﻴﺎﻳﺪ )ﻳﺎ‬ ‫ﺣﺘﻲ اﮔﺮ اﺑﻬﺎﻣﻲ ﭘﻴﺶ ﻧﻴﺎﻳﺪ( از ﭘﺮاﻧﺘﺰﻫﺎ اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ .‬اﻳﻦ اﺣﺘﻤﺎل ﺧﻄﺎ را ﻛﻢ و ﺧﻮاﻧﺎ ﺑﻮدن ﺑﺮﻧﺎﻣﻪ را زﻳﺎد ﻣﻲﻛﻨﺪ‪.‬‬ ‫اﮔﺮ ﻣﻄﻤﺌﻦ ﺑﺎﺷﻴﻢ ﻛﻪ \‪ bool n‬ﻣﻘﺪاري ﻏﻴﺮ از ﺻﻔﺮ و ﻳﻚ ﻧﺪارد ﺑﻪ ﺟﺎي ‪ p||q‬ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ ‪ .p+q‬ﺑﻪ‬ ‫ﺟﺎي ‪ p&&q‬ﻫﻢ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ ‪) p*q‬ﻳﻌﻨﻲ ﺣﺎﺻﻞ ﺿﺮب ﻣﻘﺪارﻫﺎي ‪ p‬و ‪ .(q‬وﻟﻲ اﻳﻦ ﻛﺎر اﺻﻼ ﺗﻮﺻﻴﻪ ﻧﻤﻲ‪-‬‬ ‫ﺷﻮد ﭼﻮن ﻫﻢ ‪ Borland‬و ﻫﻢ ‪ Microsoft‬ﮔﺰارهﻫﺎﻳﻲ دارﻧﺪ ﻛﻪ ﻣﻤﻜﻦ اﺳﺖ ﻣﻘﺪارﻫﺎي ﻏﻴﺮ از ‪ 0‬و ‪ 1‬داﺷﺘﻪ‬ ‫ﺑﺎﺷﻨﺪ‪.‬‬ ‫اﮔﺮ ﺑﺨﻮاﻫﻢ ﻣﻲﺗﻮاﻧﻢ ﺣﺘﻲ ‪ 300‬ﺻﻔﺤﻪي دﻳﮕﺮ درﺑﺎرهي ﮔﺰارهﻫﺎ و وﻳﮋﮔﻲﻫﺎﻳﻲ ﭘﻴﭽﻴﺪهي آنﻫﺎ ﺑﻨﻮﻳﺴﻢ‪ .‬وﻟﻲ در‬ ‫اﻳﻦ ﻧﻮﺷﺘﻪ ﻗﺼﺪ ﺗﻤﺮﻛﺰ ﺑﻴﺶ از ﺣﺪ روي ﻫﻴﭻ ﭼﻴﺰ را ﻧﺪارم و ﻓﻘﻂ ﺳﻌﻲ دارم ﺷﻤﺎ را ﺑﺎ ﻗﺎﺑﻠﻴﺖﻫﺎي ‪ C++‬آﺷﻨﺎ‬ ‫ﻛﻨﻢ‪ .‬ﮔﺰارهﻫﺎ در ﻫﻤﻪي زﺑﺎنﻫﺎي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ وﺟﻮد دارﻧﺪ و ﻣﻲﺷﻮد ﺧﺼﻮﺻﻴﺎت آنﻫﺎ را ﺑﻪ ﻃﻮر ﻛﻠﻲ و ﺧﺎرج‬ ‫از ﻫﺮ زﺑﺎن ﺧﺎﺻﻲ ﮔﻔﺖ‪ ) .‬ﻣﻮﺿﻮع ﮔﺰارهﻫﺎ از ﻫﺰاران ﺳﺎل ﭘﻴﺶ ﻛﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲﻫﺎي اوﻟﻴﻪ ﺻﻔﺮ و ﻳﻚﻫﺎ را ﺑﺮ‬ ‫دﻳﻮارهي ﻏﺎرﻫﺎ ﺣﻚ ﻣﻲﻛﺮدﻧﺪ ﻣﻮﺿﻮع ﭘﺮ دردﺳﺮي ﺑﻮده اﺳﺖ ‪ .‬اﻟﺒﺘﻪ در آن زﻣﺎنﻫﺎ ﻣﺮدﻣﺎن اﻳﺮان زﻣﻴﻦ آن ﻗﺪر‬ ‫ﻣﺘﻤﺪن ﺑﻮدهاﻧﺪ ﻛﻪ ﺑﺮ ﻛﺘﻴﺒﻪﻫﺎي ﺳﻨﮕﻲ دوران ﻫﺨﺎﻣﻨﺸﻲ ﺑﺮﻧﺎﻣﻪﻫﺎﻳﻲ ﺑﻪ زﺑﺎن ‪ C++‬وﻟﻲ ﺑﻪ ﺧﻂ ﻣﻴﺨﻲ ﻳﺎﻓﺖ ﺷﺪه‬ ‫اﺳﺖ‪ Bjarne Stroustrup .‬ﺑﻪ دروغ ﺑﻪ ﻋﻨﻮان آﻓﺮﻳﻨﻨﺪهي ‪ C++‬ﻣﻌﺮﻓﻲ ﺷﺪه اﺳﺖ‪ .‬ﺑﻪ ﻋﻼوه ﻣﺨﺘﺮع ‪ C#‬ﻫﻢ‬ ‫ﺷﺨﺼﻲ اﻳﺮاﻧﻲ ﺑﻪ ﻧﺎم ﺳﻴﺪ ﺑﻦ ﺷﺎرع ﺑﻮده اﺳﺖ ﻛﻪ در ‪ 700‬ﺳﺎل ﭘﻴﺶ ﻣﻲزﻳﺴﺘﻪ‪ .‬ﻣﺘﺎﺳﻔﺎﻧﻪ اﻣﺮوزه ﻳﻜﻲ از ﻛﺎرﻛﻨﺎن‬ ‫‪ Microsoft‬ﺑﻪ ﻋﻨﻮان ﺑﻪ وﺟﻮد آورﻧﺪهي ‪ C#‬ﻣﻌﺮﻓﻲ ﻣﻲﺷﻮد و اﺳﻢ ﺳﻴﺪ ﺑﻦ ﺷﺎرع ﻫﻢ ﺑﻪ ﻃﻮر ﻣﻐﺮﺿﺎﻧﻪاي ﺑﺪ ﺗﻠﻔﻆ‬ ‫ﻣﻲﺷﻮد و ﺑﺪﺗﺮ از ﻫﻤﻪ اﻳﻦ ﻛﻪ ﻫﻴﭻ ﻛﺲ ﻫﻴﭻ اﻋﺘﺮاﺿﻲ ﻧﻤﻲﻛﻨﺪ‪.‬‬

‫(‬

‫د‪ "#‬ر ‪if … else‬‬

‫دﺳﺘﻮر ‪ if‬را ﻗﺒﻼ ﺑﻪ ﻃﻮر ﺧﻴﻠﻲ ﻧﺎﻗﺼﻲ ﻣﻌﺮﻓﻲ ﻛﺮده ﺑﻮدﻳﻢ‪ .‬ﻓﺮﻣﻮل ﻛﺎﻣﻞ اﻳﻦ دﺳﺘﻮر ﺑﻪ ﺷﻜﻞ زﻳﺮ اﺳﺖ‪:‬‬ ‫)‪23‬ار‪if(/‬‬ ‫]د‪456‬ر د‪4t‬ا‪ /‬اول[‬ ‫‪[else‬‬ ‫]]د‪456‬ر د‪4t‬ا‪ /‬دوم[‬

‫ﻣﻨﻈﻮر از ][ اﻳﻦ اﺳﺖ ﻛﻪ ﺑﺨﺶ‬ ‫‪else‬‬

‫‪84‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫]د‪456‬ر د‪4v‬ا‪ /‬دوم[‬ ‫ﻣﻲﺗﻮاﻧﺪ ﺣﺬف ﺷﻮد‪ .‬اﮔﺮ ‪23‬ار‪ /‬درﺳﺖ ﺑﺎﺷﺪ‪ ،‬ﻓﻘﻂ ]د‪456‬ر د‪4t‬ا‪ /‬اول[ اﺟﺮا ﻣﻲﺷﻮد وﮔﺮﻧﻪ ﻓﻘﻂ‬ ‫]د‪456‬ر د‪4t‬ا‪ /‬دوم[ اﺟﺮا ﻣﻲﺷﻮد‪ .‬ﺑﻪ ﻣﺜﺎل زﻳﺮ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪char a‬‬ ‫;‪cin>> a‬‬ ‫;‪cout<< endl‬‬ ‫)'‪if( a == 'a‬‬ ‫{‬ ‫;"‪char* c = "one‬‬ ‫;‪cout<< c‬‬ ‫}‬ ‫‪else‬‬ ‫{‬ ‫;"‪char c[] = "two‬‬ ‫;‪cout<< c‬‬ ‫}‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪x‬‬ ‫‪two‬‬

‫ا‪ +‬د‪!84‬ر ‪ if‬در ا‪ F 01‬ل را ‪! E‬ل ‪ if‬ﻛﻪ ﻗﺒﻞ از ﻣﺜﺎل آورده ﺷﺪه ﻣﻘﺎﻳﺴﻪ ﻛﻨﻴﻢ ﻣﻲﺑﻴﻨﻴﻢ در اﻳﻦ ﺟﺎ‬ ‫]د‪456‬ر د‪4t‬ا‪ /‬اول[ ﻋﺒﺎرت اﺳﺖ از‬ ‫{‬ ‫;"‪char* c = "one‬‬ ‫;‪cout<< c‬‬ ‫}‬

‫ﻛﻪ ﻳﻚ ﺑﻠﻮك اﺳﺖ‪] .‬د‪456‬ر د‪4t‬ا‪ /‬دوم[ ﻫﻢ ﻳﻚ ﺑﻠﻮك اﺳﺖ‪:‬‬ ‫{‬ ‫;"‪char c[] = "two‬‬ ‫;‪cout<< c‬‬ ‫}‬

‫‪23‬ار‪ /‬ﻫﻢ در اﻳﻦ ﺟﺎ '‪ a == 'a‬ا‪ .C4‬ﭼﻮن ﻣﻦ ‪ x‬را وارد ﻛﺮدم '‪ a == 'a‬ﻧﺎدرﺳﺖ ﺷﺪه و ]د‪456‬ر‬

‫د‪4t‬ا‪ /‬دوم[ اﺟﺮا ﺷﺪه‪.‬‬

‫‪85‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻣﻨﻈﻮر ﻣﻦ از د‪456‬ر د‪4t‬ا‪ /‬اﻳﻦ اﺳﺖ ﻛﻪ ﻫﺮ ﻳﻚ از اﻧﻮاع دﺳﺘﻮرات ﻛﻪ در اول ﻓﺼﻞ ﮔﻔﺘﻢ ﻣﻲﺗﻮاﻧﺪ ﺑﺎﺷﺪ‪ .‬اﻣﺎ‬ ‫در ﻣﻮرد دﺳﺘﻮر _^]\[ ﻳﻚ ﻧﻜﺘﻪ ﻫﺴﺖ‪ .‬در‬ ‫)‪if(true‬‬ ‫;‪int a = 1‬‬

‫‪ a‬ﭘﺲ از »;« اﻋﺘﺒﺎر ﺧﻮد را از دﺳﺖ ﻣﻲدﻫﺪ و ﻗﺎﺑﻞ اﺳﺘﻔﺎده ﻧﻴﺴﺖ‪.‬‬ ‫‪ else‬ﻫﻤﻴﺸﻪ ﺑﻪ ﻧﺰدﻳﻚ ﺗﺮﻳﻦ ‪if‬ي ﻣﻲﭼﺴﺒﺪ ﻛﻪ داﺧﻞ ﺑﻠﻮك ﻧﺒﺎﺷﺪ ﻣﺜﻼ اﻳﻦ دو ﺗﺎ ﻣﺜﺎل را ﺑﺎ ﻫﻢ ﻣﻘﺎﻳﺴﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫)‪if(3 > 2‬‬ ‫)‪if(4 > 5‬‬ ‫;"‪cout<< "4 > 5‬‬ ‫‪else‬‬ ‫;"‪cout<< "else‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪else‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫)‪if(3 > 2‬‬ ‫{‬ ‫)‪if(4 > 5‬‬ ‫;"‪cout<< "4 > 5‬‬ ‫}‬ ‫‪else‬‬ ‫;"‪cout<< "else‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output: empty‬‬

‫در ﻣﺜﺎل دوم ‪ else‬ﺑﻪ ‪ if‬اول ﭼﺴﺒﻴﺪه‪ .‬ﭼﻮن ‪ 3>2‬درﺳﺖ اﺳﺖ‪،‬‬ ‫{‬ ‫)‪if(4 > 5‬‬ ‫;"‪cout<< "4 > 5‬‬ ‫}‬

‫‪86‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫اﺟﺮا ﺷﺪه ﻛﻪ ﻫﻴﭻ ﻛﺎري اﻧﺠﺎم ﻧﻤﻲدﻫﺪ‪ .‬اﻣﺎ در ﻣﺜﺎل اول ‪ else‬ﺑﻪ ‪ if‬دوم ﭼﺴﺒﻴﺪه‪ .‬ﭼﻮن در ‪ if‬اول ‪3>2‬‬

‫درﺳﺖ اﺳﺖ‪،‬‬ ‫)‪if(4 > 5‬‬ ‫;"‪cout<< "4 > 5‬‬ ‫‪else‬‬ ‫;"‪cout<< "else‬‬

‫اﺟﺮا ﺷﺪه ﻛﻪ ﻧﺘﻴﺠﻪاش ﭼﺎپ "‪ "else‬اﺳﺖ‪.‬‬

‫‪for F‬‬

‫ﺣﻠﻘﻪاي ﺑﺎ ﻧﺎم ‪ for‬ﺗﻘﺮﻳﺒﺎ در ﻫﻤﻪي زﺑﺎنﻫﺎي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﭘﻴﺪا ﻣﻲﺷﻮد اﻣﺎ ﭘﻴﭽﻴﺪه ﺗﺮﻳﻦ ﺷﻜﻞ آن در ‪ C++‬اﺳﺖ‪.‬‬ ‫ﻓﺮﻣﻮل ﺣﻠﻘﻪي ‪ for‬ﺑﻪ اﻳﻦ ﺷﻜﻞ اﺳﺖ‪:‬‬ ‫)د‪456‬ر)‪Z6 (2‬د‪23];`a Z\ /‬ار‪;[/‬د‪456‬ر)‪Z6 (1‬د‪for([\]^_ Z\ `a Z\ /‬‬ ‫]د‪456‬ر)‪ (3‬د‪4t‬ا‪[/‬‬

‫ﭘﺲ ﺳﻪ دﺳﺘﻮر دارﻳﻢ‪:‬‬ ‫‪ (1‬د‪456‬ر)‪ (1‬ﻛﻪ ﻧﻮع آن ﻣﻲﺗﻮاﻧﺪ ‪Z6‬د‪ [\]^_ Z\ `a Z\ /‬ﺑﺎﺷﺪ‪.‬‬ ‫‪ (2‬د‪456‬ر)‪ (2‬ﻛﻪ ﻧﻮع آن ﻣﻲﺗﻮاﻧﺪ ‪Z6‬د‪ `a Z\ /‬ﺑﺎﺷﺪ‪.‬‬ ‫‪ (3‬د‪456‬ر)‪ (3‬ﻛﻪ ﻫﺮ ﻧﻮﻋﻲ ﻣﻲﺗﻮاﻧﺪ ﺑﺎﺷﺪ‪.‬‬ ‫وﻗﺘﻲ ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ ﺑﻪ دﺳﺘﻮر ‪ for‬ﺑﺎﻻ ﻣﻲرﺳﺪ اول د‪456‬ر)‪ (1‬را اﺟﺮا ﻣﻲﻛﻨﺪ‪ .‬ﺑﻌﺪ ﺑﻪ ﺗﺮﺗﻴﺐ ﻣﺮاﺣﻞ زﻳﺮ‬ ‫را آن ﻗﺪر ﺗﻜﺮار ﻣﻲﻛﻨﺪ ﺗﺎ از ﺣﻠﻘﻪ ﺧﺎرج ﺑﺸﻮد‪:‬‬ ‫‪ (1‬اﮔﺮ ‪23‬ار‪ /‬ﻧﺎدرﺳﺖ ﺑﺎﺷﺪ )ﻳﻌﻨﻲ ﺻﻔﺮ ﺑﺎﺷﺪ( از ﺣﻠﻘﻪي ‪ for‬ﺧﺎرج ﻣﻲﺷﻮد‪.‬‬ ‫‪ (2‬د‪456‬ر)‪ (3‬را اﺟﺮا ﻣﻲﻛﻨﺪ‪.‬‬ ‫‪ (3‬د‪456‬ر)‪ (2‬را اﺟﺮا ﻣﻲﻛﻨﺪ‪.‬‬ ‫ﺑﻨﺎﺑﺮاﻳﻦ د‪456‬ر)‪ (3‬و ﺑﻌﺪ د‪456‬ر)‪ (2‬آن ﻗﺪر ﭘﺸﺖ ﺳﺮ ﻫﻢ اﺟﺮا ﻣﻲﺷﻮﻧﺪ ﺗﺎ آن ﻛﻪ ‪23‬ار‪ /‬ﺻﻔﺮ‬ ‫)ﻧﺎدرﺳﺖ( ﺷﻮد‪ .‬ﻣﺘﺪاول ﺗﺮﻳﻦ ﺷﻜﻞ اﺳﺘﻔﺎده از ﺣﻠﻘﻪي ‪ for‬ﺷﻜﻞ زﻳﺮ اﺳﺖ‪:‬‬ ‫)‪for(int i = 0; i < 10; i++‬‬

‫]د‪456‬ر)‪ (3‬د‪4t‬ا‪[/‬‬

‫‪87‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫در واﻗﻊ ﺑﻬﺘﺮ اﺳﺖ ﻛﻪ ﻓﻘﻂ اﻳﻦ ﺷﻜﻞ ﺑﻪ ﺧﺼﻮص از ﺣﻠﻘﻪي ‪ for‬ﻣﻮرد اﺳﺘﻔﺎده ﻗﺮار ﺑﮕﻴﺮد‪ .‬ﺑﺮﻧﺎﻣﻪي زﻳﺮ ‪ 10‬ﺑﺎر‬ ‫‪ hello‬را ﭼﺎپ ﻣﻲﻛﻨﺪ‪.‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫)‪for(int i = 0; i < 10; i++‬‬ ‫;‪cout<< "hello" << endl‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪hello‬‬ ‫‪hello‬‬ ‫‪hello‬‬ ‫‪hello‬‬ ‫‪hello‬‬ ‫‪hello‬‬ ‫‪hello‬‬ ‫‪hello‬‬ ‫‪hello‬‬ ‫‪hello‬‬

‫ﺷﺎﻳﺪ ﻫﻨﻮز ﻛﺎر ‪ for‬ﺑﺮاﻳﺘﺎن ﻣﺒﻬﻢ ﺑﺎﺷﺪ‪ for .‬ﺑﺮاي اﻳﻦ ﺑﻪ ﻛﺎر ﻣﻲرود ﻛﻪ ﻳﻚ دﺳﺘﻮر را ﭼﻨﺪ ﺑﺎر ﺗﻜﺮار ﻛﻨﺪ‪ .‬در‬ ‫ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ ‪ for‬دﺳﺘﻮر‬

‫;‪"hello" << endl‬‬

‫<<‪ cout‬را ‪ 10‬ﺑﺎر اﺟﺮا ﻣﻲﻛﻨﺪ ﻳﺎ ﻣﺜﻼ ﺑﻪ ﺟﺎي‬ ‫;‪0‬‬ ‫;‪1‬‬ ‫;‪2‬‬ ‫;‪3‬‬ ‫;‪4‬‬

‫<<‪cout‬‬ ‫<<‪cout‬‬ ‫<<‪cout‬‬ ‫<<‪cout‬‬ ‫<<‪cout‬‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫)‪for(int i = 0; i < 5; i++‬‬ ‫;‪cout<< i‬‬

‫ﺳﻌﻲ ﻛﻨﻴﺪ اﻳﻦﻫﺎ را ﺑﺎ ﺗﻮﺿﻴﺤﻲ ﻛﻪ اول اﻳﻦ ﺑﺨﺶ در ﻣﻮرد ﻧﺤﻮهي ﻛﺎر ‪ for‬ﮔﻔﺘﻢ ﺗﻮﺟﻴﻪ ﻛﻨﻴﺪ ﺗﺎ ﻛﺎﻣﻼ ﺑﺎ دﺳﺘﻮر‬ ‫‪ for‬آﺷﻨﺎ ﺑﺸﻮﻳﺪ‪.‬‬

‫‪88‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﺷﻜﻠﻲ ﻏﻴﺮ ﻣﺘﺪاول و ﻧﻤﺎدﻳﻦ از ﺑﻪ ﻛﺎر ﺑﺮدن ‪ for‬را ﻧﺸﺎن ﻣﻲدﻫﺪ‪ .‬ﺧﻮب اﺳﺖ روي ﻣﺮاﺣﻞ اﺟﺮاي‬ ‫دﺳﺘﻮرات ﻓﻜﺮ ﻛﻨﻴﺪ و ﺧﺮوﺟﻲ را ﺗﻮﺟﻴﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪bool prop1 = true‬‬ ‫;‪bool prop2 = true‬‬ ‫)"‪for(cout<<"statement1\n"; prop1; cout<<"statement2\n‬‬ ‫{‬ ‫;"‪cout<< "statement3\n‬‬ ‫)‪if(prop2 == true‬‬ ‫;‪prop2 = false‬‬ ‫‪else‬‬ ‫;‪prop1 = false‬‬ ‫}‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪statement1‬‬ ‫‪statement3‬‬ ‫‪statement2‬‬ ‫‪statement3‬‬ ‫‪statement2‬‬

‫ﮔﺮﭼﻪ ﻓﻜﺮ ﻣﻲﻛﻨﻢ ﺣﻴﻦ آﻣﻮزش ‪ C++‬ﻧﺒﺎﻳﺪ ﺧﻴﻠﻲ وارد ﻛﺎرﺑﺮدﻫﺎي واﻗﻌﻲ دﺳﺘﻮرات ﺷﺪ وﻟﻲ ﻣﺜﺎل زﻳﺮ ﺑﺮاي‬ ‫ﻧﺸﺎن دادن ﻗﺪرت ﺣﻠﻘﻪي ‪ for‬ﺿﺮوري ﺑﻪ ﻧﻈﺮ ﻣﻲرﺳﺪ‪ .‬ﺿﻤﻦ اﻳﻦ ﻛﻪ ﻳﻚ ﻳﺎد آوري ﺑﺮاي رﺷﺘﻪﻫﺎﺳﺖ ﻛﻪ آنﻫﺎ‬ ‫را ﻓﺮاﻣﻮش ﻧﻜﻨﻴﺪ‪ .‬ﺷﺎﻳﺪ ﺑﻪ ﻧﻈﺮ ﻧﻴﺎﻳﺪ اﻣﺎ رﺷﺘﻪ ﺑﻪ ﻋﻨﻮان راﺑﻂ ﺑﻴﻦ ﻛﺎرﺑﺮ و ﺑﺮﻧﺎﻣﻪ از ﻣﻬﻢﺗﺮﻳﻦ ﻗﺴﻤﺖﻫﺎي ﻫﺮ زﺑﺎن‬ ‫ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ اﺳﺖ و اﮔﺮ دﻗﺖ ﻛﻨﻴﺪ ﻧﺮم اﻓﺰارﻫﺎي ﭘﺮ ﻛﺎرﺑﺮدي ﻛﻪ ﺑﺎ آنﻫﺎ ﺳﺮ و ﻛﺎر دارﻳﺪ ﻛﺎر اﺻﻠﻴﺸﺎن ﻣﺮﺗﺐ‬ ‫ﻛﺮدن و ﻧﻤﺎﻳﺶ ﻣﻨﺎﺳﺐ رﺷﺘﻪﻫﺎﺳﺖ‪ .‬در ﻫﺮ ﺣﺎل ﻗﺒﻮل دارم ﻛﻪ ﺑﺮاي ﻳﻚ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻛﻪ ﻓﻜﺮ ﻛﺮدن را دوﺳﺖ‬ ‫دارد‪ ،‬رﺷﺘﻪﻫﺎ ﺧﻴﻠﻲ ﻣﺤﺒﻮﺑﻴﺖ ﻧﺪارﻧﺪ‪ .‬ﻣﺜﺎل زﻳﺮ ﺷﺎﻣﻞ ﺗﺎﺑﻌﻲ اﺳﺖ ﻛﻪ ﻃﻮل رﺷﺘﻪ را ﻣﻌﻴﻦ ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪int GetLength(char* c‬‬ ‫{‬ ‫;‪int i‬‬ ‫)‪for(i = 0; c[i] != '\0'; i++‬‬ ‫;‬ ‫;‪return i‬‬ ‫}‬

‫‪89‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)(‪int main‬‬ ‫{‬ ‫;)"‪cout<< GetLength("hello‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬

‫در ﺗﺎﺑﻊ )(‪ GetLength‬از اﻳﻦ ﻣﻮﺿﻮع ﻛﻪ آﺧﺮﻳﻦ ﻛﺎراﻛﺘﺮ ﻳﻚ رﺷﺘﻪ '‪ '\0‬اﺳﺖ اﺳﺘﻔﺎده ﺷﺪه‪ .‬ﻣﻘﺪار ﻋﺪدي‬ ‫'‪ '\0‬ﺻﻔﺮ اﺳﺖ ﺑﺮاي ﻫﻤﻴﻦ ﺑﻪ ﺟﺎي '‪!6 c[i] != '\0‬ا‪ .c[i] != 0 .G1! ./‬در ﺣﻠﻘﻪي ‪for‬‬

‫دﺳﺘﻮر ﺗﻬﻲ را ﺑﻪ ﻛﺎر ﺑﺮدهام‪ .‬ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﮔﺎﻫﻲ ﺑﻪ دﺳﺘﻮر ﺗﻬﻲ ﻫﻢ ﻧﻴﺎز دارﻳﻢ‪ .‬در اﻳﻦ ﻣﺜﺎل ﻃﻮل رﺷﺘﻪي‬ ‫"‪ "hello‬ﭼﺎپ ﺷﺪه‪.‬‬ ‫در ﻓﺮﻣﻮل دﺳﺘﻮر ‪ for‬اﮔﺮ د‪456‬ر)‪ (1‬ﻳﻚ د‪456‬ر _^]\[ ﺑﺎﺷﺪ ﻣﺘﻐﻴﺮ)ﻫﺎي( ﺗﻌﺮﻳﻔﻲ آن ﺑﺎ ﺧﺮوج از‬ ‫ﺣﻠﻘﻪ ﻏﻴﺮ ﻣﻌﺘﺒﺮ ﻣﻲﺷﻮﻧﺪ‪ .‬ﻣﺜﻼ در ﻣﺜﺎل ﻗﺒﻞ ﺗﻌﺮﻳﻒ ﻣﺘﻐﻴﺮ ‪ i‬را ﻧﻤﻲﺗﻮاﻧﺴﺘﻴﻢ در ﺣﻠﻘﻪي ‪ for‬اﻧﺠﺎم ﺑﺪﻫﻴﻢ و‬ ‫ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫)‪int GetLength(char* c‬‬ ‫{‬ ‫)‪for(int i = 0; c[i] != '\0'; i++‬‬ ‫;‬ ‫;‪return i‬‬ ‫}‬

‫ﻧﻜﺘﻪي ﺟﺎﻟﺐ اﻳﻦ اﺳﺖ ﻛﻪ در ﮔﺬﺷﺘﻪ و در ‪compiler‬ﻫﺎي ﻗﺪﻳﻤﻲ اﻳﻦ ﻃﻮر ﻧﺒﻮد و ﻣﻲﺗﻮاﻧﺴﺘﻴﻢ‬ ‫ﺗﺎﺑﻊ)(‪ GetLength‬را ﺑﻪ ﺻﻮرت اﺧﻴﺮ ﻫﻢ ﺑﻨﻮﻳﺴﻴﻢ‪ .‬در ﻗﺴﻤﺖ ‪ options‬در ‪compiler‬ﻫﺎي ﺟﺪﻳﺪ اﺣﺘﻤﺎﻻ‬ ‫ﮔﺰﻳﻨﻪاي ﺑﺮاي ﺗﻐﻴﻴﺮ اﻳﻦ وﺿﻌﻴﺖ وﺟﻮد دارد‪ .‬اﻳﻦ ﻣﺴﺎﺋﻞ ﺑﻪ ﺗﺼﻤﻴﻢﻫﺎﻳﻲ ﻛﻪ در ﻣﻮرد اﺳﺘﺎﻧﺪارد ‪ C++‬ﮔﺮﻓﺘﻪ ﻣﻲ‪-‬‬ ‫ﺷﻮد ﺑﺴﺘﮕﻲ دارد )و ﻣﺎ ﻛﺎﻣﻼ ﺑﻲ ﺗﻘﺼﻴﺮﻳﻢ‬

‫(‪.‬‬

‫اﮔﺮ ﺑﻪ ﻓﺮﻣﻮﻟﻲ ﻛﻪ ﺑﺮاي ﺣﻠﻘﻪي ‪ for‬اراﺋﻪ ﻛﺮدم ﻧﮕﺎه ﻛﻨﻴﺪ ﻧﻮﺷﺘﻪام ]‪23‬ار‪ [/‬ﻧﻪ ‪23‬ار‪ ./‬اﻳﻦ ﻳﻌﻨﻲ ﻣﻲﺷﻮد‬ ‫ﻧﻮﺷﺖ‪:‬‬ ‫)‪for(int i = 0;; i++‬‬ ‫;‬

‫ﻛﻪ ﻣﻌﺎدل اﺳﺖ ﺑﺎ‬ ‫)‪for(int i = 0; true; i++‬‬ ‫;‬

‫‪90‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻣﺸﻜﻞ اﻳﻦ ﺟﺎﺳﺖ ﻛﻪ اﮔﺮ اﻳﻦ ﺣﻠﻘﻪ اﺟﺮا ﺷﻮد‪ ،‬اﺟﺮاي آن ﻫﻴﭻ وﻗﺖ ﺗﻤﺎم ﻧﻤﻲﺷﻮد ﻣﮕﺮ ﺑﺎ زور ﺑﺮﻧﺎﻣﻪ را ﻣﺘﻮﻗﻒ‬ ‫ﻛﻨﻴﻢ‪ .‬ﺑﺮﻧﺎﻣﻪ زﻳﺮ را اﺟﺮا ﻛﻨﻴﺪ و ﺑﺮاي ﻣﺘﻮﻗﻒ ﻛﺮدن آن از ‪ Ctrl + Break‬ﻛﻤﻚ ﺑﮕﻴﺮﻳﺪ ) ﻛﻠﻴﺪ ‪Break‬‬

‫ﻳﻜﻲ از ﺳﻪ ﻛﻠﻴﺪ ﻛﻨﺎر ﻫﻢ در ﮔﻮﺷﻪي راﺳﺖ و ﺑﺎﻻي ‪ keyboard‬اﺳﺖ(‪ .‬ﺑﻪ ﻋﻼوه ﻣﻲﺗﻮاﻧﻴﺪ از دﮔﻤﻪﻫﺎي‬ ‫‪ compiler‬ﺑﺮاي ﺗﻮﻗﻒ اﺳﺘﻔﺎده ﻛﻨﻴﺪ )در ‪ Visual C++ 2005‬دﮔﻤﻪي ﻧﺸﺎن داده ﺷﺪه در‬

‫را ﻓﺸﺎر دﻫﻴﺪ‪(.‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫)‪for(int i = 0;; i++‬‬ ‫;‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output: empty‬‬

‫راه دﻳﮕﺮي ﻫﻢ ﺑﺮاي ﺧﺮوج از ﺣﻠﻘﻪي ‪ for‬ﻫﺴﺖ و آن اﺳﺘﻔﺎده از دﺳﺘﻮر ‪ break‬اﺳﺖ‪ .‬اﮔﺮ ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ‬ ‫در ﺣﻠﻘﻪ ﺑﻪ دﺳﺘﻮر ‪ break‬ﺑﺮﺳﺪ ﻓﻮرا از ﺣﻠﻘﻪ ﺧﺎرج ﻣﻲﺷﻮد‪ .‬ﺑﻪ ﻣﺜﺎل زﻳﺮ ﻧﮕﺎه ﻛﻨﻴﺪ‪ .‬اﻳﻦ ﻣﺜﺎل اﻋﺪاد ‪ 1‬ﺗﺎ ‪ 10‬را‬ ‫ﭼﺎپ ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int i = 1‬‬ ‫);;(‪for‬‬ ‫{‬ ‫)‪if(10 < i‬‬ ‫;‪break‬‬ ‫;‪cout<< i << endl‬‬ ‫;‪i++‬‬ ‫}‬

‫‪91‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬ ‫‪7‬‬ ‫‪8‬‬ ‫‪9‬‬ ‫‪10‬‬

‫در ا‪ for(;;) / 01‬ﻣﻌﺎدل اﺳﺖ ﺑﺎ );‪ for(;true‬ﻛﻪ در آن دو دﺳﺘﻮر ‪ `a‬ﺑﻪ ﻛﺎر رﻓﺘﻪ‪ .‬در اﻳﻦ‬ ‫ﺑﺮﻧﺎﻣﻪ ﺣﻠﻘﻪي ‪ for‬آن ﻗﺪر ﺧﻄﻮط‬ ‫)‪if(10 < i‬‬ ‫;‪break‬‬ ‫;‪cout<< i << endl‬‬ ‫;‪i++‬‬

‫را اﺟﺮا ﻣﻲﻛﻨﺪ ﺗﺎ ﺑﻪ ‪ break‬ﺑﺮﺳﺪ و ﺑﻪ ﻣﺤﺾ رﺳﻴﺪن ﺑﻪ ‪ break‬از ﺣﻠﻘﻪ ﺧﺎرج ﻣﻲﺷﻮد‪ break .‬ﭘﺸﺖ ﻳﻚ‬ ‫‪ if‬ﭘﻨﻬﺎن ﺷﺪه و ‪ if‬ﻓﻘﻂ وﻗﺘﻲ اﺟﺎزهي اﺟﺮاي آن را ﻣﻲدﻫﺪ ﻛﻪ ‪ i‬از ‪ 10‬ﺑﻴﺶ ﺗﺮ ﺑﺎﺷﺪ‪ .‬ﻣﻘﺪار ‪ i‬در ﻫﺮ ﺑﺎر اﺟﺮا‬ ‫ﺑﻪ وﺳﻴﻠﻪي ‪ i++‬ﻳﻜﻲ زﻳﺎد ﻣﻲﺷﻮد ﺗﺎ ﻣﻘﺪارش از ‪ 10‬ﺑﻴﺶ ﺗﺮ ﺷﻮد‪.‬‬ ‫دﺳﺘﻮر دﻳﮕﺮي ﻫﻢ ﻫﺴﺖ ﺑﻪ ﻧﺎم ‪ .continue‬ﺗﻮﺿﻴﺢ اﻳﻦ دﺳﺘﻮر ﭘﻴﭽﻴﺪه ﺗﺮ اﺳﺖ‪ .‬ﺑﻪ ﻓﺮﻣﻮل ‪ for‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫)د‪456‬ر)‪23];(2‬ار‪;[/‬د‪456‬ر)‪for((1‬‬ ‫]د‪456‬ر)‪[(3‬‬

‫)ﻛﻪ ﻧﻮع دﺳﺘﻮرﻫﺎ را ﺑﺮاي ﺳﺎدﮔﻲ ﺣﺬف ﻛﺮدهام(‪ .‬اﻳﻦ ﺣﻠﻘﻪ ﭼﻨﺪﻳﻦ ﺑﺎر د‪456‬ر)‪ (3‬را ﺗﻜﺮار ﻣﻲﻛﻨﺪ‪ .‬اﻣﺎ اﮔﺮ‬ ‫‪ ِ control‬ﺑﺮﻧﺎﻣﻪ در د‪456‬ر)‪ (3‬ﺑﻪ دﺳﺘﻮر ‪ continue‬ﺑﺮﺳﺪ از ﻛﺎﻣﻞ ﻛﺮدن اﺟﺮاي د‪456‬ر)‪ (3‬ﻣﻨﺼﺮف‬ ‫ﻣﻲﺷﻮد و ﻓﺮض ﻣﻲﻛﻨﺪ اﺟﺮاي د‪456‬ر)‪ (3‬ﻛﺎﻣﻞ ﺷﺪه‪ .‬ﻫﻴﭻ ﭼﻴﺰ دﻳﮕﺮي ﺗﻐﻴﻴﺮ ﻧﻤﻲﻛﻨﺪ‪ .‬ﻣﺜﻼ ﭘﺲ از اﻳﻦ ﻛﻪ‬ ‫د‪456‬ر)‪ (3‬ﻛﺎﻣﻞ ﺷﺪه ﻓﺮض ﺷﺪ‪ ،‬د‪456‬ر)‪ (2‬اﺟﺮا ﻣﻲﺷﻮد و ‪23‬ار‪ /‬ﭼﻚ ﻣﻲﺷﻮد‪ .‬ﻣﺜﺎل زﻳﺮ ﻫﻤﻪ ﭼﻴﺰ را‬ ‫روﺷﻦ ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬

‫‪92‬‬

‫‪www.pupuol.com‬‬


â€Ťď­˜ď­˜ďť? ﺎďş&#x; ﺊďş?ﺸﺎ ďť­ ﺪﺭﺳ‏ { for(int i = 0; i < 10; i++) { if( i % 2 == 0) // if i is even continue; cout<< i << endl; } getch(); }

Output: 1 3 5 7 9

‍ زŮˆŘŹ اﺳďş– ﺧ‏i 8H‍ Ů„ Ůˆâ€ŹF 01‍دع ا‏ cout<< i << endl;

‍ ŘŻŘą Ůˆا‏.‍ عﺳﺪ Ůˆ ďť“عا اďş&#x;ﺎاŮŠ ďş‘ďť ďťŽŮƒ عا ďş˜ďť—ďť’ ďť›ﺪ‏continue ‍ Ů? ďş‘ﺎﺎ ďş‘‏control ‍اďş&#x;ﺎا ﺡد زﺎا‏ ‍ ďşœďťź ďş‘ﺎﺎŮŠ ďť—ďş’ďťž عا ďş—ان ďş‘ ا ﺝعت ﺡďş– Ůˆ ďş‘ ďş&#x;ﺎي‏.‍ ﺡﺒﺎďş– داعد‏return ‍ ďş‘ ŘŻďşłďş˜ع‏continue :‍ اﺳďş˜ďť”ďşŽŘŻŮ‡ ďť›ﺎد‏return ‍ از‏continue #include <conio.h> #include <iostream> using namespace std; void block(int& i) { if( i % 2 == 0) // if i is even return; cout<< i << endl; } int main() { for(int i = 0; i < 10; i++) block(i); getch(); }

Output: 1 3 5 7 9

93

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ا‪ / 01‬ه‪ 3‬ن ‪ LMH , /‬ا‪ C4‬ا‪ E 01‬ق ‪ I!J‬از ‪ for‬ﺑﻪ ﻳﻚ ﺗﺎﺑﻊ ﺗﺒﺪﻳﻞ ﺷﺪه‪ .‬در اﻳﻦ ﺟﺎ‬ ‫دﻳﮕﺮ ﻧﻤﻲﺗﻮاﻧﻴﻢ از ‪ continue‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ وﻟﻲ ﺑﺎ ‪ return‬ﺗﻮاﻧﺴﺘﻪاﻳﻢ ﻫﻤﺎن ﻛﺎري را ﺑﻜﻨﻴﻢ ﻛﻪ‬ ‫‪ continue‬ﻣﻲﻛﺮد‪ .‬وﻗﺘﻲ در ﻳﻚ ﺗﺎﺑﻊ ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ ﺑﻪ ‪ return‬ﻣﻲرﺳﺪ اﺟﺮاي ﺗﺎﺑﻊ را ﻣﺘﻮﻗﻒ ﻣﻲﻛﻨﺪ و‬ ‫از آن ﺧﺎرج ﻣﻲﺷﻮد‪.‬‬

‫‪while F‬‬

‫ﺣﻠﻘﻪي ‪ while‬ﺣﺎﻟﺖ ﺧﺎﺻﻲ از ﺣﻠﻘﻪي ‪ for‬اﺳﺖ‪ .‬ﻓﺮﻣﻮل آن ﻋﺒﺎرت اﺳﺖ از‬ ‫)‪23‬ار‪while(/‬‬ ‫]د‪456‬ر د‪4t‬ا‪[/‬‬

‫و ﻛﺎر آن ﻫﻤﺎن ﻛﺎري اﺳﺖ ﻛﻪ‬ ‫);‪23‬ار‪for(;/‬‬ ‫]د‪456‬ر د‪4t‬ا‪[/‬‬

‫اﻧﺠﺎم ﻣﻲدﻫﺪ‪ .‬ﻳﻌﻨﻲ ﺗﺎ زﻣﺎﻧﻲ ﻛﻪ ‪23‬ار‪ /‬درﺳﺖ اﺳﺖ‪] ،‬د‪456‬ر د‪4t‬ا‪ [/‬اﺟﺮا ﻣﻲﺷﻮد‪.‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int i = 0‬‬ ‫)‪while(i < 10‬‬ ‫{‬ ‫;"‪cout<< "statement\n‬‬ ‫;‪i++‬‬ ‫}‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪statement‬‬ ‫‪statement‬‬ ‫‪statement‬‬ ‫‪statement‬‬ ‫‪statement‬‬ ‫‪statement‬‬ ‫‪statement‬‬ ‫‪statement‬‬ ‫‪statement‬‬ ‫‪statement‬‬

‫‪94‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ‪ while‬ﺗﺎ زﻣﺎﻧﻲ ﻛﻪ ‪ i‬ﻛﻢ ﺗﺮ از ‪ 10‬اﺳﺖ‪ ،‬ﺧﻄﻮط‬ ‫{‬ ‫;"‪cout<< "statement\n‬‬ ‫;‪i++‬‬ ‫}‬

‫را اﺟﺮا ﻣﻲﻛﻨﺪ‪.‬‬ ‫دﺳﺘﻮرﻫﺎي ‪ break‬و ‪ continue‬ﻫﻢ ﻣﺎﻧﻨﺪ ﻗﺒﻞ در ‪ while‬ﻗﺎﺑﻞ اﺳﺘﻔﺎدهاﻧﺪ‪.‬‬

‫‪do … while F‬‬

‫ﻓﺮﻣﻮل اﻳﻦ ﺣﻠﻘﻪ ﻋـﺒﺎرت اﺳﺖ از‬ ‫‪do‬‬ ‫]د‪456‬ر د‪4t‬ا‪[/‬‬ ‫;)‪23‬ار‪while(/‬‬

‫و اﻳﻦ ﻣﻌﺎدل اﺳﺖ ﺑﺎ‬ ‫);;(‪for‬‬ ‫{‬ ‫]د‪456‬ر د‪4t‬ا‪[/‬‬ ‫)‪23‬ار‪if(!/‬‬ ‫;‪break‬‬ ‫}‬

‫در واﻗﻊ ]د‪456‬ر د‪4t‬ا‪ [/‬ره ا* ا =!د ‪ 6‬ز ‪23 /‬ار‪ / /‬در‪!= C4‬د‪.‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int i = 1‬‬ ‫‪do‬‬ ‫{‬ ‫;‪cout<< i << endl‬‬ ‫;‪i++‬‬ ‫}‬ ‫;)‪while(i < 10‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬

‫‪95‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬ ‫‪7‬‬ ‫‪8‬‬ ‫‪9‬‬

‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺧﻄﻮط‬ ‫{‬ ‫;‪cout<< i << endl‬‬ ‫;‪i++‬‬ ‫}‬

‫ﺗﺎ زﻣﺎﻧﻲ ﻛﻪ ‪ i‬ﻛﻢ ﺗﺮ از ‪ 10‬اﺳﺖ‪ ،‬اﺟﺮا ﻣﻲﺷﻮﻧﺪ‪ .‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﺑﻪ ﺟﺎي‬ ‫‪do‬‬ ‫{‬ ‫;‪cout<< i << endl‬‬ ‫;‪i++‬‬ ‫}‬ ‫;)‪while(i < 10‬‬

‫ﻧﻤﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫‪do‬‬ ‫;‪cout<< i << endl‬‬ ‫;‪i++‬‬ ‫;)‪while(i < 10‬‬

‫وﻟﻲ ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫‪do‬‬ ‫;‪cout<< i << endl, i++‬‬ ‫;)‪while(i < 10‬‬

‫ﻛﻪ دﺳﺘﻮرﻫﺎ ﺑﺎ »‪ «,‬ﺗﺮﻛﻴﺐ ﺷﺪهاﻧﺪ‪.‬‬ ‫ﺧﺎﺻﻴﺖ ﻣﻬﻢ ﺣﻠﻘﻪي ‪ do … while‬اﻳﻦ اﺳﺖ ﻛﻪ دﺳﺖ ﻛﻢ ﻳﻚ ﺑﺎر ]د‪456‬ر د‪4t‬ا‪ [/‬اﺟﺮا ﻣﻲﺷﻮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪do‬‬ ‫;"‪cout<< "statement\n‬‬ ‫;)‪while(false‬‬

‫‪96‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ getch(); }

Output: statement

:‫ ﻫﻢ ﻗﺎﺑﻞ اﺳﺘﻔﺎدهاﻧﺪ‬do … while ‫ در‬continue ‫ و‬break ‫دﺳﺘﻮرﻫﺎي‬ #include <conio.h> #include <iostream> using namespace std; int main() { int i = 0; do { i++; if(i > 10) break; if( i % 2 == 0) // if i is even continue; cout<< i << endl; } while(1); getch(); }

Output: 1 3 5 7 9

.‫ ﺑﻪ ﻋﻨﻮان ﮔﺰارهاي درﺳﺖ اﺳﺘﻔﺎده ﻛﺮدهام‬1 ‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ از‬

‫ ه‬G

:‫اﮔﺮ ﺑﻨﻮﻳﺴﻴﻢ‬ const int a = 10;

97

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫آن وﻗﺖ ‪ a‬ﺟﺎﻳﻲ از ﺣﺎﻓﻈﻪ اﺳﺖ ﻛﻪ ﻣﻘﺪار آن ‪ 10‬اﺳﺖ وﻟﻲ اﻳﻦ ﻣﻘﺪار ﻗﺎﺑﻞ ﺗﻐﻴﻴﺮ ﻧﻴﺴﺖ )دﺳﺖ ﻛﻢ ﺗﺎ زﻣﺎﻧﻲ ﻛﻪ‬ ‫ﺑﻪ وﺳﻴﻠﻪي ‪ a‬ﺑﻪ آن اﺷﺎره ﺷﻮد(‪ .‬در واﻗﻊ از ‪ a‬ﻣﻲﺷﻮد ﻣﺜﻞ ﻳﻚ ﻣﺘﻐﻴﺮ ﻣﻌﻤﻮﻟﻲ اﺳﺘﻔﺎده ﻛﺮد ﺑﻪ اﻳﻦ ﺷﺮط ﻛﻪ ﻣﻘﺪار‬ ‫آن ﺗﻐﻴﻴﺮ ﻧﻜﻨﺪ‪ .‬ﺑﻪ ﻫﻤﻴﻦ ﻋﻠﺖ ﺑﻪ ‪ a‬ﻳﻚ ﺛﺎﺑﺖ ﺑﺎ ﻧﻮع ‪ int‬ﻣﻲﮔﻮﻳﻨﺪ‪ .‬از ﻫﺮ ﻧﻮﻋﻲ ﻣﻲﺗﻮاﻧﻴﻢ ﺛﺎﺑﺖ داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﻣﺜﻼ‬ ‫;'‪const char ch = 'a‬‬

‫ﻧﻜﺘﻪي دﻳﮕﺮ اﻳﻦ اﺳﺖ ﻛﻪ ﻳﻚ ﺛﺎﺑﺖ ﺣﺘﻤﺎ ﺑﺎﻳﺪ ‪ initialize‬ﺷﻮد ﻳﻌﻨﻲ ﺑﺎﻳﺪ ﺑﻪ آن ﻣﻘﺪار اوﻟﻴﻪ داد )ﻓﻜﺮ ﻣﻲﻛﻨﻴﺪ‬ ‫ﭼﺮا؟(‪ .‬ﺑﻪ ﻣﺜﺎل زﻳﺮ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫;‪const int a = 4‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪const int b‬‬ ‫= ]‪char c[b‬‬ ‫<< ‪cout<< a‬‬ ‫<< ‪cout<< b‬‬ ‫;‪cout<< c‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫;‪= a‬‬ ‫;"‪"abc‬‬ ‫;‪endl‬‬ ‫;‪endl‬‬

‫‪Output:‬‬ ‫‪4‬‬ ‫‪4‬‬ ‫‪abc‬‬

‫ﻃﺒﻖ آن ﭼﻴﺰي ﻛﻪ ﮔﻔﺘﻢ ‪4i n\ const int‬ع اﺳﺖ‪ .‬ﻳﻚ ‪ pointer‬ﺑﻪ اﻳﻦ ‪4i‬ع ﻃﺒﻖ ﻣﻌﻤﻮل ﺑﻪ ﺷﻜﻞ‬ ‫*‪ const int‬اﺳﺖ‪ .‬اﻣﺎ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﺧﻮد ‪ pointer‬ﺛﺎﺑﺖ ﺑﺎﺷﺪ )ﻧﻪ ﻣﻘﺪاري ﻛﻪ ﺑﻪ آن اﺷﺎره ﻣﻲﻛﻨﺪ( ﻣﻲﺗﻮاﻧﻴﻢ‬ ‫ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪int a‬‬ ‫;‪int* const p = &a‬‬

‫در اﻳﻦ ﺻﻮرت ﻣﻘﺪار ‪ p‬را ﻧﻤﻲﺷﻮد ﺗﻐﻴﻴﺮ داد اﻣﺎ ‪ *p‬را ﻣﻲﺷﻮد‪.‬‬ ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ از ﻳﻚ ‪ ِ pointer‬ﺛﺎﺑﺖ و از ﻳﻚ ‪ pointer‬ﺑﻪ ﻳﻚ ﺛﺎﺑﺖ اﺳﺘﻔﺎده ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪//--------------------------- part 1‬‬ ‫;'‪const char ch1 = 'a‬‬

‫‪98‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪const char* p = &ch1‬‬ ‫‪// *p = 'x'; // error‬‬ ‫'‪cout<< *p; // 'a‬‬ ‫‪//--------------------------‬‬‫;"‪cout<< "\n‬‬ ‫‪//--------------------------- part 2‬‬ ‫;'‪char ch2 = 'b‬‬ ‫;‪char * const q = &ch2‬‬ ‫‪// q = "hello"; // error‬‬ ‫;'‪*q ='y‬‬ ‫'‪cout<< *q; // 'y‬‬ ‫‪//--------------------------‬‬‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪a‬‬ ‫‪y‬‬

‫ﻣﻘﺪار ‪ *p‬را ﻧﻤﻲﺷﻮد ﺗﻐﻴﻴﺮ داد ﭼﻮن ‪ *p‬ﻳﻚ ﺛﺎﺑﺖ اﺳﺖ‪ .‬ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ '‪ comment out ،*p='x‬ﺷﺪه‬ ‫اﺳﺖ‪ .‬ﻣﻘﺪار ‪ q‬را ﻫﻢ ﻧﻤﻲﺷﻮد ﻋﻮض ﻛﺮد ﭼﻮن ‪ q‬ﺧﻮدش ﻳﻚ ﺛﺎﺑﺖ اﺳﺖ اﻣﺎ ‪ *q‬ﻳﻚ ﺛﺎﺑﺖ ﻧﻴﺴﺖ ﺑﺮاي ﻫﻤﻴﻦ‬ ‫ﻣﻘﺪارش را ﺗﻮاﻧﺴﺘﻪام ﻋﻮض ﻛﻨﻢ‪.‬‬ ‫ﺣﺎل ﺑﻪ ﻣﺜﺎل زﻳﺮ و ﻧﺘﻴﺠﻪي ﻋﺠﻴﺐ آن ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪const int a = 4‬‬ ‫;‪int* const q = (int*) &a‬‬ ‫;‪*q = 5‬‬ ‫;‪cout<< *(&a) << endl‬‬ ‫;‪cout<< a‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪5‬‬ ‫‪4‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫‪4‬‬ ‫‪4‬‬ ‫ﻣﻦ ﺗﻮﺟﻴﻪ ﻣﻨﺎﺳﺒﻲ ﺑﺮاي اﻳﻦ ﻧﺘﻴﺠﻪ ﻧﺪارم‪ .‬ﺷﻤﺎ ﭼﻪ ﻃﻮر؟ ﺛﺎﺑﺖ ‪ a‬ﻣﻘﺪار ‪ 4‬دارد‪ &a .‬ﻛﻪ ﻧﻮﻋﺶ *‪const int‬‬

‫اﺳﺖ ﺑﻪ ‪ int* cast‬ﺷﺪه و در ‪ ِ pointer‬ﺛﺎﺑﺖ ‪ q‬ﻗﺮار ﮔﺮﻓﺘﻪ‪ .‬ﺣﺎﻻ ﺑﻪ ﻧﻈﺮ ﻣﻲآﻳﺪ ‪ *q‬ﺑﺎﻳﺪ ﻫﻤﺎن ‪ a‬ﺑﺎ ﻫﻤﺎن‬

‫‪99‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻣﻜﺎن ﺣﺎﻓﻈﻪ ﺑﺎﺷﺪ‪ .‬ﻣﻘﺪار ‪ *q‬را ﻋﻮض ﻛﺮدهام‪ *(&a).‬و ‪ a‬را ﻛﻪ ﺣﺘﻤﺎ ﺑﺎﻳﺪ ﻳﻜﺴﺎن ﺑﺎﺷﻨﺪ ﭼﺎپ ﻛﺮدهام‪BDS .‬‬ ‫‪ 2006‬دو ﻣﻘﺪار ﻣﺘﻔﺎوت را ﭼﺎپ ﻣﻲﻛﻨﺪ‪ .‬اﺧﺘﻼف ﻧﺘﺎﻳﺞ دو اﻳﻦ ‪ compiler‬ﻣﻌﺮوف ﻧﺸﺎن ﻣﻲدﻫﺪ ﻛﻪ ﺧﻮد ﺑﻪ‬ ‫وﺟﻮد آورﻧﺪﮔﺎن ‪compiler‬ﻫﺎ ﺗﺼﻮر ﻛﺎﻣﻠﻲ از ‪ pointer‬ﺑﻪ ﺛﺎﺑﺖﻫﺎ ﻧﺪارﻧﺪ‪ .‬ﻫﻤﻴﻦ ﻣﺜﺎل را ﺗﻐﻴﻴﺮ دادهام و ﺑﻪ ﺟﺎي‬ ‫;‪cout<< *(&a) << endl‬‬

‫ﻧﻮﺷﺘﻪام‪:‬‬ ‫;‪const int* w = &a‬‬ ‫;‪cout<< *(w) << endl‬‬

‫ﻛﻪ ﻇﺎﻫﺮا ﺑﺎ ﻫﻢ ﻫﻴﭻ ﻓﺮﻗﻲ ﻧﺪارﻧﺪ‪ ،‬ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﺑﻪ دﺳﺖ آﻣﺪه‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪const int a = 4‬‬ ‫;‪int* const q = (int*) &a‬‬ ‫;‪*q = 5‬‬ ‫;‪const int* w = &a‬‬ ‫;‪cout<< *(w) << endl‬‬ ‫;‪cout<< a‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬ ‫‪4‬‬

‫ﺧﺮوﺟﻲ ‪ Visual C++ 2005‬ﺗﻐﻴﻴﺮ ﻣﻲﻛﻨﺪ و ﻫﺮ دو ‪ compiler‬ﻳﻚ ﻧﺘﻴﺠﻪ دارﻧﺪ‪ .‬اﻳﻦ ﺟﻮر ﻧﺘﺎﻳﺞ ﻧﺸﺎن ﻣﻲ‪-‬‬ ‫دﻫﻨﺪ ﻛﻪ ﺷﺎﻳﺪ آن ﭼﻪ ‪ compiler‬اﻧﺠﺎم ﻣﻲدﻫﺪ ﺑﺎ ﺗﺼﻮرﻫﺎي ﺳﺎدهي ﻣﺎ از ﻣﻜﺎنﻫﺎي ﺣﺎﻓﻈﻪ ﻛﻪ ﺑﻪ ﻣﺘﻐﻴﺮﻫﺎ ﻧﺴﺒﺖ‬ ‫داده ﻣﻲﺷﻮد ﭘﻴﭽﻴﺪه ﺗﺮ اﺳﺖ و ﺑﻪ ‪compiler‬ﻫﺎ واﺑﺴﺘﮕﻲ زﻳﺎدي دارد‪ .‬در ﻫﺮ ﺣﺎل ﺗﺼﻮرﻫﺎي ﺳﺎده ﺑﻬﺘﺮ از آن‬ ‫اﺳﺖ ﻛﻪ ﻫﻴﭻ ﺗﺼﻮري ﻧﺪاﺷﺘﻪ ﺑﺎﺷﻴﻢ‪.‬‬ ‫اﮔﺮ ﻋﺪد‪ ،‬رﺷﺘﻪ و‪ ...‬ﻣﺴﺘﻘﻴﻤﺎ در ﻣﺘﻦ ﺑﺮﻧﺎﻣﻪ ﻇﺎﻫﺮ ﺑﺸﻮﻧﺪ )ﻣﺜﻞ ‪ 4‬و ‪ 5‬در ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ( ﻧﻮﻋﻲ ﺛﺎﺑﺖ ﺑﻪ ﺣﺴﺎب ﻣﻲ‪-‬‬ ‫آﻳﻨﺪ ﻛﻪ ﺑﻪ آنﻫﺎ اﺻﻄﻼﺣﺎ ﺛﺎﺑﺖ ‪ literal‬ﻳﺎ ‪ literal constant‬ﮔﻔﺘﻪ ﻣﻲﺷﻮد‪ .‬ﻣﺜﻼ ﺧﻮد "‪ "hello‬وﻗﺘﻲ در‬ ‫ﻣﺘﻦ ﺑﺮﻧﺎﻣﻪ ﻇﺎﻫﺮ ﻣﻲﺷﻮد ﻳﻚ ﺛﺎﺑﺖ ‪ literal‬اﺳﺖ‪ .‬ﺑﻪ ﺛﺎﺑﺖﻫﺎﻳﻲ ﻛﻪ ﭘﻴﺶ از اﻳﻦ ﮔﻔﺘﻴﻢ و ‪ literal‬ﻧﻴﺴﺘﻨﺪ‬ ‫‪ symbolic constant‬ﻣﻲﮔﻮﻳﻨﺪ‪ .‬در ‪ C++‬اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻧﻮع ‪ a‬را ﻣﺸﺨﺺ ﻛﻨﻴﻢ ﺑﺎ ‪،cout‬‬ ‫)(‪ typeid(a).name‬را ﭼﺎپ ﻣﻲﻛﻨﻴﻢ‪ .‬ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻧﺸﺎن ﻣﻲدﻫﺪ ﻛﻪ ﻣﻤﻜﻦ اﺳﺖ ‪ compiler‬ﻧﻮع ﺛﺎﺑﺖﻫﺎ‬ ‫را واﻗﻌﺎ ﺛﺎﺑﺖ ﻧﺪاﻧﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬

‫‪100‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ using namespace std; int main() { const int a = 5; cout<< typeid(a).name() << endl; cout<< typeid(&a).name() << endl; cout<< typeid("hello").name(); _getch(); }

Output(BDS 2006): int const int * char[6] Output(Visual C++ 2005): int int const * char const [6]

‫ اﺳﺖ در ﺣﺎﻟﻲ ﻛﻪ ﻣﺎ ﻣﻲداﻧﻴﻢ‬int ،a ‫ ﻫﺮ دو ﻣﻲﮔﻮﻳﻨﺪ ﻧﻮع‬Visual C++ 2005 ‫ و‬BDS 2006 ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬ 6 ‫ ﻋﻠﺖ اﻳﻦ ﻛﻪ آراﻳﻪ‬.‫ ﻣﻌﺮﻓﻲ ﺷﺪه اﺳﺖ‬6 ‫ﻫﺎ ﺑﺎ ﻃﻮل‬char ‫" آراﻳﻪاي از‬hello" ‫ ﻧﻮع‬.‫ اﺳﺖ‬const int .‫ ﻫﻢ ﻫﺴﺖ‬0 ‫ ﺗﺎﻳﻲ اﻳﻦ اﺳﺖ ﻛﻪ آﺧﺮ ﻫﺮ رﺷﺘﻪ ﻳﻚ ﻛﺎراﻛﺘﺮ‬5 ‫ﺗﺎﻳﻲ اﺳﺖ ﻧﻪ‬ .int const * ‫ ﻧﻮﺷﺘﻪ‬Visual C++ ‫ و‬const int * ‫ ﻧﻮﺷﺘﻪ‬BDS 2006 ‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ‬

switch ‫" ر‬#‫د‬

‫ﻓﺮﻣﻮل اﻳﻦ دﺳﺘﻮر ﻋﺒﺎرت اﺳﺖ از‬ switch([int n\]) { case [int ‫ع‬4i Zd (1)ydZz]: [/‫د‬Z6،b4cd،`a (1)‫ر‬456‫]د‬ case [int ‫ع‬4i Zd (2)ydZz]: [/‫د‬Z6،b4cd،`a (2)‫ر‬456‫]د‬ . . case [int ‫ع‬4i Zd (n)ydZz]: [/‫د‬Z6،b4cd،`a (n)‫ر‬456‫]د‬ [default:

101

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫]]د‪456‬ر)‪Z6،b4cd،`a (n+1‬د‪[/‬‬ ‫}‬ ‫اﻳﻦ دﺳﺘﻮر ﺑﻪ ﺗﺮﺗﻴﺐ از ﺑﺎﻻ ﺑﻪ ﭘﺎﻳﻴﻦ ﺑﻪ دﻧﺒﺎل اوﻟﻴﻦ ‪ ِ ydZz‬ﺑﻌﺪ از ﻫﺮ ‪ case‬ﻣﻲﮔﺮدد ﻛﻪ ﺑﺎ ]\‪[int n‬‬

‫ﻣﺴﺎوي ﺑﺎﺷﺪ‪ .‬اﮔﺮ ﭘﻴﺪا ﻛﺮد‪ ،‬از آن ﺟﺎ ﺑﻪ ﺑﻌﺪ ﻫﻤﻪي د‪456‬رﻫﺎي ﺑﻌﺪ از ﻫﺮ ‪ case‬و ﺑﻌﺪ از ‪) default‬در‬ ‫ﺻﻮرت وﺟﻮد( اﺟﺮا ﻣﻲﺷﻮﻧﺪ‪ .‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﮔﺬاﺷﺘﻦ ‪ default‬ﺿﺮوري ﻧﻴﺴﺖ‪ .‬اﮔﺮ ﺗﺎ زﻣﺎﻧﻲ ﻛﻪ ﺑﻪ‬ ‫‪ default‬ﻣﻲرﺳﺪ ﭘﻴﺪا ﻧﻜﺮده ﺑﺎﺷﺪ ﺗﻨﻬﺎ دﺳﺘﻮرات ﭘﺲ از ‪ default‬اﻧﺠﺎم ﻣﻲﺷﻮد‪ .‬اﮔﺮ ‪ default‬وﺟﻮد‬ ‫ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ و ‪ case‬ﻣﻨﺎﺳﺐ ﻫﻢ ﭘﻴﺪا ﻧﺸﻮد ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ از ‪ switch‬ﺧﺎرج ﻣﻲﺷﻮد‪.‬‬ ‫ﺑﻪ ﻣﺜﺎلﻫﺎي زﻳﺮ ﻧﮕﺎه ﻛﻨﻴﺪ‪ .‬ﺧﺮوﺟﻲ آنﻫﺎ ﻫﻤﻪ ﭼﻴﺰ را ﺗﻮﺿﻴﺢ ﻣﻲدﻫﺪ‪ .‬در ﺿﻤﻦ آن ﭼﻪ در اﻳﻦ ﻣﺜﺎلﻫﺎ ﻣﻲﺑﻴﻨﻴﺪ‬ ‫ﻓﺮاﺗﺮ از ﻓﺮﻣﻮل ﺑﺎﻻﺳﺖ‪ .‬اﮔﺮ در ﻣﻮرد ﻛﺎرﻛﺮد ﻫﺮ ﻛﺪام ﺷﻚ داﺷﺘﻴﺪ آن را را در ‪ compiler‬ﺧﻮد آرام و ﺧﻂ ﺑﻪ‬ ‫ﺧﻂ اﺟﺮا ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a = 10‬‬ ‫)‪switch(a‬‬ ‫{‬ ‫‪case 9:‬‬ ‫;‪cout<< "case 9" << endl‬‬ ‫‪case 11:‬‬ ‫;‪cout<< "case 11" << endl‬‬ ‫‪case 10:‬‬ ‫;‪cout<< "case 10" << endl‬‬ ‫‪case 100:‬‬ ‫;‪cout<< "case 100" << endl‬‬ ‫}‬ ‫;"‪cout<< "end of switch‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪case 10‬‬ ‫‪case 100‬‬ ‫‪end of switch‬‬

‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻣﻘﺪار ‪ a‬ﺑﺮاﺑﺮ ﺑﺎ ‪ 10‬اﺳﺖ و ﺑﻨﺎﺑﺮاﻳﻦ دﺳﺘﻮرات ﻣﻮﺟﻮد در ‪ switch‬ﻛﻪ ﺑﻌﺪ از‬ ‫‪case 10:‬‬

‫ﻗﺮار دارﻧﺪ اﺟﺮا ﻣﻲﺷﻮد‪.‬‬ ‫‪102‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

#include <conio.h> #include <iostream> using namespace std; int main() { int a = 10; switch(a) { case 101: cout<< "case 101" << endl; case 11: case 10: case 100: cout<< "cases 11, 10, 100" << endl; } cout<< "end of switch"; _getch(); }

Output: cases 11, 10, 100 end of switch

#include <conio.h> #include <iostream> using namespace std; int main() { int a = 10; switch(a) { default: cout<< "default" << endl; case 10: cout<< "case 10" << endl; } cout<< "end of switch"; _getch(); }

Output: case 10 end of switch

#include <conio.h> #include <iostream>

103

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ using namespace std; int main() { int a = 10; switch(a) { default: cout<< "default" << endl; case 11: cout<< "case 11" << endl; } cout<< "end of switch"; _getch(); }

Output: default case 11 end of switch #include <conio.h> #include <iostream> using namespace std; int main() { int a = 10; switch(a) { cout<< "before cases"; case 9: int b; b = 5; cout<< "case 9" << endl; case 10: int a = 2; cout<< "case 10" << endl; cout<< b << endl; } cout<< "end of switch"; _getch(); }

Output: case 10 256 end of switch

‫اﮔﺮ در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﺟﺎي‬ int b; b = 5;

104

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺑﻨﻮﻳﺴﻴﺪ‬ ‫;‪int b = 5‬‬

‫‪ compiler‬ﻳﻚ ‪ error‬ﻣﻲﮔﻴﺮد زﻳﺮا ‪case‬ي ﻛﻪ ‪ b‬در آن ﺗﻌﺮﻳﻒ ﻣﻲﺷﻮد اﺻﻼ اﺟﺮا ﻧﻤﻲﺷﻮد‪ .‬و ﺑﻨﺎﺑﺮاﻳﻦ ‪b‬‬

‫ﻗﺎﺑﻞ ‪ initialize‬ﺷﺪن ﻧﻴﺴﺖ‪ .‬اﻣﺎ ﺗﻌﺮﻳﻒ ﺑﺪون ‪ initialize‬ﻛﺮدن اﻣﻜﺎن ﭘﺬﻳﺮ اﺳﺖ زﻳﺮا ﻣﻌﻤﻮﻻ ﺣﺎﻓﻈﻪي ﻻزم‬ ‫ﺑﺮاي ﻣﺘﻐﻴﺮﻫﺎ در ﺷﺮوع ‪ block‬ﺗﺨﺼﻴﺺ داده ﻣﻲﺷﻮد ﻧﻪ در ﺣﻴﻦ اﺟﺮاي دﺳﺘﻮرات ‪ block‬دﻗﻴﻘﺎ ﻣﺜﻞ آن ﭼﻴﺰي‬ ‫ﻛﻪ در ‪ pascal‬راﻳﺞ اﺳﺖ‪) .‬از روي ﺗﻌﺼﺐ و ﻋﻼﻗﻪ ﺑﻪ ‪ C++‬ﻣﻲﮔﻮﻳﻢ ﻛﻪ زﺑﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ‬ ‫در ﻣﻘﺎﺑﻞ ‪C‬‬

‫ﻳﺎ‬

‫زﺑﺎنﻫﺎي ﻣﻬﻤﻲ ﻧﻴﺴﺘﻨﺪ‬

‫‪ delphi‬در ﺑﺮاﺑﺮ ‪C++‬‬

‫‪pascal‬‬

‫(‪.‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫)(‪int main‬‬ ‫{‬ ‫)‪switch(5‬‬ ‫‪case 5:‬‬ ‫;"‪cout<< "case 5‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪case 5‬‬

‫ﻣﺎﻧﻨﺪ ﺣﻠﻘﻪﻫﺎ‪ ،‬در ‪ switch‬ﻫﻢ ﻣﻲﺷﻮد از دﺳﺘﻮر ‪ break‬اﺳﺘﻔﺎده ﻛﺮد و اﺳﺘﻔﺎده از آن ﺑﺎﻋﺚ ﺧﺮوج از‬ ‫‪ switch‬ﻣﻲﺷﻮد‪ .‬اﺳﺘﻔﺎده از ‪ break‬در ﭘﺎﻳﺎن ﻫﺮ ‪ case‬ﺑﺴﻴﺎر ﻣﺘﺪاول اﺳﺖ ﭼﻮن ﺑﺎﻋﺚ ﻣﻲﺷﻮد ﻛﻪ ﻓﻘﻂ ﻳﻚ‬ ‫‪ case‬اﺟﺮا ﺷﻮد و ‪case‬ﻫﺎي ﺑﻌﺪي اﺟﺮا ﻧﺸﻮﻧﺪ‪.‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫)‪switch(5‬‬ ‫{‬ ‫‪case 5:‬‬ ‫;"‪cout<< "case 5‬‬ ‫;‪break‬‬ ‫‪case 4:‬‬ ‫;"‪cout<< "case 4‬‬ ‫;‪break‬‬ ‫‪default:‬‬ ‫{‬

‫‪105‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪int a = 4‬‬ ‫;‪cout<< a‬‬ ‫;‪break‬‬ ‫}‬ ‫}‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪case 5‬‬

‫د‪ "#‬ر ‪goto‬‬

‫درون ﻳﻚ ﺗﺎﺑﻊ ا‪ 01‬د‪!84‬ر ﻣﻲﺗﻮاﻧﺪ ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ را ﺑﻪ ﺟﺎي دﻳﮕﺮي از ﺗﺎﺑﻊ ﺑﻔﺮﺳﺘﺪ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﺟﺎﻳﻲ از‬ ‫ﺗﺎﺑﻊ ﻋﻼﻣﺖ ﮔﺬاري ﺑﺸﻮد ﺗﺎ ﺑﺘﻮاﻧﻴﻢ ‪ control‬را آن ﺟﺎ ﺑﻔﺮﺳﺘﻴﻢ‪ ،‬ﺑﺎﻳﺪ از ‪ label‬اﺳﺘﻔﺎده ﻛﺮد )‪ label‬ﺷﺒﻴﻪ ﺑﻪ‬ ‫‪ bookmark‬در ‪ Microsoft Word‬ﻳﺎ ﺑﺮﻧﺎﻣﻪﻫﺎي دﻳﮕﺮ اﺳﺖ(‪ .‬ﺑﺮاي اﻳﺠﺎد ﻳﻚ ‪ label‬اول ﻳﻚ اﺳﻢ ﺑﺮاي‬ ‫آن اﻧﺘﺨﺎب ﻣﻲﻛﻨﻴﻢ آن اﺳﻢ را در ﻣﺤﻞ ﻣﻮرد ﻧﻈﺮ از ﺗﺎﺑﻊ ﺗﺎﻳﭗ ﻣﻲﻛﻨﻴﻢ و ﭘﺲ از آن »‪ «:‬ﻣﻲﮔﺬارﻳﻢ‪ .‬ﻓﺮﻣﻮل‬ ‫‪ goto‬ﺑﻪ ﺷﻜﻞ زﻳﺮ اﺳﺖ‪:‬‬ ‫;]\‪goto [label n‬‬

‫ﻣﺜﺎل زﻳﺮ ﻧﺤﻮهي اﺳﺘﻔﺎده از ‪ goto‬را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int i = 1‬‬ ‫;‪int sum = 0‬‬ ‫‪REP:‬‬ ‫;‪sum = sum + i‬‬ ‫;‪i++‬‬ ‫)‪if(i <= 10‬‬ ‫;‪goto REP‬‬ ‫;‪cout<< sum‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪55‬‬

‫‪106‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺟﻤﻊ اﻋﺪاد ‪ 1‬ﺗﺎ ‪ 10‬را ﭘﻴﺪا و ﭼﺎپ ﻣﻲﻛﻨﺪ‪ .‬اﮔﺮ در ﻣﻮرد ﻧﺤﻮهي ﻛﺎر آن ﺷﻚ دارﻳﺪ آن را ﻗﺪم ﺑﻪ ﻗﺪم‬ ‫اﺟﺮا ﻛﻨﻴﺪ‪ REP .‬در اﻳﻦ ﺟﺎ \‪ label n‬اﺳﺖ‪.‬‬ ‫در ﺷﺮح ﺑﺪي دﺳﺘﻮر ‪ goto‬زﻳﺎد ﮔﻔﺘﻪ ﻣﻲﺷﻮد‪ .‬ﮔﻔﺘﻪ ﻣﻲﺷﻮد ﻛﻪ ﺧﻮاﻧﺎﻳﻲ و ﻣﺮﺗﺐ ﺑﻮدن ﺑﺮﻧﺎﻣﻪ ﺑﺎ دﺳﺘﻮر ‪goto‬‬

‫از ﺑﻴﻦ ﻣﻲرود‪ .‬زﻳﺎد ﺑﻪ ﻛﺎر ﺑﺮدن ‪ ،goto‬ﺑﺮﻧﺎﻣﻪ را آن ﻗﺪر ﺗﻮ در ﺗﻮ ﻣﻲﻛﻨﺪ ﻛﻪ ﻣﺜﻞ اﺳﭙﺎﮔﺘﻲ ﻣﻲﺷﻮد‪Jesse .‬‬ ‫‪ Liberty‬ﻧﻮﻳﺴﻨﺪهي ﭘﺮ ﻓﺮوش ﺗﺮﻳﻦ ﻛﺘﺎبﻫﺎي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ در ﻳﻜﻲ از ﻛﺘﺎبﻫﺎي ﺧﻮد ﻣﻲﻧﻮﻳﺴﺪ‪:‬‬ ‫آﻣﻮزﮔﺎران ﻋﻠﻢ ﻛﺎﻣﭙﻴﻮﺗﺮ ‪ 20‬ﺳﺎل ﮔﺬﺷﺘﻪ را ﺻﺮف ﻓﺮو ﻛﺮدن ﻳﻚ ﺣﺮف در ﺳﺮ داﻧﺶ آﻣﻮزان ﺧﻮد ﻛﺮدهاﻧﺪ‪:‬‬ ‫»ﻫﺮﮔﺰ و ﻫﺮﮔﺰ از دﺳﺘﻮر ﺷﻴﻄﺎﻧﻲ ‪ goto‬اﺳﺘﻔﺎده ﻧﻜﻨﻴﺪ«‬ ‫”!‪“Never, ever, ever use goto! It is evil‬‬ ‫ﺑﺎ وﺟﻮد ﻫﻤﻪي اﻳﻦﻫﺎ ﻣﻦ ﻓﻜﺮ ﻣﻲﻛﻨﻢ اﺳﺘﻔﺎده از ‪ goto‬ﺑﻌﻀﻲ ﺟﺎﻫﺎ اﺟﺘﻨﺎب ﻧﺎﭘﺬﻳﺮ اﺳﺖ‪ .‬ﻣﺜﻼ اﮔﺮ درون دو‬ ‫ﺣﻠﻘﻪي ﺗﻮ در ﺗﻮ ﺑﺎﺷﻴﻢ ﺑﺮاي ﺧﺮوج ﻫﻢ زﻣﺎن از ﻫﺮ دو ﻧﻤﻲﺗﻮاﻧﻴﻢ از ‪ break‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ break .‬ﺗﻨﻬﺎ از ﻳﻜﻲ‬ ‫ﺧﺎرج ﻣﻲﺷﻮد‪.‬‬ ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﺗﻼش ﻣﻲﻛﻨﺪ اﻋﺪاد ﺻﺤﻴﺢ و و را ﻃﻮري ﭘﻴﺪا ﻛﻨﺪ ﻛﻪ در ﻣﻌﺎدﻟﻪي رﻳﺎﺿﻲ ‪،‬‬ ‫ﺻﺪق ﻛﻨﻨﺪ ﺑﺎ اﻳﻦ ﺷﺮط ﻛﻪ ‪ .‬ﺑﻪ آن دﻗﺖ ﻛﻨﻴﺪ اﻣﺎ ﺧﻴﻠﻲ وﻗﺖ ﺻﺮف آن ﻧﻜﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int r, i, j‬‬ ‫)‪for(r = 600; r <= 1400; r++‬‬ ‫{‬ ‫;‪i = j = 0‬‬ ‫)‪while(true‬‬ ‫{‬ ‫)‪if (i * i + j * j < r‬‬ ‫;‪i++‬‬ ‫‪else‬‬ ‫)‪if (i * i + j * j > r‬‬ ‫{‬ ‫;‪i--‬‬ ‫;‪j++‬‬ ‫}‬ ‫‪else‬‬ ‫;‪goto END‬‬ ‫)‪if(i < 0‬‬ ‫;‪break‬‬

‫‪107‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ } // while } // for END: cout<< r << endl; cout<< i << endl; cout<< j << endl; _getch(); }

Output: 601 24 5

. ‫اﻳﻦ ﺧﺮوﺟﻲ ﻳﻌﻨﻲ‬ (‫ در ﻓﻀﺎي ﻋﻤﻮﻣﻲ )ﻳﻌﻨﻲ ﺧﺎرج از ﻫﺮ ﺗﺎﺑﻊ‬.‫ از ﺗﺎﺑﻌﻲ ﺑﻪ ﺗﺎﺑﻊ دﻳﮕﺮ ﭘﺮﻳﺪ‬goto ‫در ﭘﺎﻳﺎن ﻣﻲﮔﻮﻳﻢ ﻛﻪ ﻧﻤﻲﺷﻮد ﺑﺎ‬ .‫ ﺑﮕﺬارﻳﻢ‬label n\ ‫ﻫﻢ ﻧﻤﻲﺗﻮاﻧﻴﻢ‬

typedef ‫ و‬typeid ‫ و‬sizeof ‫ ه‬

‫ ﺑﺎ ﻛﻠﻤﻪي ﻛﻠﻴﺪي‬.‫ع را ﻣﺸﺨﺺ ﻛﻨﻴﻢ‬4i n\ ‫ ﻣﻲﺗﻮاﻧﻴﻢ ﺗﻌﺪاد ﺑﺎﻳﺖﻫﺎي ﻳﻚ ﻣﺘﻐﻴﺮ ﻳﺎ‬sizeof ‫ﺑﺎ ﻛﻠﻤﻪي ﻛﻠﻴﺪي‬ ‫ ﺑﺮﻧﺎﻣﻪي زﻳﺮ اﺳﺘﻔﺎدهﻫﺎي اﺑﺘﺪاﻳﻲ اﻳﻦ دو‬.‫ع را ﻣﺸﺨﺺ ﻛﺮد‬4i n\ ‫ ﻣﻲﺷﻮد اﺳﻢ ﻧﻮع ﻳﻚ ﻣﺘﻐﻴﺮ ﻳﺎ اﺳﻢ‬typeid :‫ﻛﻠﻤﻪ را ﻧﺸﺎن ﻣﻲدﻫﺪ‬ #include <conio.h> #include <iostream> using namespace std; int main() { double a = 2.365; cout<< sizeof(double) << endl; cout<< sizeof(a) << endl; cout<< typeid(double).name() << endl; cout<< typeid(a).name() << endl; cout<< typeid(sizeof(a)).name() << endl; getch(); }

Output: 8 8 double double

108

www.pupuol.com


тАлянШя╗оянШя╗оя╗Э я╗гя║оя║Яя╗К я║йя║Ня╗зя║╕яоХя║Оя╗й я╗н я╗гя║кя║ня║│я╗ктАм unsigned int

тАл я╗│я╗Мя╗ия╗▓ я╗│я╗Ъ я╗гя║Шя╗Ря╗┤я║отАм.тАл ╪зя║│я║ЦтАм8 тАл я╗гя╗Шя║к╪з╪▒ я╗ля║о я╗Ыя║к╪з┘ЕтАм.тАл я╗│я╗Ья╗▓ я╗ля║┤я║Шя╗ия║ктАмsizeof(a) тАл ┘ИтАмsizeof(double) тАл╪п╪▒ ╪зя╗│я╗ж я║Ся║оя╗зя║Оя╗гя╗ктАм тАл ╪▒╪зтАмa тАл" ╪зя║│я║Ц я╗Ыя╗к я╗зя╗о╪╣тАмdouble" тАл ╪▒я║╖я║Шя╗к┘КтАм╪Мtypeid(a).name() .тАл я╗ля║╕я║Ц я║Ся║Оя╗│я║Ц ╪зя║│я║ЦтАмdouble тАля║Ся║О я╗зя╗о╪╣тАм .тАля╗гя║╕я║ия║║ я╗гя╗▓я╗Ыя╗ия║ктАм Visual тАл ╪зя║Яя║о╪з я╗гя╗▓я║╖я╗о╪п ┘Ия╗Яя╗▓ ╪п╪▒тАмBDS 2006 тАл я║Ся║оя╗зя║Оя╗гя╗к┘К ╪▓я╗│я║о ╪п╪▒тАм.тАл я║Чя╗оя║Яя╗к я╗Ыя╗ия╗┤я║ктАмsizeof тАля║гя║Оя╗╗ я║Ся╗к я╗Ыя║О╪▒я║Ся║о╪п ╪пя╗│яоХя║о┘К ╪з╪▓тАм :тАл ╪зя║Яя║о╪з я╗зя╗дя╗▓я║╖я╗о╪птАмC++ 2005 #include <conio.h> #include <iostream> using namespace std; int main() { int a[] ={1,2,3,4,5,6,7,8,9}; cout<< sizeof(a)/sizeof(int) << endl; cout<< sizeof((int*)a)/sizeof(int) << endl; int*& p = a; cout<< sizeof(p) <<endl; char c[] = "hello"; cout<< sizeof(c)/ sizeof(char) << endl; getch();

// output 9 // output 9 // output 4 // output 6

}

Output (BDS 2006): 9 9 4 6

тАл ╪▒╪з я╗│я╗ЪтАмp ┘Р pointer тАл я║Ся╗Мя║ктАм.тАл ╪▒╪з ян╝я║О┘╛ я╗гя╗▓я╗Ыя╗ия╗┤я╗втАмa тАл я║Чя╗Мя║к╪з╪п я╗Ля╗ия║Оя║╗я║о ╪в╪▒╪зя╗│я╗к┘КтАмsizeof тАл╪п╪▒ ╪зя╗│я╗ж я║Ся║оя╗зя║Оя╗гя╗к я║Ся║О ╪зя║│я║Шя╗Фя║О╪п┘З ╪з╪▓тАм p тАл ╪зя╗гя║О я╗гя╗▓я║Ся╗┤я╗ия╗┤я╗в я╗Ыя╗к я║Ся║ОтАм.тАл я╗│я╗Ья╗▓ я║Ся║Оя║╖я║ктАмa тАл ╪з╪┤ ┘ЗтАмNE O тАл ┘ЖтАмP PJ тАл я╗гя╗▓яоФя╗┤я║оя╗│я╗в я║Чя║О я╗зя╗к я║Чя╗ия╗мя║О я╗гя╗Шя║к╪з╪▒╪┤тАмa тАл я║Ся╗ктАмreference

тАл я║Ся║оя╗зя║Оя╗гя╗к ╪▒╪з я║Чя╗Ря╗┤я╗┤я║о я╗гя╗▓╪пя╗ля╗┤я╗в ┘И я║Ся╗к я║Яя║О┘КтАм.тАл( янШя╗┤я║к╪з я╗Ыя║о╪птАмsizeof тАл ╪▒╪з )я║Ся║ОтАмa тАля╗зя╗дя╗▓я║╖я╗о╪п я║Чя╗Мя║к╪з╪п я╗Ля╗ия║Оя║╗я║отАм int*& p = a;

:тАля╗гя╗▓я╗зя╗оя╗│я║┤я╗┤я╗втАм int* p = a;

:тАл я╗ля╗в я╗Чя║Оя║Ся╗Ю ╪зя║Яя║о╪з я║Ся║Оя║╖я║ктАмVisual C++ 2005 тАля║Чя║О ╪п╪▒тАм #include <conio.h> #include <iostream> using namespace std; int main() { int a[] ={1,2,3,4,5,6,7,8,9};

109

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪// output 9‬‬ ‫‪// output 1 or 9‬‬ ‫‪// output 4‬‬ ‫‪// output 6‬‬

‫;‪sizeof(a)/sizeof(int) << endl‬‬ ‫;‪sizeof((int*)a)/sizeof(int) << endl‬‬ ‫;‪= a‬‬ ‫;‪sizeof(p) <<endl‬‬

‫<<‪cout‬‬ ‫<<‪cout‬‬ ‫‪int* p‬‬ ‫<<‪cout‬‬

‫;"‪char c[] = "hello‬‬ ‫;‪cout<< sizeof(c)/ sizeof(char) << endl‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪9‬‬ ‫‪9‬‬ ‫‪4‬‬ ‫‪6‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫‪9‬‬ ‫‪1‬‬ ‫‪4‬‬ ‫‪6‬‬

‫اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻫﻤﺎن ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ اﺳﺖ وﻟﻲ اﻳﻦ ﺑﺎر ‪ p reference‬ﻧﻴﺴﺖ‪ .‬ﺑﻪ اﺧﺘﻼف ﺧﺮوﺟﻲ دو ‪ compiler‬ﺗﻮﺟﻪ‬ ‫ﻛﻨﻴﺪ‪.‬‬ ‫ﺧﺮوﺟﻲ ‪ Microsoft‬در اﻳﻦ ﺟﺎ و در ﺑﻴﺶ ﺗﺮ ﻣﻮارد اﺧﺘﻼف ﺑﺮاي ﻣﻦ ﻗﺎﺑﻞ ﻗﺒﻮل ﺗﺮ از ﺧﺮوﺟﻲ ‪Borland‬‬ ‫اﺳﺖ‪ .‬ﺑﺎ اﻳﻦ ﺣﺎل ﻣﻦ ‪compiler‬ﻫﺎي ‪ Borland‬را ﺗﺮﺟﻴﺢ ﻣﻲدﻫﻢ ﭼﻮن ﻋﻼوه ﺑﺮ ‪ Editor‬ﺑﻬﺘﺮ ﺑﺮاي ﺑﺮﻧﺎﻣﻪ‬ ‫ﻧﻮﻳﺴﻲ‪ ،‬اﻣﻜﺎﻧﺎت ﻛﺎﻣﻞ ﺗﺮي دارﻧﺪ و ﺳﺨﺖ ﮔﻴﺮي آنﻫﺎ ﻛﻢ ﺗﺮ اﺳﺖ‪) .‬ﻛﻼ در ﻫﻤﻪي ﻧﺮم اﻓﺰارﻫﺎي ‪Microsoft‬‬ ‫ﺧﺴﺎﺳﺘﻲ آزار دﻫﻨﺪه ﭘﻴﺪاﺳﺖ‬

‫ﮔﺮﭼﻪ ‪ Microsoft‬در ﺗﻮزﻳﻊ ﻧﺮم اﻓﺰارﻫﺎي ﺧﻮد ﺳﺨﺎوﺗﻤﻨﺪاﻧﻪ ﻋﻤﻞ ﻣﻲﻛﻨﺪ‬

‫)ﻣﺜﻼ ﻧﺮم اﻓﺰارﻫﺎي راﻳﮕﺎن زﻳﺎدي ﭘﺨﺶ ﻣﻲﻛﻨﺪ و ﺣﺘﻲ ﺑﻪ ‪ Windows‬ﻫﺎي ﻛﭙﻲ ﺷﺪه ﺳﺮوﻳﺲ ﻣﻲدﻫﺪ((‪.‬‬ ‫ﺗﻮﺟﻪ ﺑﻪ اﻳﻦ ﻧﻜﺘﻪ ﻫﻢ ﺿﺮوري اﺳﺖ ﻛﻪ ﻇﺎﻫﺮا ﻛﺎر اﺻﻠﻲ ‪ Borland‬اﻳﺠﺎد ﻧﺮم اﻓﺰارﻫﺎي ﻣﺮﺑﻮط ﺑﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ‬ ‫اﺳﺖ اﻣﺎ ﻛﺎر اﺻﻠﻲ ‪ Microsoft‬ﺗﻮﻟﻴﺪ ﺳﻴﺴﺘﻢ ﻋﺎﻣﻞ اﺳﺖ‪.‬‬ ‫ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ typedef‬ﺑﺮاي ﺗﻐﻴﻴﺮ اﺳﻢ ‪4i‬عﻫﺎ ﺑﻪ ﻛﺎر ﻣﻲرود‪ .‬ﻣﺜﻼ ﺷﺎﻳﺪ ﻧﻮﺷﺘﻦ ‪ unsigned int‬ﺑﺮاي‬ ‫ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻣﻨﺎﺳﺐ ﻧﺒﺎﺷﺪ و او ﺑﺨﻮاﻫﺪ اﺳﻢ ﻛﻮﺗﺎه ﺗﺮي را ﺑﻪ ﺟﺎي آن ﺑﮕﺬارد‪ .‬اﮔﺮ ﺑﺨﻮاﻫﺪ ‪ UINT‬را ﺑﻪ ﺟﺎي آن‬ ‫ﺑﮕﺬارد ﻣﻲﺗﻮاﻧﺪ از ‪ typedef‬اﺳﺘﻔﺎده ﻛﻨﺪ و ﺑﻨﻮﻳﺴﺪ‪:‬‬ ‫;‪typedef unsigned int UNIT‬‬

‫ﺑﻪ اﻳﻦ ﻣﺜﺎل ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬

‫‪110‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <iostream> using namespace std; int main() { typedef unsigned int UINT; UINT a = 5; cout<< a << endl; cout<< typeid(UINT).name(); getch(); }

Output: 5 unsigned int typedef ‫ ﺑﺮاي اﻳﻦ ﻛﻪ ﺷﻜﻞ ﻛﺎرﺑﺮد‬.‫ ﻳﻜﻲ ﻣﻲﮔﻴﺮد‬unsigned int ‫ را ﺑﺎ‬UINT ،typeid ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬

‫ در ﻛﻨﺎر ﻫﻢ‬int ‫ و‬unsigned ،typedef ‫را ﺑﻪ ﺧﺎﻃﺮ ﺑﺴﭙﺎرﻳﺪ ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ در ﻣﺜﺎل ﺑﺎﻻ ﻛﻠﻤﻪﻫﺎي ﻛﻠﻴﺪي‬ :‫ اﻳﻦ ﻣﺜﺎل را ﻧﮕﺎه ﻛﻨﻴﺪ‬.‫ﻗﺮار دارﻧﺪ‬ #include <conio.h> #include <iostream> struct TAG { int a; }; typedef TAG INT,* PINT; using namespace std; int main() { INT a; PINT p = &a; a.a = 2; cout<< a.a << endl; cout<< typeid(a.a).name() << endl; cout<< typeid(p).name() << endl; cout<< typeid(PINT).name() << endl; getch(); }

Output (BDS 2006): 2 int TAG * TAG * Output (Visual C++ 2005): 2 int

111

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ struct TAG * struct TAG *

‫در ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ ﺑﻪ ﺟﺎي‬ struct TAG { int a; }; typedef TAG INT,* PINT;

:‫ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‬ typedef struct TAG { int a; } INT,* PINT;

:‫ را ﺣﺬف ﻛﺮد و ﺑﺮﻧﺎﻣﻪ را ﺑﻪ اﻳﻦ ﺻﻮرت ﺗﻐﻴﻴﺮ داد‬TAG ‫ ﻣﻲﺷﻮد ﻛﻠﻤﻪي‬،‫ ﺣﺘﻲ ﺳﺎده ﺗﺮ‬.‫و ﺧﺮوﺟﻲ ﺗﻐﻴﻴﺮ ﻧﻤﻲﻛﻨﺪ‬ #include <conio.h> #include <iostream> typedef struct { int a; } INT,* PINT; using namespace std; int main() { INT a; PINT p = &a; a.a = 2; cout<< a.a << endl; cout<< typeid(a.a).name() << endl; cout<< typeid(p).name() << endl; cout<< typeid(PINT).name() << endl; getch(); }

Output (BDS 2006): 2 int INT * INT * Output (Visual C++ 2005): 2 int struct INT * struct INT *

112

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ :‫ﻣﺜﺎل زﻳﺮ ﻫﻢ ﺟﺎﻟﺐ اﺳﺖ‬ #include <conio.h> #include <iostream> using namespace std; int f(int a,int b) { cout<< a + b; return 0; } int main() { cout<< typeid(f).name() << endl; _getch(); }

Output (BDS 2006): int (*)(int,int) Output (Visual C++ 2005): int __cdecl(int,int)

.‫__ ﺗﻮﺿﻴﺢ ﺧﻮاﻫﻢ داد‬cdecl ‫ﺑﻌﺪا در ﻣﻮرد ﻣﻌﻨﻲ‬ :‫ اﻃﻼﻋﺎﺗﻲ در ﻣﻮرد آراﻳﻪﻫﺎ ﺑﻪ دﺳﺖ ﺑﻴﺎورﻳﻢ‬typeid ‫ﺣﺎﻻ ﺑﮕﺬارﻳﺪ ﺑﺎ‬ #include <conio.h> #include <iostream> using namespace std; int main() { cout<< typeid(new double [2]).name() << endl; char c[12]; cout<< typeid(c).name() << endl; char d[] = "hello"; cout<< typeid(d).name() << endl; _getch(); }

Output(BDS 2006): double * char[12] char[6]

113

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ Output(Visual C++ 2005): double * char [12] char [6]

default-int 8!H ‫و‬

Microsoft ‫ را ﭘﺸﺘﻴﺒﺎﻧﻲ ﻣﻲﻛﻨﻨﺪ اﻣﺎ‬default-int ‫ وﻳﮋﮔﻲ‬Borland ‫ﻫﺎي‬compiler ‫ﻧﺴﻞﻫﺎي ﻣﺨﺘﻠﻒ‬ ‫ اﻳﻦ اﺳﺖ ﻛﻪ در ﻫﺮ ﺟﺎ اﺑﻬﺎﻣﻲ‬default-int ‫ وﻳﮋﮔﻲ‬.‫ اﻳﻦ وﻳﮋﮔﻲ را ﭘﺸﺘﻴﺒﺎﻧﻲ ﻧﻤﻲﻛﻨﺪ‬Visual C++ 2005 ‫ ﺧﻮدش آن را در ﻧﻈﺮ ﻣﻲﮔﻴﺮد ﻣﺜﻼ ﺑﻪ ﺟﺎي‬compiler ‫ را ﻧﻨﻮﻳﺴﻴﻢ و‬int ‫وﺟﻮد ﻧﺪارد ﻣﻲﺗﻮاﻧﻴﻢ ﻛﻠﻤﻪي‬ const int a = 3;

:‫ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻢ‬ const a = 3;

‫و ﺑﻪ ﺟﺎي‬ int f(int a, char ch) { … }

:‫ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‬ f(a, char ch) { … }

:‫ ﻗﺎﺑﻞ اﺟﺮاﺳﺖ‬Borland ‫ﻫﺎي‬compiler ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ در‬ #include <conio.h> #include <iostream> using namespace std; const M = 4; f(a, b) { cout<< a+b << endl; cout<< typeid(a).name() << endl; return a*b; } int main() { cout<< f(2, 3); getch(); }

Output: 5

114

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪int‬‬ ‫‪6‬‬

‫در ﻣﻮرد ﻓﺮم ﭘﺎراﻣﺘﺮﻫﺎي ﺗﺎﺑﻊ ‪ f‬در ﺑﺎﻻ ﺣﺘﻲ ‪ Borland‬دو ﺗﺎ ‪ warning‬ﻣﻲﮔﻴﺮد )ﻳﻌﻨﻲ ﺻﺎدر ﻣﻲﻛﻨﺪ‬

‫(‪.‬‬

‫ﺑﺮاي رﻓﻊ آنﻫﺎ ﻛﺎﻓﻲ اﺳﺖ ﺟﻠﻮي ﭘﺎراﻣﺘﺮﻫﺎي ‪ a‬و ‪ int ، b‬ﺑﮕﺬارﻳﻢ‪.‬‬

‫‪ LValue‬و ‪RValue‬‬

‫ﻗﺒﻼ در ﻣﻮرد ﻋﻤﻠﮕﺮ = ﭼﻴﺰﻫﺎﻳﻲ ﮔﻔﺘﻢ‪ .‬ﮔﻔﺘﻢ ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;‪int a‬‬ ‫;‪a = 2‬‬

‫اﻣﺎ اﮔﺮ ﺑﻨﻮﻳﺴﻴﺪ‪:‬‬ ‫;‪2 = a‬‬

‫‪error‬ي ﺻﺎدر ﻣﻲﺷﻮد ﭼﻮن ‪ 2‬ﻧﻤﻲﺗﻮاﻧﺪ ﺳﻤﺖ ﭼﭗ ﺗﺴﺎوي ﻗﺮار ﺑﮕﻴﺮد‪ .‬در اﻳﻦ ﺣﺎﻟﺖ ﻣﻲﮔﻮﻳﻴﻢ ‪ 2‬ﻳﻚ‬ ‫‪ LValue‬ﻧﻴﺴﺖ )‪ L‬ﻣﺨﻔﻒ ‪ Left‬ﺑﻪ ﻣﻌﻨﻲ »ﭼﭗ« اﺳﺖ(‪ .‬ﺑﻪ ﭼﻴﺰي ﻛﻪ )ﺗﻨﻬﺎ( ﻣﻲﺗﻮاﻧﺪ ﺳﻤﺖ راﺳﺖ ﺗﺴﺎوي ﻗﺮار‬ ‫ﮔﻴﺮد ﻳﻚ ‪ RValue‬ﻣﻲﮔﻮﻳﻨﺪ )‪ R‬ﻣﺨﻔﻒ ‪ Right‬ﺑﻪ ﻣﻌﻨﻲ »راﺳﺖ« اﺳﺖ(‪ 2 .‬و ﻫﺮ ﺛﺎﺑﺖ دﻳﮕﺮي ‪LValue‬‬ ‫ﻧﻴﺴﺖ‪ .‬اﮔﺮ ‪ a‬و ‪ b‬ﻣﺘﻐﻴﺮﻫﺎﻳﻲ ﺑﺎ ﻧﻮع ‪ int‬ﺑﺎﺷﻨﺪ‪ a+b ،‬ﻳﻚ ‪ LValue‬ﻧﻴﺴﺖ‪ .‬ﺑﻪ ﺗﺎﺑﻊ زﻳﺮ ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫)‪int f(int a‬‬ ‫{‬ ‫;‪a++‬‬ ‫;‪return a‬‬ ‫}‬

‫ﺣﺎل اﮔﺮ ‪ x‬ﻳﻚ ﻣﺘﻐﻴﺮ ﺑﺎ ﻧﻮع ‪ int‬ﺑﺎﺷﺪ‪ f(x) ،‬ﻳﻚ ‪ LValue‬ﻧﻴﺴﺖ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﺑﺎﺷﺪ ﺑﺎﻳﺪ ﻳﻚ & ﭘﺲ ﻫﺮ‬ ‫‪ int‬ﺑﮕﺬارﻳﻢ ﻳﻌﻨﻲ ﺗﻌﺮﻳﻒ ﺗﺎﺑﻊ را ﺑﻪ ﺻﻮرت زﻳﺮ ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﻢ‪:‬‬ ‫)‪int& f(int& a‬‬ ‫{‬ ‫;‪a++‬‬ ‫;‪return a‬‬ ‫}‬

‫ﻣﺜﺎل زﻳﺮ از اﻳﻦ ﺗﺎﺑﻊ اﺳﺘﻔﺎده ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪int& f(int& a‬‬ ‫{‬ ‫;‪a++‬‬ ‫;‪return a‬‬

‫‪115‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a = 3‬‬ ‫;‪cout<< f(a) << endl‬‬ ‫;‪f(a) = 300‬‬ ‫;‪cout<< a‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪4‬‬ ‫‪300‬‬

‫در ﺣﻘﻴﻘﺖ در ﺗﺎﺑﻊ )(‪ main‬ﻣﺘﻐﻴﺮ ‪ a‬ﻧﻤﺎﻳﻨﺪهي ﻫﻤﺎن ﺟﺎﻳﻲ از ﺣﺎﻓﻈﻪ اﺳﺖ ﻛﻪ )‪ f(a‬ﻧﻤﺎﻳﻨﺪهي آن اﺳﺖ‪ .‬ﺑﺮاي‬ ‫ﻳﺎدآوري ﻣﻲﮔﻮﻳﻢ ﻛﻪ اﮔﺮ در ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ ﺗﻌﺮﻳﻒ ﺗﺎﺑﻊ ‪ f‬ﺑﻪ ﺷﻜﻞ زﻳﺮ ﻧﻮﺷﺘﻪ ﺑﺸﻮد‪:‬‬ ‫)‪int& f(int a‬‬ ‫{‬ ‫;‪a++‬‬ ‫;‪return a‬‬ ‫}‬

‫ﺑﺮﻧﺎﻣﻪ اﺟﺮا ﻧﻤﻲﺷﻮد ﭼﻮن ‪ a‬ﺗﻨﻬﺎ در ﺗﺎﺑﻊ ‪ f‬ﻣﻌﺘﺒﺮ اﺳﺖ وﻟﻲ )‪ f(a‬ﻛﻪ ﻫﻤﺎن ‪) a‬ﺑﺎ ﻫﻤﺎن ﺣﺎﻓﻈﻪ( اﺳﺖ ﺑﺎﻳﺪ در‬ ‫)(‪ main‬ﻫﻢ ﻣﻌﺘﺒﺮ ﺑﺎﺷﺪ‪ .‬اﮔﺮ ﺑﺨﻮاﻫﻴﻢ اﻳﻦ ﺗﺎﺑﻊ ‪ error‬اﻳﺠﺎد ﻧﻜﻨﺪ ﻳﺎ ﺟﻠﻮي ﻫﺮ دو ‪ int‬ﺑﺎﻳﺪ & ﺑﮕﺬارﻳﻢ ﻳﺎ ﺟﻠﻮ‬ ‫ﻫﻴﭻ ﻛﺪام )ﺑﺎﻳﺪ ﺑﻪ اﻳﻦ ﻣﺴﺄﻟﻪ آن ﻗﺪر ﻓﻜﺮ ﻛﻨﻴﺪ ﻛﻪ ﺑﺘﻮاﻧﻴﺪ آن را ﺑﻪ ﺧﻮﺑﻲ ﺗﻮﺟﻴﻪ ﻛﻨﻴﺪ!‬

‫(‪.‬‬

‫‪& ' prototype‬ه و ' &ه ز!‪8"5‬‬

‫اﮔﺮ ﺗﺎﺑﻊ )(‪ f‬ﭘﻴﺶ از ﺗﺎﺑﻊ )(‪ g‬ﺗﻌﺮﻳﻒ ﺷﺪه ﺑﺎﺷﺪ ﻧﻤﻲﺗﻮاﻧﺪ )(‪ g‬را ﻓﺮا ﺑﺨﻮاﻧﺪ‪ .‬ﺑﻪ ﻧﺎﭼﺎر ﺑﺎﻳﺪ )(‪ g‬را ﻗﺒﻞ از‬ ‫)(‪ f‬ﺗﻌﺮﻳﻒ ﻛﺮد‪ .‬اﻣﺎ اﮔﺮ ﺗﺎﺑﻊ )(‪ g‬ﻫﻢ ﺑﺨﻮاﻫﺪ )(‪ f‬را ﻓﺮا ﺑﺨﻮاﻧﺪ ﺑﺎﻳﺪ ﭼﻪ ﻛﺎر ﻛﺮد؟ ﭼﺎرهي ﻛﺎر اﺳﺘﻔﺎده از‬ ‫‪ prototype‬اﺳﺖ‪ ِ prototype .‬ﻳﻚ ﺗﺎﺑﻊ ﻋﺒﺎرت اﺳﺖ از ﺧﺮوﺟﻲ‪ ،‬اﺳﻢ و ﻧﻮع ﭘﺎراﻣﺘﺮﻫﺎي ﻳﻚ ﺗﺎﺑﻊ و »;«‪.‬‬ ‫ﻣﺜﻼ ﺑﺮاي ﺗﺎﺑﻊ‬ ‫)‪int f(int a, double b‬‬ ‫{‬ ‫;‪cout<< a + b‬‬ ‫;‪return a‬‬ ‫}‬

‫ﻣﻲﺷﻮد ‪prototype‬ﻫﺎي زﻳﺮ را در ﻧﻈﺮ ﮔﺮﻓﺖ‪:‬‬ ‫;)‪int f(int a, double b‬‬ ‫;)‪int f(int x, double y‬‬

‫‪116‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ int f(int , double y); int f(int, double);

:‫ اﻳﻦ ﻣﺜﺎل را ﺑﺒﻴﻨﻴﺪ‬.‫ ﺑﺎ ﻫﻢ ﻓﺮﻗﻲ ﻧﺪارﻧﺪ‬prototype ‫و اﻳﻦﻫﺎ ﺑﻪ ﻋﻨﻮان‬ #include <conio.h> #include <iostream> using namespace std; int f(int v,int); int main() { f(5,5); _getch(); } int f(int a,int b) { cout<< a +b; return a; }

Output: 10

.‫ اﺳﺘﻔﺎده ﻣﻲﻛﻨﺪ‬f() ‫ ﻣﻲﺗﻮاﻧﺪ از‬main() ،‫ ﻧﻮﺷﺘﻪ ﺷﺪه‬main() ‫ ﻗﺒﻞ از‬f() ِ prototype ‫ﭼﻮن‬ :‫ﻣﺜﺎل زﻳﺮ ﭘﻴﭽﻴﺪه ﺗﺮ اﺳﺖ‬ #include <conio.h> #include <iostream> using namespace std; void f(bool); // can be commented out void g(bool); void f(bool a) { if(a) { cout<< "f does not call g\n"; return; } else { cout<< "f calls g\n"; g(!a); cout<< "g called\n"; } } void g(bool b) {

117

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ cout<< "g calls f\n"; f(b); cout<< "f called\n"; } int main() { g(false); cout<< "g called\n"; _getch(); }

Output: g calls f f calls g g calls f f does not call g f called g called f called g called

.‫ ﺳﻌﻲ ﻛﻨﻴﺪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ را ﺧﻮب ﺗﺤﻠﻴﻞ ﻛﻨﻴﺪ‬.‫ را ﻓﺮا ﻣﻲﺧﻮاﻧﺪ‬f() ،g() ‫ را و‬g() ،f() ‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ‬ ‫ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ‬.‫ ﻣﻲﺗﻮاﻧﺪ ﭼﻨﺪ ﺑﺎر ﻗﺒﻞ و ﺑﻌﺪ از ﺗﻌﺮﻳﻒ و ﺣﺘﻲ درون ﺗﺎﺑﻊﻫﺎي دﻳﮕﺮ ﺗﻜﺮار ﺷﻮد‬prototype ‫ﻳﻚ‬ ‫ اﺳﺘﻔﺎده ﻛﺮدهاﻳﻢ ﺗﺎ‬prototype ‫ ﻧﻴﺴﺖ اﻣﺎ در ﻣﺜﺎل زﻳﺮ از‬prototype ‫ﻳﻚ ﺗﺎﺑﻊ ﺧﻮدش را ﻓﺮا ﺑﺨﻮاﻧﺪ ﻧﻴﺎزي ﺑﻪ‬ :‫ ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‬main() ‫ﺑﺘﻮاﻧﻴﻢ ﺗﺎﺑﻊ را ﺑﻌﺪ از‬ #include <conio.h> #include <iostream> using namespace std; int main() { void f(bool a); // a prototype f(false); _getch(); } void f(bool a) { if(a == true) cout<<"true\n"; else { cout<<"false\n"; f(true); } }

Output: false

118

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪true‬‬ ‫در اﻳﻦ ﻣﺜﺎل ‪ f() ِ prototype‬درون ﺗﺎﺑﻊ )(‪ main‬ﻧﻮﺷﺘﻪ ﺷﺪه و ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﺗﻨﻬﺎ در ﺗﺎﺑﻊ )(‪main‬‬

‫ﻣﻌﺘﺒﺮ اﺳﺖ‪ .‬ﺗﺤﻠﻴﻞ اﻳﻦ ﺑﺮﻧﺎﻣﻪ از ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ آﺳﺎن ﺗﺮ اﺳﺖ ﻓﻘﻂ وﻗﺘﻲ در )(‪ f‬ﺑﻪ ﺧﻂ‬ ‫;)‪f(true‬‬

‫رﺳﻴﺪﻳﺪ ﮔﻴﺞ ﻧﺸﻮﻳﺪ اﻳﻦ ﺧﻂ در ﺗﺎﺑﻊ )(‪ f‬ﻫﻤﺎن ﻛﺎري را ﻣﻲﻛﻨﺪ ﻛﻪ اﮔﺮ در )(‪ main‬ﺑﻮد ﻣﻲﻛﺮد‪.‬‬ ‫ﺑﻪ ﺗﺎﺑﻌﻲ ﻛﻪ ﻣﺴﺘﻘﻴﻤﺎ ﻳﺎ ﺑﺎ واﺳﻄﻪ ﺧﻮدش را ﻓﺮاﻣﻲﺧﻮاﻧﺪ‪ ،‬ﺗﺎﺑﻊ ﺑﺎزﮔﺸﺘﻲ ﻣﻲﮔﻮﻳﻨﺪ‪ .‬ﺗﺎﺑﻊ ﺑﺎزﮔﺸﺘﻲ ﻳﻚ اﺑﺰار ﻗﻮي‬ ‫ﺑﺮاي ﻧﻮﺷﺘﻦ ﺧﻴﻠﻲ از ﺑﺮﻧﺎﻣﻪﻫﺎ اﺳﺖ‪ .‬ﻣﻤﻜﻦ وﻗﺘﻲ ﺑﺎ ﻗﺪرت ﺧﺎرق اﻟﻌﺎدهي ﺗﺎﺑﻊﻫﺎي ﺑﺎزﮔﺸﺘﻲ آﺷﻨﺎ ﺷﺪﻳﺪ‪) ،‬ﻣﺜﻞ ﻣﻦ(‬ ‫آن ﻗﺪر ﺷﻴﻔﺘﻪي آنﻫﺎ ﺑﺸﻮﻳﺪ ﻛﻪ ﺣﺘﻲ ﺑﺮاي ﻛﺎرﻫﺎي ﺧﻴﻠﻲ ﺳﺎده ﻫﻢ ﺑﻪ ﻓﻜﺮ آنﻫﺎ ﺑﻴﻔﺘﻴﺪ‪ .‬اﻳﻦ ﺧﻴﻠﻲ ﺧﻮب ﻧﻴﺴﺖ‬ ‫ﭼﻮن ﺑﻪ ﻛﺎر ﺑﺮدن ﺗﺎﺑﻊﻫﺎي ﺑﺎزﮔﺸﺘﻲ ﺑﺮﻧﺎﻣﻪ را ﭘﻴﭽﻴﺪه ﻣﻲﻛﻨﺪ و ﮔﺎﻫﻲ راهﻫﺎي ﺑﻬﺘﺮ و ﺑﺎ ﺻﺮﻓﻪ ﺗﺮي ﻫﺴﺖ‪ .‬ﺑﻬﺘﺮ‬ ‫اﺳﺖ ﻗﺒﻞ از اﺳﺘﻔﺎده از ﺗﺎﺑﻊﻫﺎي ﺑﺎزﮔﺸﺘﻲ ﺳﻌﻲ ﻛﻨﻴﻢ ﺑﺮﻧﺎﻣﻪ را ﺑﺎ ﺣﻠﻘﻪي ﺑﻲ ﻧﻬﺎﻳﺖ )ﻣﺜﻼ }…{)‪(while(true‬‬ ‫ﺑﻨﻮﻳﺴﻴﻢ اﮔﺮ ﻧﺸﺪ ﻳﺎ ﺧﻴﻠﻲ ﭘﻴﭽﻴﺪه ﺷﺪ ﺑﻌﺪ ﺑﻪ ﺳﺮاغ ﺗﺎﺑﻊﻫﺎي ﺑﺎزﮔﺸﺘﻲ ﻣﻲروﻳﻢ‪.‬‬ ‫ﺑﺮاي اﻳﻦ ﻛﻪ ﺑﺨﺸﻲ از ﻗﺪرت ﺗﺎﺑﻊﻫﺎي ﺑﺎزﮔﺸﺘﻲ را ﺑﻪ ﺷﻤﺎ ﻧﺸﺎن ﺑﺪﻫﻢ‪ ،‬ﻳﻚ ﺣﻠﻘﻪي ‪ while‬را ﺑﺎ ﺗﺎﺑﻊ ﺑﺎزﮔﺸﺘﻲ‬ ‫ﺟﺎﻳﮕﺰﻳﻦ ﻣﻲﻛﻨﻢ‪ .‬ﻣﺜﺎل زﻳﺮﺣﻠﻘﻪي ‪ while‬را ﺑﺮاي ﺟﻤﻊ ﻛﺮدن اﻋﺪاد ‪ 1‬ﺗﺎ ‪ 10‬ﺑﻪ ﻛﺎر ﻣﻲﮔﻴﺮد‪ .‬در اﻳﻦ ﻣﺜﺎل از‬ ‫ﻋﻤﻠﮕﺮ =‪ +‬اﺳﺘﻔﺎده ﺷﺪه ﻛﻪ درﺑﺎرهي آن ﭘﺲ ﻣﺜﺎل ﺗﻮﺿﻴﺢ ﻣﻲدﻫﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int n = 0‬‬ ‫;‪int sum = 0‬‬ ‫)‪while(n < 10‬‬ ‫{‬ ‫;‪n++‬‬ ‫;‪sum += n‬‬ ‫}‬ ‫;‪cout<< sum‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪55‬‬

‫‪119‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻣﻨﻈﻮر از ;‪ sum+=n‬ﻫﻤﺎن ‪ sum=sum+n‬اﺳﺖ در ﺿﻤﻦ ﺑﻪ ﺟﺎي ‪ a=a/b ،a=a*b‬و‪ ...‬ﻣﻲﺷﻮد ﻧﻮﺷﺖ‬ ‫‪ a/=b ،a*=b‬و‪ . ...‬ﺑﻪ ﺟﺎي ﺣﻠﻘﻪي ‪ while‬در ﺑﺎﻻ ﻣﻲﺷﻮد از ﻳﻚ ﺗﺎﺑﻊ ﺑﺎزﮔﺸﺘﻲ اﺳﺘﻔﺎده ﻛﺮد و ﺑﺮﻧﺎﻣﻪ را اﻳﻦ‬ ‫ﻃﻮري ﺗﻐﻴﻴﺮ داد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪void f(int& n, int& sum‬‬ ‫{‬ ‫)‪if(n < 10‬‬ ‫{‬ ‫;‪n++‬‬ ‫;‪sum += n‬‬ ‫;)‪f(n,sum‬‬ ‫}‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int n = 0‬‬ ‫;‪int sum = 0‬‬ ‫;)‪f(n,sum‬‬ ‫;‪cout<< sum‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪55‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺗﺎﺑﻊﻫﺎي ﺑﺎزﮔﺸﺘﻲ ﻣﻲﺗﻮاﻧﻨﺪ ﻛﺎر ﺣﻠﻘﻪﻫﺎ را اﻧﺠﺎم دﻫﻨﺪ اﻣﺎ ﻫﻢ ﻧﻮﺷﺘﻦ و ﻫﻢ ﻓﻬﻤﻴﺪن ﻳﻚ ﺣﻠﻘﻪ ﺑﺴﻴﺎر‬ ‫راﺣﺖ ﺗﺮ اﺳﺖ‪.‬‬

‫‪& ' pointer‬ه و )را ه ‬

‫ﻫﻤﺎن ﻃﻮر ﻛﻪ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻪ ﻳﻚ ﻣﺘﻐﻴﺮ ﻳﺎ ﺛﺎﺑﺖ ‪ pointer‬داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﺑﻪ ﻳﻚ ﺗﺎﺑﻊ ﻳﺎ ﻳﻚ آراﻳﻪ ﻫﻢ ﻣﻲﺗﻮاﻧﻴﻢ‬ ‫‪ pointer‬داﺷﺘﻪ ﺑﺎﺷﻴﻢ‪ .‬اﻳﻦ ﻣﺜﺎل ﻧﺤﻮهي ﻛﺎر را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪void f(int a‬‬ ‫{‬ ‫;‪cout<< "a function with argument " << a‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬

‫‪120‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ void (*pf)(int); pf = &f; (*pf)(2); _getch();

// a pointer // f(2) hijk

}

Output: a function with argument 2

‫& )ﻛﻪ ﻣﻲﺗﻮاﻧﻴﻢ آن را ﻣﻜﺎن ﺗﺎﺑﻊ در‬f ‫ را ﺑﺎ‬f ،f ‫ﻫﺎ ﺑﺮاي راﺣﺘﻲ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ در اﺳﺘﻔﺎده از ﺗﺎﺑﻊ‬compiler ‫اﻣﺎ‬ ‫ ﺑﺮاي اﺛﺒﺎت اﻳﻦ دو ﻣﻄﻠﺐ‬.‫ ﻳﻜﻲ اﺳﺖ‬pf ‫* ﺑﺎ ﺧﻮد‬pf ‫ ﺑﻪ ﻋﻼوه در ﻣﺜﺎل ﺑﺎﻻ‬.‫ﺣﺎﻓﻈﻪ ﺗﻌﺒﻴﺮ ﻛﻨﻴﻢ( ﻳﻜﻲ ﻣﻲﮔﻴﺮﻧﺪ‬ :‫ﺑﻪ ﺑﺮﻧﺎﻣﻪي زﻳﺮ دﻗﺖ ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; void f(int a) { cout<< "a function with argument " << a; } int main() { void (*pf)(int); pf = f; cout<< (&f == f) << endl; cout<< (*pf == pf) << endl; pf(8); _getch(); }

Output: 1 1 a function with argument 8

:‫ﺑﻪ ﻋﻼوه ﻣﻲﺗﻮاﻧﻴﻢ آراﻳﻪاي از ﺗﺎﺑﻊﻫﺎ داﺷﺘﻪ ﺑﺎﺷﻴﻢ‬ #include <conio.h> #include <iostream> using namespace std; void f(int a) { cout<< "f with argument " << a << endl; } void g(int b) { cout<< "g with argument " << b << endl; } int main() { void (*pf[4])(int) = {f, g, f, g};

121

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)‪for(int i = 0; i < 4; i++‬‬ ‫;)‪pf[i](i‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪0‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬

‫‪argument‬‬ ‫‪argument‬‬ ‫‪argument‬‬ ‫‪argument‬‬

‫‪Output:‬‬ ‫‪f with‬‬ ‫‪g with‬‬ ‫‪f with‬‬ ‫‪g with‬‬

‫اﮔﺮ ‪ a‬ﻳﻚ ﻣﺘﻐﻴﺮ‪ ،‬ﺛﺎﺑﺖ‪ ،‬ﺗﺎﺑﻊ و‪ ...‬ﺑﺎﺷﺪ‪ ،‬ﺑﻪ ‪ &a‬آدرس ‪ a‬ﻣﻲﮔﻮﻳﻨﺪ )ﺑﻪ ﺧﻮد & در اﻳﻦ ﺟﺎ ﻋﻤﻠﮕﺮ ‪address-of‬‬ ‫ﻣﻲﮔﻮﻳﻨﺪ(‪ .‬ﺑﻪ آن آدرس ﻣﻲﮔﻮﻳﻨﺪ ﭼﻮن ﻣﻜﺎن ﺣﺎﻓﻈﻪ را ﻣﺸﺨﺺ ﻣﻲﻛﻨﺪ )ﻫﻤﺎن ﻃﻮر ﻛﻪ ﻳﻚ ‪ shortcut‬در‬ ‫‪ Windows‬ﺷﺎﻣﻞ آدرس ﻳﻚ ﻓﺎﻳﻞ اﺳﺖ(‪ .‬ﻣﻤﻜﻦ اﺳﺖ اﻳﻦ ﻓﻜﺮ ﺑﻪ ذﻫﻨﺘﺎن رﺳﻴﺪه ﺑﺎﺷﺪ ﻛﻪ آدرس ﻳﻚ ﺗﺎﺑﻊ ﻣﺜﻞ‬ ‫‪ f‬ﺑﺎ ﺧﻮد آن ﻳﻜﻲ اﺳﺖ‪ .‬اﻣﺎ ﻧﻤﻲﺷﻮد ﺑﺎ ﺻﺮاﺣﺖ اﻳﻦ را ﮔﻔﺖ‪ .‬در ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻣﻦ ‪ compiler‬ﺧﻮدم را در اﻳﻦ‬ ‫ﻣﻮرد ﺑﺎزﺟﻮﻳﻲ ﻛﺮدهام‪ .‬ﺑﺮاي اﻳﻦ ﻛﺎر از ﻳﻚ ‪ pointer‬دوﮔﺎﻧﻪ )ﻳﻌﻨﻲ ‪pointer‬ي ﻛﻪ ﺑﻪ ﻳﻚ ‪ pointer‬دﻳﮕﺮ‬ ‫اﺷﺎره ﻣﻲﻛﻨﺪ( اﺳﺘﻔﺎده ﻛﺮدهام‪ .‬اﻳﻦ ﺑﺮﻧﺎﻣﻪ در ‪ Visual C++ 2005‬ﺧﻄﺎ دارد و ﻣﻦ آن را در ‪BDS 2006‬‬ ‫اﺟﺮا ﻛﺮدهام‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪void f(int a, int b‬‬ ‫{‬ ‫;‪cout<< a + b << endl‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪void (*pf)(int, int) = f; // hijk =&f‬‬ ‫;‪void (**ppf)(int, int) = &pf‬‬ ‫;‪cout<<(**ppf == *ppf) << endl‬‬ ‫‪// true‬‬ ‫‪cout<<( &(**ppf) == &(*ppf) ) << endl; // false‬‬ ‫‪// ppf = f; // error‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪1‬‬ ‫‪0‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺗﻨﻬﺎ ‪ pointer‬اول )ﻳﻌﻨﻲ ‪ (&f‬ﺑﺎ ﺧﻮد ﺗﺎﺑﻊ ﻣﺴﺎوي اﺳﺖ‪.‬‬ ‫ﺑﺮاي ﺗﻌﺮﻳﻒ ‪ pointer‬ﻧﻤﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;)‪void pf(int, int‬‬

‫‪122‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ﺑﻪ ﻳﻚ ﺗﺎﺑﻊ را ﺑﻪ ﻋﻨﻮان ﭘﺎراﻣﺘﺮ‬pointer ‫ اﻣﺎ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻳﻚ‬.‫ ﺑﻪ ﺣﺴﺎب ﻣﻲآﻳﺪ‬prototype ‫ﭼﻮن اﻳﻦ ﻳﻚ‬ :‫ﺗﺎﺑﻌﻲ دﻳﮕﺮ ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ ﻣﻲﺗﻮاﻧﻴﻢ از اﻳﻦ ﺷﻜﻞ اﺳﺘﻔﺎده ﻛﻨﻴﻢ ﻣﺜﻞ اﻳﻦ‬ #include <conio.h> #include <iostream> using namespace std; void f(int a, void g(int)) { cout<< a << endl; // output: 3 g(a); } void g(int b) { cout<< b * b; // output: 9 } int main() { f(3,g); _getch(); }

Output: 3 9

.‫ را ﻓﺮاﺧﻮاﻧﺪه‬g() ،pointer ‫ ﺑﺎ اﻳﻦ‬f() .‫ ﺑﻪ ﻋﻨﻮان آرﮔﻮﻣﺎن داده ﺷﺪه‬g() ‫ي ﺑﻪ ﺗﺎﺑﻊ‬pointer ‫در اﻳﻦ ﻣﺜﺎل‬ :‫اﻳﻦ ﻫﻢ ﻣﺜﺎﻟﻲ ﭘﻴﭽﻴﺪه ﺗﺮ‬ #include <conio.h> #include <iostream> using namespace std; void g(int b) { cout<< b*b; } void L( void f(int a, void g(int)) ) { f(3,g); } void f(int a, void g(int)) { cout<< a << endl; g(a); } int main() { L(f); _getch(); }

123

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪Output:‬‬ ‫‪3‬‬ ‫‪9‬‬

‫ ا‪ f() 01‬ﺑﻌﺪ از )(‪ L‬ﺗﻌﺮﻳﻒ ﺷﺪه‪ f() ،L() ،‬را ﻓﺮا ﻣﻲﺧﻮاﻧﺪ و ﻣﺸﻜﻠﻲ وﺟﻮد ﻧﺪارد‪ .‬در اﻳﻦ ﺟﺎ ﻳﻚ‬ ‫ﻧﻜﺘﻪي ﻣﻬﻢ ﻫﺴﺖ و آن اﻳﻦ ﻛﻪ در ﺗﻌﺮﻳﻒ ﺗﺎﺑﻊ)(‪ ،L‬دو ‪ g‬ﻇﺎﻫﺮ ﺷﺪه اﺳﺖ ﻛﻪ ‪g‬ي دوم ﺑﺎ ‪g‬ي اول ﻣﺘﻔﺎوت‬ ‫اﺳﺖ‪ .‬آن ‪ g‬ﻛﻪ در ﻟﻴﺴﺖ ﭘﺎراﻣﺘﺮﻫﺎ ﻣﻲﺑﻴﻨﻴﺪ ﻧﺎدﻳﺪه ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد و در ﺗﻌﺮﻳﻒ ﺗﺎﺑﻊ ﻧﻤﻲﺷﻮد از آن اﺳﺘﻔﺎده ﻛﺮد‪.‬‬ ‫ﺑﻨﺎﺑﺮاﻳﻦ اﮔﺮ ﺗﻌﺮﻳﻒ )(‪ L‬را ﺻﻮرت زﻳﺮ ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﻢ ﺑﺮﻧﺎﻣﻪ اﺟﺮا ﻧﻤﻲﺷﻮد‪:‬‬ ‫) ))‪void L( void (*f)(int a, void gg(int‬‬ ‫{‬ ‫;)‪f(3,gg‬‬ ‫}‬

‫‪ pointer‬ﺑﻪ آراﻳﻪﻫﺎ ﻫﻢ ﻣﺜﻞ ‪ pointer‬ﺑﻪ ﺗﺎﺑﻊﻫﺎﺳﺖ‪ .‬ﺑﺮاي آﺷﻨﺎﻳﻲ ﺑﺎ آنﻫﺎ ﻣﺜﺎلﻫﺎي زﻳﺮ را ﺑﻪ دﻗﺖ ﺑﺮرﺳﻲ‬ ‫ﻛﻨﻴﺪ‪.‬‬ ‫ﻣﺜﺎل زﻳﺮ در ‪ Visual C++‬اﺟﺮا ﻧﻤﻲﺷﻮد و در ‪compiler‬ﻫﺎي ‪ Borland‬ﻫﻢ ﻳﻚ ‪ warning‬دارد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;]‪int a[20‬‬ ‫;)‪cout<< (a == &a‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪1‬‬

‫ﻣﺜﺎل زﻳﺮ آراﻳﻪاي از آراﻳﻪﻫﺎ را ﺑﻪ ﻛﺎر ﻣﻲﺑﺮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;}‪int a[5] = {1,2,3,4,5‬‬ ‫;}‪int b[5] = {6,7,8,9,10‬‬ ‫;}‪int (*pa[4])[5] = { &a, &b, &a, &b‬‬ ‫)‪for(int i = 0; i < 4; i++‬‬ ‫{‬ ‫)‪for(int j = 0; j < 5; j++‬‬ ‫;]‪cout<< (*pa[i])[j‬‬ ‫;‪cout<< endl‬‬

‫‪124‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ } _getch(); }

Output: 12345 678910 12345 678910

‫& ﻣﺴﺎوي اﺳﺖ در ﻣﺜﺎل ﺑﺎﻻ ﻧﻤﻲﺗﻮاﻧﻴﻢ ﺑﻪ ﺟﺎي‬a ‫ ﺑﺎ‬a ‫ﺑﺎ اﻳﻦ ﻛﻪ در ﻣﺜﺎل ﭘﻴﺸﻴﻦ دﻳﺪﻳﻢ ﻛﻪ‬ int (*pa[4])[5] = { &a, &b, &a, &b};

:‫ﺑﻨﻮﻳﺴﻴﻢ‬ int (*pa[4])[5] = { a, b, a, b};

:‫در ﻣﺜﺎل زﻳﺮ آراﻳﻪﻫﺎ را ﺑﻪ ﻋﻨﻮان ﭘﺎراﻣﺘﺮ ﺑﻪ ﻛﺎر ﮔﺮﻓﺘﻪام‬ #include <conio.h> #include <iostream> using namespace std; #pragma argsused void f(double a[20], int b[]) { char c[12]; cout<< typeid(a).name() << endl; // double * cout<< typeid(b).name() << endl; // int * cout<< typeid(c).name() << endl; // char [12] a = new double [2]; // a is parameter // c = new char [2]; // error } int main() { double a[5] = {1,2,3,4,5}; int b[5] = {6,7,8,9,10}; f(a,b); _getch(); }

Output(BDS 2006): double * int * char[12] Output(Visual C++ 2005): double * int * char [12]

125

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﻧﻮع ﭘﺎراﻣﺘﺮ ‪ double* ،a‬اﺳﺖ ﻧﻪ ]‪ .double[12‬ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﺗﻮاﻧﺴﺘﻪاﻳﻢ ﻣﻘﺪار ‪ a‬را‬ ‫ﻋﻮض ﻛﻨﻴﻢ‪ .‬اﻣﺎ ﺧﻂ‬ ‫‪#pragma argsused‬‬

‫اﻳﻦ ﺧﻂ ﻳﻚ دﺳﺘﻮر ‪ preprocessor‬اﺳﺖ و ﻛﺎر آن ﻓﻘﻂ اﻳﻦ اﺳﺖ ﻛﻪ از اﻳﺠﺎد ﻧﻮﻋﻲ ‪ warning‬در ﺗﺎﺑﻊ‬ ‫ﺑﻌﺪي ﺟﻠﻮﮔﻴﺮي ﻣﻲﻛﻨﺪ‪ .‬ﺣﺬف آن ﺑﺎﻋﺚ ﻣﻲﺷﻮد ‪warning ،BDS 2006‬ﻫﺎﻳﻲ در ﻣﻮرد ﻋﺪم اﺳﺘﻔﺎده از‬ ‫ﭘﺎراﻣﺘﺮﻫﺎ ﺻﺎدر ﻛﻨﺪ‪.‬‬ ‫ﺑﺮاي ﺟﻠﻮﮔﻴﺮي از ﺑﻪ ﻛﺎرﺑﺮدن اﺳﻢﻫﺎي ﻃﻮﻻﻧﻲ ِ ‪pointer‬ﻫﺎ ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ typedef‬ﺧﻴﻠﻲ ﺑﻪ درد ﻣﻲﺧﻮرد‪.‬‬ ‫ﺑﻪ اﻳﻦ ﻣﺜﺎل ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫; )‪typedef int (*WND)(int, int‬‬ ‫)‪int f(int a,int b‬‬ ‫{‬ ‫;‪cout<< a + b‬‬ ‫;‪return a‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪WND pf =f‬‬ ‫;)‪pf(2,5‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪7‬‬

‫در اﻳﻦ ﻣﺜﺎل ‪ WND‬ﺑﻪ ﺟﺎي )‪ int(*)(int,int‬ﺑﻪ ﻛﺎر ﻣﻲرود‪ .‬ﻧﺤﻮهي ﺑﻪ ﻛﺎر ﮔﺮﻓﺘﻦ ‪ typedef‬در اﻳﻦ‬ ‫ﻣﺜﺎل ﻣﻬﻢ اﺳﺖ ﭼﻮن ﻣﻤﻜﻦ اﺳﺖ ﺑﻪ ﻧﻈﺮ ﺑﺮﺳﺪ اﻳﻦ ﻃﻮري ﺑﺎﻳﺪ ﻧﻮﺷﺖ‪:‬‬ ‫‪typedef int (*)(int, int) WND‬‬

‫ﻛﻪ اﻳﻦ ﻏﻠﻂ اﺳﺖ‪.‬‬

‫‪126‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ $ @ #include‬؟‬ ‫)(‪ getch‬ﺗﺎﺑﻌﻲ اﺳﺖ ﻛﻪ در ﻫﻤﻪي ﺑﺮﻧﺎﻣﻪﻫﺎ آن را ﺑﻪ ﻛﺎر ﻣﻲﮔﻴﺮﻳﻢ‪ .‬اﻣﺎ اﻳﻦ ﺗﺎﺑﻊ ﻛﺠﺎ ﻣﻌﺮﻓﻲ ﺷﺪه اﺳﺖ؟ ﺑﺎﻳﺪ‬ ‫ﺑﮕﻮﻳﻢ در ﻓﺎﻳﻞ دﻳﮕﺮي‪ .‬اﺳﻢ آن ﻓﺎﻳﻞ ‪ conio.h‬اﺳﺖ‪ .‬ﺑﺎ ‪ #include‬ﻣﺤﺘﻮﻳﺎت ﻓﺎﻳﻞ ‪ conio.h‬را ﺑﻪ ﻓﺎﻳﻞ‬ ‫ﺧﻮدﻣﺎن اﺿﺎﻓﻪ ﻣﻲﻛﻨﻴﻢ اﻧﮕﺎر اﺻﻼ ﻣﺤﺘﻮﻳﺎت آن را ﺧﻮدﻣﺎن ﺗﺎﻳﭗ ﻛﺮده ﺑﺎﺷﻴﻢ‪ conio.h .‬و ﻓﺎﻳﻞﻫﺎي دﻳﮕﺮ ﻣﺜﻞ‬ ‫آن )از ﺟﻤﻠﻪ ‪ iostream) header file‬ﻧﺎﻣﻴﺪه ﻣﻲﺷﻮﻧﺪ‪.‬‬ ‫ﺧﻮد ﻣﺎ ﻫﻢ ﻣﻲﺗﻮاﻧﻴﻢ ‪ header file‬درﺳﺖ ﻛﻨﻴﻢ و از آن اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ .‬ﺑﺮاي اﻳﻦ ﻛﺎر ﻣﺤﻠﻲ از ‪ hard disk‬ﺧﻮد‬ ‫را ﻣﺸﺨﺺ ﻛﻨﻴﺪ‪ .‬ﻣﺜﻼ "‪) ."C:\Header‬از ‪ My Computer‬وارد دراﻳﻮ ‪ C‬ﺷﻮﻳﺪ و ﻳﻚ ‪ folder‬ﺟﺪﻳﺪ ﺑﻪ‬ ‫اﺳﻢ ‪ header‬درﺳﺖ ﻛﻨﻴﺪ‬

‫(‪ .‬ﺑﻌﺪ در ‪ header ِ folder‬ﻳﻚ ﻓﺎﻳﻞ ﺑﻪ اﺳﻢ ‪ myheader.txt‬درﺳﺖ‬

‫ﻛﻨﻴﺪ‪:‬‬

‫ﻓﺎﻳﻞ ‪ myheader.txt‬را ﺑﺎز ﻛﻨﻴﺪ و در آن ﺑﻨﻮﻳﺴﻴﺪ‪:‬‬ ‫)][‪unsigned GetLength(char a‬‬ ‫{‬ ‫;‪int i = 0‬‬ ‫;)‪for(; a[i] != 0; i++‬‬ ‫;‪return i‬‬ ‫}‬ ‫ﻣﺜﻞ‬

‫‪127‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫ﺣﺎﻻ اﻳﻦ ﺑﺮﻧﺎﻣﻪ را در ‪ compiler‬ﺧﻮدﺗﺎن ﺑﻨﻮﻳﺴﻴﺪ و اﺟﺮا ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪#include <C:\header\myheader.txt‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)"‪cout<< GetLength("hello‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬

‫اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻃﻮل رﺷﺘﻪي "‪ "hello‬را ﭼﺎپ ﻣﻲﻛﻨﺪ‪ .‬در اﻳﻦ ﺑﺮﻧﺎﻣﻪ‬ ‫>‪#include <C:\header\myheader.txt‬‬

‫را ﺑﺎ ﻫﺮ ﻳﻚ از ﺧﻄﻮط زﻳﺮ ﻣﻲﺷﻮد ﺟﺎﻳﮕﺰﻳﻦ ﻛﺮد‪:‬‬ ‫"‪#include "C:\header\myheader.txt‬‬ ‫>‪#include <C:\\header\\myheader.txt‬‬ ‫"‪#include "C:\\header\\myheader.txt‬‬

‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ دﺳﺘﻮرﻫﺎﻳﻲ ﻛﻪ ﺑﺎ ‪ #‬ﺷﺮوع ﻣﻲﺷﻮﻧﺪ دﺳﺘﻮرﻫﺎي ‪ preprocessor‬ﻫﺴﺘﻨﺪ‪ .‬اﻳﻦ ﺟﻮر دﺳﺘﻮرﻫﺎ ﺑﺎﻳﺪ از‬ ‫اول ﺧﻂ ﺷﺮوع ﺷﻮﻧﺪ و آﺧﺮﺷﺎن »;« ﻧﻤﻲﺧﻮاﻫﻨﺪ‪.‬‬ ‫اﻣﺎ ﻧﻮﺷﺘﻦ آدرس ﻛﺎﻣﻞ ‪ myheader.txt‬ﻛﺎر ﭘﺮ زﺣﻤﺘﻲ اﺳﺖ و ﺑﻪ ﻋﻼوه اﮔﺮ ﻣﺤﻞ آن ﺗﻐﻴﻴﺮ ﻛﻨﺪ ﺑﺎﻳﺪ ﺑﺮﻧﺎﻣﻪ را‬ ‫ﺗﻐﻴﻴﺮ داد‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﻧﻮﺷﺘﻦ ﻓﻘﻂ اﺳﻢ ﻓﺎﻳﻞ ﻛﺎﻓﻲ ﺑﺎﺷﺪ ﺑﺎﻳﺪ در ﺟﺎي ﻣﻨﺎﺳﺐ در ﺗﻨﻈﻴﻤﺎت ‪ compiler‬ﻣﺤﻞ ﻓﺎﻳﻞ‬ ‫را اﺿﺎﻓﻪ ﻛﻨﻴﻢ‪ .‬ﺑﺮاي اﻳﻦ ﻛﺎر در ‪ BDS 2006‬اﻳﻦ ﻣﺴﻴﺮ را ﻃﻲ ﻛﻨﻴﺪ‪:‬‬ ‫‪Project | Options… | C++ Compiler | Paths and Defines‬‬ ‫و ﺑﻌﺪ ﻋﺒﺎرت ‪ ;C:\header‬را ﺑﻪ ﻧﻮار ‪ Include search path‬اﺿﺎف ﻛﻨﻴﺪ‪.‬‬ ‫در ‪ VC++ 2005 Express Edition‬اﻳﻦ ﻣﺴﻴﺮ را ﻃﻲ ﻛﻨﻴﺪ‪:‬‬ ‫‪Tools | Options… | Projects and Solutions | VC++ Directories |Show‬‬ ‫‪directories for: Include files‬‬ ‫و ﺧﻂ ‪ C:\header‬را اﺿﺎﻓﻪ ﻛﻨﻴﺪ‪ .‬ﺑﻌﺪ از اﻧﺠﺎم اﻳﻦ ﻛﺎرﻫﺎ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ را ﺑﻪ اﻳﻦ ﺻﻮرت ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬

‫‪128‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪#include <myheader.txt‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)"‪cout<< GetLength("hello‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬

‫ﭘﺴﻮﻧﺪ ‪header file‬ﻫﺎ در ‪ C++‬دﻟﺨﻮاه اﺳﺖ وﻟﻲ ﻣﻌﻤﻮﻻ ‪ .h‬ﻳﺎ ‪ .hpp‬اﻧﺘﺨﺎب ﻣﻲﺷﻮد‪ .‬ﻣﻦ در اﻳﻦ ﻣﺜﺎل ‪ .txt‬را‬ ‫اﻧﺘﺨﺎب ﻛﺮدهام‪.‬‬ ‫ﺑﻪ ﺷﻜﻞ‬ ‫>‪#include <myheader.txt‬‬

‫‪ angle-bracket form‬ﻣﻲﮔﻮﻳﻨﺪ و ﺑﻪ ﺷﻜﻞ‬ ‫"‪#include "myheader.txt‬‬

‫‪ quoted form‬ﻣﻲﮔﻮﻳﻨﺪ‪ .‬ﻓﺮق آنﻫﺎ اﻳﻦ اﺳﺖ ﻛﻪ در دوﻣﻲ ‪ myheader.txt‬را اول در ﻫﻤﺎن ﻣﻜﺎﻧﻲ ﻛﻪ‬ ‫ﻓﺎﻳﻞ ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ ﻫﺴﺖ ﺟﺴﺖ و ﺟﻮ ﻣﻲﻛﻨﺪ و اﮔﺮ ﭘﻴﺪا ﻧﺸﺪ ﺑﻌﺪ ﺑﻪ ﺳﺮاغ ﺟﺎﻫﺎي دﻳﮕﺮ ﺑﺮاي ﺟﺴﺖ و ﺟﻮ ﻣﻲرود‪.‬‬ ‫در ﻣﺤﻠﻲ ﻛﻪ ‪ compiler‬در ‪ hard disk‬ﻧﺼﺐ ﺷﺪه ‪folder‬ي ﺑﺎ ﻧﺎم ‪ include‬ﭘﻴﺪا ﻣﻲﺷﻮد ﻛﻪ ‪header‬‬ ‫‪file‬ﻫﺎي ﻣﻌﻤﻮل در ‪ C++‬آن ﺟﺎﺳﺖ‪ .‬ﺑﺮاي آﺷﻨﺎﻳﻲ ﺑﺎ ﺗﺎﺑﻊﻫﺎي ﻣﻮﺟﻮد در اﻳﻦ ‪header file‬ﻫﺎ از ‪ help‬در‬ ‫‪ compiler‬ﺧﻮدﺗﺎن ﻛﻤﻚ ﺑﮕﻴﺮﻳﺪ‪.‬‬

‫* را " ‪default‬‬

‫ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪void f(int a, int b = 2‬‬ ‫{‬ ‫;‪cout<< a <<endl‬‬

‫‪129‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪cout<< b <<endl << endl‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪f(1,3‬‬ ‫;)‪f(7‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬ ‫‪3‬‬ ‫‪7‬‬ ‫‪2‬‬

‫در ﻟﻴﺴﺖ ﭘﺎراﻣﺘﺮﻫﺎ ﺑﻪ ﺟﺎي ‪ int b‬ﻧﻮﺷﺘﻪام ‪ .int b=2‬اﻳﻦ ﺑﻪ ﻣﻦ اﺟﺎزه ﻣﻲدﻫﺪ ﻛﻪ در )(‪ main‬ﺑﻨﻮﻳﺴﻴﻢ‬ ‫;)‪ f(7‬و ‪ f‬ﭘﺎراﻣﺘﺮ دوم را ﺑﻪ ﻃﻮر ‪ 2 ،default‬ﺑﻪ ﺣﺴﺎب ﻣﻲآورد‪ .‬اﻣﺎ اﮔﺮ آرﮔﻮﻣﺎن دوم را ﻫﻢ ﻣﺸﺨﺺ ﻛﻨﻢ‬ ‫ﻫﻤﺎن آرﮔﻮﻣﺎن در ﻧﻈﺮ ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد ﻣﺜﻞ ;)‪ f(1,3‬در ﺑﺎﻻ‪.‬‬ ‫اﮔﺮ ﻳﻚ ﭘﺎراﻣﺘﺮ ﺗﺎﺑﻊ‪ default ،‬ﺷﺪ؛ ﻫﻤﻪي ﭘﺎراﻣﺘﺮﻫﺎي ﺑﻌﺪي ﻫﻢ ﺑﺎﻳﺪ ‪ default‬ﺷﻮﻧﺪ‪.‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪void f(int a = 1, int b = 2, int c = 3‬‬ ‫{‬ ‫;‪cout<< a << b << c << endl‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪f‬‬ ‫;)‪f(7‬‬ ‫;)‪f(7,8‬‬ ‫;)‪f(7,8,9‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪123‬‬ ‫‪823‬‬ ‫‪893‬‬

‫ﻣﻘﺪار ‪ default‬را ﻣﻲﺷﻮد در ‪ prototype‬ﻫﻢ ﻗﺮار داد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬

‫‪130‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ using namespace std; void f(int x = 2); void f(int x) { cout<< x; } int main() { f(); _getch(); }

Output: 2

prototype ‫ در ﺿﻤﻦ اﮔﺮ ﭼﻨﺪ‬.‫ ﻧﻪ در ﻫﺮ دو‬prototype ‫ ﻳﺎ ﺑﺎﻳﺪ در ﺗﻌﺮﻳﻒ ﺗﺎﺑﻊ ﺑﺎﺷﺪ ﻳﺎ در‬default ‫ﻣﻘﺪار‬ ‫ در ﻣﺜﺎل ﻗﺒﻞ ﺑﻪ ﺟﺎي‬.‫ ﻗﺮار داد‬prototype ‫ را ﻧﻤﻲﺷﻮد در ﺑﻴﺶ از ﻳﻚ‬default ‫داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﻣﻘﺪار‬ void f(int x = 2);

:‫ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‬ void f(int = 2);

‫ دن‬overload

‫ ﺑﺎ اﺳﺘﻔﺎده از ﻧﻮع آرﮔﻮﻣﺎنﻫﺎ و ﺗﻌﺪاد‬compiler ‫ﻣﻲﺷﻮد دو ﺗﺎ ﺗﺎﺑﻊ ﻫﻢ اﺳﻢ ﺑﺎ ﻟﻴﺴﺖ ﭘﺎراﻣﺘﺮﻫﺎي ﻣﺘﻔﺎوت داﺷﺖ و‬ :‫ اﻳﻦ ﻣﺜﺎل را ﺑﺒﻴﻨﻴﺪ‬.‫ ﺗﺎﺑﻊ ﻣﻨﺎﺳﺐ را ﺗﺸﺨﻴﺺ ﻣﻲدﻫﺪ‬،‫آنﻫﺎ‬ #include <conio.h> #include <iostream> using namespace std; #pragma argsused void f(int a) { cout<< "first f" << endl; } #pragma argsused void f(char a) { cout<< "second f" << endl; } int main()

131

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫{‬ ‫;)'‪f('a‬‬ ‫;)'‪f((int)'a‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪second f‬‬ ‫‪first f‬‬

‫'‪ char n\ 'a‬اﺳﺖ و )'‪ f('a‬ﺗﺎﺑﻊ دون را ﻓﺮا ﻣﻲﺧﻮاﻧﺪ‪ .‬اﻣﺎ '‪ int n\ (int)'a‬اﺳﺖ و‬ ‫)'‪ f((int)'a‬ﺗﺎﺑﻊ اول را ﻓﺮا ﻣﻲﺧﻮاﻧﺪ‪.‬‬ ‫اﻣﺎ ﻧﻤﻲﺷﻮد دو ﺗﺎﺑﻊ ﺑﺎ اﺳﻢ و ﭘﺎراﻣﺘﺮﻫﺎي ﻳﻚ ﺟﻮر داﺷﺖ ﺣﺘﻲ اﮔﺮ ﺧﺮوﺟﻲ آنﻫﺎ ﻣﺘﻔﺎوت ﺑﺎﺷﺪ‪ .‬ﻣﻮاردي ﭘﻴﺶ‬ ‫ﻣﻲآﻳﺪ ﻛﻪ ‪ compiler‬از اﻧﺘﺨﺎب ﺗﺎﺑﻊ ﻣﻨﺎﺳﺐ ﻋﺎﺟﺰ اﺳﺖ در اﻳﻦ ﻣﻮارد ‪ error‬ﺻﺎدر ﻣﻲﺷﻮد ﻣﺜﻼ ﺑﺮﻧﺎﻣﻪي زﻳﺮ‬ ‫ﻏﻴﺮ ﻗﺎﺑﻞ اﺟﺮاﺳﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪#pragma argsused‬‬ ‫)‪void f(int a, int b = 2‬‬ ‫{‬ ‫;‪cout<< "first f" << endl‬‬ ‫}‬ ‫‪#pragma argsused‬‬ ‫)‪void f(int a‬‬ ‫{‬ ‫;‪cout<< "second f" << endl‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪f(2‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output: Error‬‬

‫ﺑﻪ اﺳﺘﻔﺎده از ﻳﻚ ﻧﺎم ﺑﺮاي دو ﺗﺎﺑﻊ ‪ overload‬ﻛﺮدن ﻣﻲﮔﻮﻳﻨﺪ‪.‬‬

‫‪132‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ namespace‬و ‪using‬‬

‫ﻓﺮض ﻛﻨﻴﺪ ﺑﺨﻮاﻫﻴﻢ ﻳﻚ اﺳﻢ را ﺑﺮاي دو ﺗﺎ ﺗﺎﺑﻊ ﻛﻪ ﭘﺎراﻣﺘﺮﻫﺎي ﻳﻚ ﺟﻮر دارﻧﺪ ﺑﻪ ﻛﺎر ﺑﺒﺮﻳﻢ ﻳﺎ دو ﺗﺎ ﻣﺘﻐﻴﺮ ﻫﻢ‬ ‫اﺳﻢ داﺷﺘﻪ ﺑﺎﺷﻴﻢ‪ .‬ﺑﺮاي اﻳﻦ ﻛﺎر ﻣﻲﺗﻮاﻧﻴﻢ از ‪ namespace‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ .‬ﺑﺮﻧﺎﻣﻪي زﻳﺮ دو ‪ namespace‬دارد‬ ‫ﻛﻪ در ﻫﺮ ﻛﺪام ﻣﺘﻐﻴﺮي ﺑﺎ ﻧﺎم ‪ a‬ﺗﻌﺮﻳﻒ ﺷﺪه‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪namespace AA‬‬ ‫{‬ ‫;‪int a = 2‬‬ ‫}‬ ‫‪namespace BB‬‬ ‫{‬ ‫;‪int a = 3‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;"‪cout<< AA::a << "\n‬‬ ‫;"‪cout<< BB::a << "\n‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪2‬‬ ‫‪3‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺑﺮاي دﺳﺘﺮﺳﻲ ﺑﻪ ﻣﺘﻐﻴﺮ ‪ a‬ﺗﻌﺮﻳﻒ ﺷﺪه در ‪ namespace AA‬ﻣﻲﻧﻮﻳﺴﻴﻢ ‪ .AA::a‬اﻳﻦ‬ ‫‪namespace‬ﻫﺎ را ﻧﻤﻲﺷﻮد در ﺗﺎﺑﻊ )(‪ main‬ﺗﻌﺮﻳﻒ ﻛﺮد و ﺗﻌﺮﻳﻒ آنﻫﺎ ﺑﺎﻳﺪ در ﻓﻀﺎي ﻋﻤﻮﻣﻲ ﺑﺎﺷﺪ‪ .‬ﻣﺜﺎل‬ ‫زﻳﺮ ﺟﺮﺋﻴﺎت ﺑﻴﺶ ﺗﺮي دارد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪namespace AA‬‬ ‫{‬ ‫;‪int a = 2‬‬ ‫)(‪void f‬‬ ‫{‬ ‫;‪a = 6‬‬ ‫;‪AA::a = 5‬‬ ‫}‬ ‫}‬ ‫‪namespace BB‬‬ ‫{‬ ‫;‪int a = 3‬‬ ‫}‬ ‫)(‪int main‬‬

‫‪133‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { cout<< AA::a << "\n"; // output: 2 AA::f(); cout<< AA::a << "\n"; // output: 5 _getch(); }

Output: 2 5

‫ و ﻫﻢ از‬a ‫ ﻣﻲﺷﻮد ﻫﻢ از‬a ‫ ﻗﺮار دارد ﺑﺮاي دﺳﺘﺮﺳﻲ ﺑﻪ‬namespace AA ‫ ﻛﻪ درون‬f ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ در ﺗﺎﺑﻊ‬ -‫ ﺑﺎﻳﺪ ﻛﻠﻤﻪ‬a ‫ ﺑﻨﻮﻳﺴﻴﻢ‬AA::a ‫ ﻫﻢ ﺑﻪ ﺟﺎي‬namespace AA ‫ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ در ﺧﺎرج از‬.‫ اﺳﺘﻔﺎده ﻛﺮد‬AA::a :‫ را ﺑﻪ ﻛﺎر ﺑﺒﺮﻳﻢ‬using ‫ي ﻛﻠﻴﺪي‬ #include <conio.h> #include <iostream> using namespace std; namespace AA { int a = 2; } namespace BB { int a = 3; } int main() { using namespace AA; cout<< a << "\n"; // outpout: 2 cout<< AA::a << "\n"; // outpout: 2 cout<< BB::a << "\n"; // outpout: 3 _getch(); }

Output: 2 2 3 using ‫ را در ﻓﻀﺎي ﻋﻤﻮﻣﻲ ﻫﻢ ﻣﻲﺷﻮد ﻗﺮار داد و در اﻳﻦ ﺻﻮرت ﻫﻤﻪي ﺗﺎﺑﻊﻫﺎي ﺑﻌﺪ از ﻣﺤﻞ ﻧﻮﺷﺘﻦ‬using

.‫ﻣﻲﺗﻮاﻧﻨﺪ از آن اﺳﺘﻔﺎده ﻛﻨﻨﺪ‬ :‫ را ﻧﺸﺎن ﻣﻲدﻫﺪ‬namespace ‫ﻣﺜﺎل زﻳﺮ ﻛﺎﺑﺮدي ﺟﺎﻟﺐ از‬ #include <iostream> using namespace std; namespace ABC {

134

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <conio.h> } int main() { char ch = ABC::_getch(); cout<< ch; ABC::_getch(); }

Output: a

:‫ﺣﺎﻻ ﻣﻲﺗﻮاﻧﻴﺪ ﺑﺮﻧﺎﻣﻪ زﻳﺮ را ﺗﻮﺟﻴﻪ ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> int main() { std::cout<< "hello"; _getch(); }

Output: hello

:‫ ﺑﻪ ﻣﺜﺎل زﻳﺮ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‬.‫ ﺑﺪون اﺳﻢ ﺑﻪ ﺣﺴﺎب آورد‬namespace ‫ﻓﻀﺎي ﻋﻤﻮﻣﻲ را ﻣﻲﺷﻮد ﻳﻚ‬ #include <conio.h> #include <iostream> using namespace std; int a = 1; int b = 2; int main() { int a = 3; cout<< a << endl; cout<< ::a << endl; cout<< b << endl; cout<< ::b << endl; { // block int a = 4; cout<< ::a; } // end of block _getch();

// // // //

output: output: output: output:

3 1 2 2

// output: 1

}

Output: 3 1

135

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪2‬‬ ‫‪2‬‬ ‫‪1‬‬

‫در اﻳﻦ ﻣﺜﺎل ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻫﻤﻴﺸﻪ ﻣﻨﻈﻮر از ‪ ::a‬ﻣﺘﻐﻴﺮي اﺳﺖ ﻛﻪ در ﻓﻀﺎي ﻋﻤﻮﻣﻲ ﺗﻌﺮﻳﻒ ﺷﺪه اﺳﺖ‪ .‬ﺑﻪ ﻋﻼوه‬ ‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ در ﻫﺮ ﺑﻠﻮك ﻣﻲﺷﻮد ﻣﺘﻐﻴﺮي ﻫﻢ اﺳﻢ ﺑﺎ ﻣﺘﻐﻴﺮﻫﺎي ﺗﻌﺮﻳﻒ ﺷﺪه در ﺧﺎرج آن ﺗﻌﺮﻳﻒ ﻛﺮد‪.‬‬

‫‪ try ،throw‬و ‪catch‬‬

‫ﻳﻜﻲ از راهﻫﺎي ﭘﻴﺪا ﻛﺮدن ﺧﻄﺎ‪ ،‬ﻳﺎ ﺑﺮﻃﺮف ﻛﺮدن ﺧﻮدﻛﺎر آن؛ اﺳﺘﻔﺎده از ‪ exception‬اﺳﺖ‪ .‬وﻗﺘﻲ ﻳﻚ ﺑﺮﻧﺎﻣﻪ‬ ‫ﺑﺎ ﻣﺸﻜﻠﻲ ﻣﻮاﺟﻪ ﻣﻲﺷﻮد ﻛﻪ ﻗﺎدر ﺑﻪ اداﻣﻪي ﻛﺎر ﻧﻴﺴﺖ ﺑﺎﻳﺪ ﭼﻪ اﺗﻔﺎﻗﻲ ﺑﻴﻔﺘﺪ؟ ﺑﺪون ﺷﻚ اﻳﻦ ﻛﻪ اﺟﺮاي ﺑﺮﻧﺎﻣﻪ‬ ‫ﺑﺪون ﻫﻴﭻ ﻫﺸﺪاري‪ ،‬ﻧﺎﮔﻬﺎن ﭘﺎﻳﺎن ﻳﺎﺑﺪ اﺗﻔﺎق ﺧﻮﺑﻲ ﻧﻴﺴﺖ‪ .‬ﻣﻲﺷﻮد از ‪ exception‬ﺑﺮاي اﻳﺠﺎد راه ﺣﻞ ﻣﻨﺎﺳﺐ‬ ‫ﺗﺮي اﺳﺘﻔﺎده ﻛﺮد‪.‬‬ ‫وﻗﺘﻲ ﻳﻚ ‪ exception‬را ﺑﻪ وﺟﻮد ﻣﻲآورﻳﻢ ﻣﻲﮔﻮﻳﻴﻢ ‪ exception‬را ‪ throw‬ﻛﺮدهاﻳﻢ و ﺑﻪ ﺟﺎي اﻳﻦ ﻛﻪ‬ ‫ﺑﮕﻮﻳﻴﻢ ‪ exception‬درﺳﺖ ﺷﺪه ﻣﻲﮔﻮﻳﻴﻢ ‪ raise ،exception‬ﺷﺪه اﺳﺖ )واﻗﻌﺎ ﻛﻪ ﭼﻪ ﻗﺪر ﻣﻦ ﻓﺎرﺳﻲ را‬ ‫دوﺳﺖ دارم‬

‫(‪.‬‬

‫وﻗﺘﻲ ﻳﻚ ‪ throw ،exception‬ﻣﻲﺷﻮد‪ ِ control ،‬ﺑﺮﻧﺎﻣﻪ ﺷﺮوع ﻣﻲﻛﻨﺪ ﺑﻪ ﺑﺮﮔﺮداﻧﺪن ﺣﺎﻓﻈﻪﻫﺎي ‪ stack‬و‬ ‫ﺧﺮوج از ﺗﺎﺑﻊﻫﺎ ﺗﺎ اﻳﻦ ﻛﻪ ﺑﻪ )(‪ main‬ﺑﺮﺳﺪ و اﺟﺮاي ﺑﺮﻧﺎﻣﻪ ﻣﺘﻮﻗﻒ ﺷﻮد ﻣﮕﺮ اﻳﻦ ﻛﻪ در ﺟﺎﻳﻲ ﺑﻪ وﺳﻴﻠﻪي‬ ‫‪ try‬و ‪ catch‬ﺟﻠﻮي آن ﮔﺮﻓﺘﻪ ﺷﻮد‪ .‬ﻓﺮﻣﻮل ‪ throw‬ﺑﻪ اﻳﻦ ﺻﻮرت اﺳﺖ‪:‬‬ ‫;] ‪ ydZz Z\ ]kl5m‬از ه] ‪4i‬ع[ ‪throw‬‬

‫ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪void f‬‬ ‫{‬ ‫;‪int a‬‬ ‫;‪cin>> a‬‬ ‫)‪if (a < 0‬‬ ‫;"‪throw "negative not allowed\n‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬

‫‪136‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪BEGIN:‬‬ ‫‪try‬‬ ‫{‬ ‫;)(‪f‬‬ ‫}‬ ‫)‪catch(char* c‬‬ ‫{‬ ‫;‪cout<< c‬‬ ‫;‪goto BEGIN‬‬ ‫}‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪-5‬‬ ‫‪negative not allowed‬‬ ‫‪-7‬‬ ‫‪negative not allowed‬‬ ‫‪4‬‬

‫‪ BDS 2006‬ﺑﻌﺪ از ﻫﺮ ‪ exception‬ﻛﻪ ‪ throw‬ﻣﻲﺷﻮد ﻳﻚ ‪ Message Box‬اﻳﺠﺎد ﻣﻲﻛﻨﺪ ﻣﺜﻞ اﻳﻦ‪:‬‬

‫در اﻳﻦ ﺣﺎﻟﺖ ‪ Continue‬را ﻓﺸﺎر دﻫﻴﺪ‪.‬‬ ‫در اﻳﻦ ﻣﺜﺎل ﺗﺎﺑﻊ )(‪ f‬در ﻳﻚ »ﺑﻠﻮك ‪ «try‬ﻗﺮار ﮔﺮﻓﺘﻪ ﻛﻪ ﻫﻨﮕﺎم ‪ raise‬ﺷﺪن ‪ ،exception‬ﺑﺸﻮد آن را‬ ‫‪ catch‬ﻛﺮد‪» .‬ﺑﻠﻮك ‪ «catch‬ﺑﺎﻳﺪ ﺑﻼﻓﺎﺻﻠﻪ ﺑﻌﺪ از ﺑﻠﻮك ‪ try‬ﻗﺮار ﺑﮕﻴﺮد و ‪ try‬ﺣﺘﻤﺎ ﺑﺎﻳﺪ }{ داﺷﺘﻪ ﺑﺎﺷﺪ‪.‬‬ ‫ﻧﻜﺘﻪي دﻳﮕﺮ آن اﺳﺖ ﻛﻪ ‪ BEGIN:‬ﻧﻤﻲﺗﻮاﻧﺪ درون ﺑﻠﻮك ‪ try‬ﻗﺮار ﺑﮕﻴﺮد‪.‬‬ ‫وﻗﺘﻲ در ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ ﻳﻚ ﻋﺪد ﻣﻨﻔﻲ وارد ﻣﻲﺷﻮد ﻳﻚ ‪ exception‬ﺑﺎ ﻧﻮع *‪ throw ،char‬ﻣﻲﺷﻮد‪ .‬ﺑﺎ‬ ‫‪ throw‬ﺷﺪن‪ control ،‬ﺑﺮﻧﺎﻣﻪ ‪ exception‬را )ﻛﻪ ﻧﻮع *‪ char‬دارد( ﺑﺮﻣﻲدارد )و در ﺟﻴﺐ ﺧﻮد ﻣﻲﮔﺬارد‬ ‫( و از ﺗﺎﺑﻊ ‪ f‬ﺧﺎرج ﻣﻲﺷﻮد وﻟﻲ در ﺑﻠﻮك ‪ try‬ﻣﺘﻮﻗﻒ ﻣﻲﺷﻮد و ‪ exception‬در ﺑﻠﻮك ‪) catch‬ﭘﺲ از‬ ‫ﺑﺎزرﺳﻲ ﺑﺪﻧﻲ( ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد )و ‪ ِ control‬ﺑﺮﻧﺎﻣﻪ ﺑﻪ زﻧﺪان ﻣﻲاﻓﺘﺪ(‪ .‬ﻗﺮار اﺳﺖ در ﺑﻠﻮك ‪ catch‬اﻋﻤﺎل ﻻزم‬ ‫ﺑﺮاي ﺑﺮﻃﺮف ﺷﺪن ﻣﺸﻜﻞ اﻧﺠﺎم ﺷﻮد‪ .‬دراﻳﻦ ﺟﺎ ﻣﻦ ﻓﻘﻂ ‪ exception‬را ﭼﺎپ ﻛﺮدهام و ﺑﺎ ‪ goto‬ﺑﺮﻧﺎﻣﻪ را از ﻧﻮ‬ ‫آﻏﺎز ﻛﺮدهام‪.‬‬

‫‪137‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

:‫ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﺗﻮﺟﻪ ﻛﻨﻴﺪ‬.‫ ﻗﺮار ﺑﺪﻫﻴﻢ‬try ‫ ﺑﻌﺪ از ﻳﻚ ﺑﻠﻮك‬،‫ را ﭘﺸﺖ ﺳﺮ ﻫﻢ‬catch ‫ﻣﻲﺗﻮاﻧﻴﻢ ﭼﻨﺪ ﺑﻠﻮك‬ #include <conio.h> #include <iostream> using namespace std; void i(int a) { if(a == -1) throw "too bad"; } void h(int a) { if(a == 0) throw 97; } void g(int a) { if(a == 1) throw 'a'; } void f() { int a; cin>> a; g(a); h(a); i(a); } int main() { BEGIN: try { f(); } catch(int) { cout<< "int object\n"; goto BEGIN; } catch(char& ch) { cout<< "char object\n"; goto BEGIN; } catch(...) { cout<< "other object\n"; goto BEGIN; } _getch(); }

138

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪Output:‬‬ ‫‪-1‬‬ ‫‪other object‬‬ ‫‪0‬‬ ‫‪int object‬‬ ‫‪1‬‬ ‫‪char object‬‬ ‫‪2‬‬

‫)…(‪ catch‬ﻫﺮ ﮔﻮﻧﻪ ‪ exception‬را ﻛﻪ ﺗﺎ ﺑﻪ ﺣﺎل ﮔﺮﻓﺘﻪ ﻧﺸﺪه ﺑﺎﺷﺪ ﻣﻲﮔﻴﺮد‪ .‬ﻣﺜﺎل ﺑﻌﺪي ﻛﻤﻲ ﻛﺎﺑﺮدي ﺗﺮ‬ ‫اﺳﺖ‪ .‬در اﻳﻦ ﻣﺜﺎل از ‪ new‬ﺑﺮاي ﮔﺮﻓﺘﻦ ﺣﺎﻓﻈﻪ اﺳﺘﻔﺎده ﺷﺪه اﺳﺖ‪ .‬اﮔﺮ ‪ new‬ﻧﺘﻮاﻧﺪ ﺣﺎﻓﻈﻪي ﻣﻮرد ﻧﻴﺎز را اﺧﺬ ﻛﻨﺪ‬ ‫ﺻﻔﺮ ﺑﺮﻣﻲﮔﺮداﻧﺪ )ﻣﻌﻤﻮﻻ در ﻣﻮرد ﺻﻔﺮ ﺳﺨﺖ ﮔﻴﺮيﻫﺎي ﻣﺮﺑﻮط ﺑﻪ ﺗﺒﺪﻳﻞ ﻧﻮع ﻛﻢ ﺗﺮ اﺳﺖ(‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪BEGIN:‬‬ ‫;‪char* c‬‬ ‫‪try‬‬ ‫{‬ ‫;]‪c = new char [99999999‬‬ ‫)‪if(c == 0‬‬ ‫;‪throw 0‬‬ ‫}‬ ‫)‪catch(...‬‬ ‫{‬ ‫;"‪cout<< "Low Memory‬‬ ‫}‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output: empty‬‬

‫ ‪ static‬درون ‪& ' B‬‬

‫ﻣﺘﻐﻴﺮﻫﺎﻳﻲ ﻛﻪ در ﻳﻚ ﺗﺎﺑﻊ ﺗﻌﺮﻳﻒ ﻣﻲﺷﻮﻧﺪ ﺑﺎ ﺧﺮوج از آن ﻧﺎﺑﻮد ﻣﻲﺷﻮﻧﺪ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﻧﺎﺑﻮد ﻧﺸﻮﻧﺪ ﻣﻮﻗﻊ ﺗﻌﺮﻳﻒ‬ ‫ﺑﺎﻳﺪ از ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ static‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ .‬اﮔﺮ ﻳﻚ ﻣﺘﻐﻴﺮ ﺑﻪ ﻃﻮر ‪ static‬ﺗﻌﺮﻳﻒ ﺷﻮد در اوﻟﻴﻦ ﻓﺮاﺧﻮاﻧﻲ‬ ‫ﺗﺎﺑﻊ‪ ،‬اﻳﺠﺎد و ‪ initialize‬ﻣﻲﺷﻮد )ﻳﻌﻨﻲ ﻣﻘﺪار اوﻟﻴﻪ داده ﻣﻲﺷﻮد( و ﺗﺎ آﺧﺮ ﺑﺮﻧﺎﻣﻪ از ﺑﻴﻦ ﻧﻤﻲرود‪ .‬اﮔﺮ ﻣﻘﺪار اوﻟﻴﻪ‬

‫‪139‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻣﺸﺨﺺ ﻧﺸﺪه ﺑﺎﺷﺪ‪ ،‬ﻣﻘﺪار اوﻟﻴﻪ‪ ،‬ﺻﻔﺮ در ﻧﻈﺮ ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد‪ .‬ﻣﺜﺎل زﻳﺮ اﺳﺘﻔﺎده از ﻳﻚ ﻣﺘﻐﻴﺮ ‪ static‬را ﻧﺸﺎن‬ ‫ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪-1;// executed only once‬‬ ‫;"‪even\n‬‬

‫"<<‬

‫;"‪odd\n‬‬

‫" <<‬

‫)‪i < 10; i++‬‬

‫)(‪void f‬‬ ‫{‬ ‫= ‪static int a‬‬ ‫;‪a++‬‬ ‫)‪if(a % 2 == 0‬‬ ‫‪cout<< a‬‬ ‫‪else‬‬ ‫‪cout<< a‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪for(int i = 0‬‬ ‫;)(‪f‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪0 even‬‬ ‫‪1 odd‬‬ ‫‪2 even‬‬ ‫‪3 odd‬‬ ‫‪4 even‬‬ ‫‪5 odd‬‬ ‫‪6 even‬‬ ‫‪7 odd‬‬ ‫‪8 even‬‬ ‫‪9 odd‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ‪ static int a = -1‬ﺗﻨﻬﺎ ﻳﻚ ﺑﺎر اﺟﺮا ﻣﻲﺷﻮد و در ﻓﺮاﺧﻮاﻧﻲﻫﺎي ﻣﻜﺮر )(‪ f‬دوﺑﺎره ﺑﻪ‬ ‫وﺟﻮد ﻧﻤﻲآﻳﺪ و ﻣﻘﺪار اوﻟﻴﻪي آن ﻳﻌﻨﻲ ‪ -1‬ﻫﻢ ﺗﻨﻬﺎ ﻳﻚ ﺑﺎر ﺑﻪ آن داده ﻣﻲﺷﻮد‪ .‬در ﻓﺮاﺧﻮاﻧﻲﻫﺎي ﺑﻌﺪي ِ )(‪f‬‬

‫ﻣﻘﺪار ﻗﺒﻠﻲ ‪ a‬ﺑﺎ ‪ a++‬ﺗﻐﻴﻴﺮ ﻣﻲﻛﻨﺪ‪ .‬ﺑﺮ ﺣﺴﺐ اﻳﻦ ﻛﻪ ‪ a‬زوج ﻳﺎ ﻓﺮد اﺳﺖ ﭘﻴﺎم ﻣﻨﺎﺳﺐ ﭼﺎپ ﻣﻲﺷﻮد‪.‬‬

‫ ‪register‬‬

‫‪ CPU register 1 register‬ﺣﺎﻓﻈﻪاي در ‪ CPU‬اﺳﺖ ﻛﻪ ﻣﻌﻤﻮﻻ ﺑﺮاي ﺳﺮﻋـﺖ ﺑﺎﻻﺗﺮ در ﺑﺮﺧﻲ ﺟﺎﻫﺎي‬ ‫ﺑﺮﻧﺎﻣﻪ اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪ .‬ﻣﺜﻼ ﺷﻤﺎرﺷﮕﺮ ﺣﻠﻘﻪي ‪ for‬را ﺑﺮاي ﺳﺮﻋـﺖ ﺑﻴﺶ ﺗﺮ ﻣﻲﺷﻮد از ‪CPU register‬‬

‫‪140‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﮔﺮﻓﺖ ﻧﻪ از ‪ .RAM‬ﺑﺮاي ﺗﻌﺮﻳﻒ ﻣﺘﻐﻴﺮ در ‪ register‬ﻛﺎﻓﻲ اﺳﺖ ﻗﺒﻞ از ﺗﻌﺮﻳﻒ ﻋﺎدي‪ ،‬ﻛﻠﻤﻪي ﻛﻠﻴﺪي‬ ‫‪ register‬را ﻗﺮار دﻫﻴﻢ‪ .‬ﻣﺜﻼ‬ ‫;‪register int i = 0‬‬

‫اﻣﺎ ‪compiler‬ﻫﺎي ‪ Microsoft‬ﺑﻪ آن ﺑﻲ ﺗﻮﺟﻪ ﻫﺴﺘﻨﺪ و ‪register‬ﻫﺎ را ﺧﻮدﺷﺎن اﻧﺘﺨﺎب ﻣﻲﻛﻨﻨﺪ‪.‬‬ ‫‪compiler‬ﻫﺎي ‪ Borland‬ﻫﻢ ﺑﺮاي ﺗﺨﺼﻴﺺ ﺣﺎﻓﻈﻪ از ‪ register‬ﻧﺎز زﻳﺎدي دارﻧﺪ‪ .‬ﺑﺮاي ﻫﻤﻴﻦ ﻣﻲﺗﻮاﻧﻴﺪ آن را‬ ‫ﻓﺮاﻣﻮش ﻛﻨﻴﺪ‪.‬‬

‫ ‪auto‬‬

‫داﺧﻞ ﻫﺮ ﺑﻠﻮك ﻣﻲﺷﻮد ﺑﻪ ﺟﺎي‬ ‫;‪int i = 5‬‬

‫ﻧﻮﺷﺖ‪:‬‬ ‫;‪auto int i = 5‬‬

‫ﻛﻪ ﻓﺮﻗﻲ ﺑﺎ ﻗﺒﻠﻲ ﻧﺪارد ﻓﻘﻂ اﻧﮕﺎر ﺗﺄﻛﻴﺪ ﻛﺮدهاﻳﻢ ﺑﺎ ﺧﺮوج از ﺑﻠﻮك ﻣﺘﻐﻴﺮ ﺑﻪ ﻃﻮر اﺗﻮﻣﺎﺗﻴﻚ از ﺑﻴﻦ ﻣﻲرود‪.‬‬

‫ ‪inline‬‬

‫ﺑﻪ اﻳﻦ ﺗﺎﺑﻊ ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫)‪int plus(int a,int b‬‬ ‫{‬ ‫;‪return a + b‬‬ ‫}‬

‫ﺣﺎل اﮔﺮ در )(‪ main‬ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;)‪int b = f(2,3‬‬

‫ﻣﻨﻈﻮر ﻣﺎ اﻳﻦ اﺳﺖ ﻛﻪ‬ ‫;‪int b = 2 + 3‬‬

‫اﻣﺎ ﻣﻮﻗﻊ اﺟﺮاي ;)‪ int b=f(2,3‬ﭼﻨﺪ ﻣﺘﻐﻴﺮ ﺑﻪ وﺟﻮد ﻣﻲآﻳﻨﺪ‪ ،‬ﻣﻘﺪار دﻫﻲ ﻣﻲﺷﻮﻧﺪ و ﺑﻌﺪ ﻧﺎﺑﻮد ﻣﻲﺷﻮﻧﺪ‪ .‬اﻳﻦ‬ ‫ﻫﺰﻳﻨﻪي ﺳﻨﮕﻴﻨﻲ از ﻧﻈﺮ زﻣﺎن و ﺣﺎﻓﻈﻪ اﺳﺖ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﺑﻪ ‪ compiler‬ﭘﻴﺶ ﻧﻬﺎد ﻛﻨﻴﻢ از اﻳﺠﺎد اﻳﻦ ﻣﺘﻐﻴﺮﻫﺎي‬

‫‪141‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫اﺿﺎﻓﻪ ﺻﺮف ﻧﻈﺮ ﻛﻨﺪ و ;‪ int b=2+3‬را در ﻧﻈﺮ ﺑﮕﻴﺮد ﻣﻲﺗﻮاﻧﻴﻢ از ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ inline‬ﻗﺒﻞ از ﺗﻌﺮﻳﻒ‬ ‫ﺗﺎﺑﻊ اﺳﺘﻔﺎده ﻛﻨﻴﻢ و ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫)‪inline int plus(int a,int b‬‬ ‫{‬ ‫;‪return a + b‬‬ ‫}‬

‫اﻟﺒﺘﻪ اﻳﻦ ﻓﻘﻂ ﻳﻚ ﭘﻴﺶ ﻧﻬﺎد ﺑﻪ ‪ compiler‬اﺳﺖ‪ .‬در ‪compiler‬ﻫﺎي ‪ Microsoft‬ﺑﻪ ﺟﺎي ‪ inline‬از‬ ‫ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ __forceinline‬ﻫﻢ ﻣﻲﺷﻮد اﺳﺘﻔﺎده ﻛﺮد ﻛﻪ ﻓﺸﺎر ﺑﻴﺶ ﺗﺮي ﺑﻪ ‪ compiler‬ﺑﺮاي ‪inline‬‬ ‫ﻛﺮدن ﺗﺎﺑﻊ ﻣﻲآورد‪ .‬در ﻫﺮ ﺣﺎل اﻳﻦ ﻛﻪ ﺗﺎﺑﻊ‪ inline ،‬ﺑﺸﻮد ﻳﺎ ﻧﻪ ﺑﻪ ‪ compiler‬ﺑﺴﺘﮕﻲ دارد‪ .‬روش دﻳﮕﺮي را‬ ‫ﻫﻢ ﺑﺮاي اﻳﺠﺎد ﺗﺎﺑﻊﻫﺎي ‪ inline‬ﺑﺎ اﺳﺘﻔﺎده از دﺳﺘﻮرﻫﺎي ‪ preprocessor‬ﻫﺴﺖ ﻛﻪ در آن ‪ inline‬ﺷﺪن ﻗﻄﻌﻲ‬ ‫اﺳﺖ‪ .‬در ﻓﺼﻞ ﭼﻬﺎرم ﺑﺎ آن آﺷﻨﺎ ﻣﻲﺷﻮﻳﺪ‪.‬‬

‫ ‪enum‬‬

‫اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﭼﻨﺪ ﺛﺎﺑﺖ ﻋﺪدي را ﻫﻢ زﻣﺎن و ﺑﻪ راﺣﺘﻲ ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ ﻣﻲﺗﻮاﻧﻴﻢ از ﻛﻠﻤﻪ ﻛﻠﻴﺪي ‪ enum‬اﺳﺘﻔﺎده‬ ‫ﻛﻨﻴﻢ‪ .‬ﺑﺎ ﻧﻮﺷﺘﻦ‬ ‫;}‪enum A {a = 10, b = 20, c = 100‬‬

‫ﻧﻮع ﺟﺪﻳﺪي ﺑﺎ ﻧﺎم ‪ A‬ﺗﻌﺮﻳﻒ ﻣﻲﺷﻮد و ﺑﻪ ﻋﻼوه ﺛﺎﺑﺖﻫﺎي ‪ a‬ﺑﺎ ﻣﻘﺪار ‪ b ،10‬ﺑﺎ ﻣﻘﺪار ‪ 20‬و ‪ c‬ﺑﺎ ﻣﻘﺪار ‪100‬‬ ‫ﺗﻌﺮﻳﻒ ﻣﻲﺷﻮﻧﺪ ﻛﻪ ﻧﻮع ﻫﻤﻪي آنﻫﺎ ‪ A‬اﺳﺖ‪ .‬اﻳﻦ ﻣﺜﺎل ﻫﻤﻪ ﭼﻴﺰ را روﺷﻦ ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫;}‪enum A {a = 10, b = 20, c = 100‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪cout<< a << endl‬‬ ‫;‪cout<< b << endl‬‬ ‫;‪cout<< c << endl‬‬ ‫;)(‪cout<< typeid(a).name‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪10‬‬

‫‪142‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪20‬‬ ‫‪100‬‬ ‫‪A‬‬ ‫‪Output(Visual C++ 2005):‬‬ ‫‪10‬‬ ‫‪20‬‬ ‫‪100‬‬ ‫‪enum A‬‬

‫اﮔﺮ در اﻳﻦ ﻣﺜﺎل ﺑﻪ ‪ b‬و ‪ c‬ﻣﻘﺪار ﻧﺪﻫﻴﻢ‪ compiler ،‬ﺑﻪ ﺗﺮﺗﻴﺐ ﺑﻪ آنﻫﺎ ﻣﻘﺪارﻫﺎي ‪ 11‬و ‪ 12‬ﻣﻲدﻫﺪ‪ .‬اﻳﻦ ﺑﺮﻧﺎﻣﻪ‬ ‫را ﺑﺒﻴﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫;}‪enum A {a, b = 10, c, d, e = 500, f, g‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪cout<< a << endl‬‬ ‫;‪cout<< b << endl‬‬ ‫;‪cout<< c << endl‬‬ ‫;‪cout<< d << endl‬‬ ‫;‪cout<< e << endl‬‬ ‫;‪cout<< f << endl‬‬ ‫;‪cout<< g << endl‬‬ ‫‪//g = 12; // error‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪0‬‬ ‫‪10‬‬ ‫‪11‬‬ ‫‪12‬‬ ‫‪500‬‬ ‫‪501‬‬ ‫‪502‬‬

‫ﭘﺲ اﮔﺮ ﺑﻪ ﻳﻜﻲ از ﺛﺎﺑﺖﻫﺎي ‪ enum‬ﻣﻘﺪار ﻧﺪﻫﻴﻢ ﺧﻮد ‪ compiler‬ﻣﻘﺪاري ﺑﻪ آن ﻣﻲﻫﺪ ﺑﺮاﺑﺮ ﺑﺎ »ﺛﺎﺑﺖ ﻗﺒﻠﻲ ﺑﻪ‬ ‫اﺿﺎﻓﻪي ﻳﻚ«‪ .‬ﺑﻪ ‪ a‬ﻣﻘﺪاري ﻧﺪادهاﻳﻢ و ﻗﺒﻞ از آن ﻫﻢ ﭼﻴﺰي در ‪ enum‬ﻧﻴﺴﺖ و ‪ compiler‬ﻣﻘﺪار ﺻﻔﺮ را ﺑﻪ‬ ‫آن داده‪.‬‬ ‫ﻣﻲﺗﻮاﻧﻴﻢ از ﻧﻮع ‪ enum‬ﻣﺘﻐﻴﺮي ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ ﻛﻪ ﻗﺮار اﺳﺖ ﺗﻨﻬﺎ ﻣﻘﺪارﻫﺎﻳﻲ را ﺑﮕﻴﺮد ﻛﻪ ﺛﺎﺑﺖﻫﺎي ‪ enum‬آنﻫﺎ‬ ‫را ﮔﺮﻓﺘﻪاﻧﺪ‪:‬‬

‫‪143‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <conio.h> #include <iostream> using namespace std; enum A {a, b, c}; int main() { A x = c; // x++; // can be an error cout<< sizeof(x) << endl << x; _getch(); }

Output (BDS 2006): 1 2 Output (Visual C++ 2005): 4 2

4 ‫ اﻧﺪازهي آن را‬Visual C++ 2005 ‫ را ﻳﻚ ﺑﺎﻳﺖ ﻣﻲﮔﻴﺮد وﻟﻲ‬enum ‫ اﻧﺪارهي‬BDS 2006 ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬ ‫ را ﭼﻬﺎر ﺑﺎﻳﺖ ﺑﮕﻴﺮد‬enum ‫ ﻫﻢ ﻳﻚ‬BDS 2006 ‫ ﺑﺮاي اﻳﻦ ﻛﻪ‬.‫ اﺳﺖ‬int ‫ﺑﺎﻳﺖ ﻣﻲﮔﻴﺮد ﻛﻪ ﺑﻪ اﻧﺪازهي ﻳﻚ‬ :‫ﺧﻂ زﻳﺮ را درﺳﺖ ﺑﻪ اول ﺑﺮﻧﺎﻣﻪ اﺿﺎﻓﻪ ﻛﻨﻴﺪ‬ #pragma option –b

‫راه دﻳﮕﺮ اﻳﻦ اﺳﺖ ﻛﻪ ﺑﺎ ﻣﻨﻮﻫﺎ ﻣﺴﻴﺮ زﻳﺮ‬ Project | Options… | C++ Compiler (bcc32) | compiling x++ ‫ در اﻳﻦ ﺣﺎﻟﺖ درﻣﺜﺎل ﺑﺎﻻ‬.‫ ﺗﻴﻚ ﺑﮕﺬارﻳﺪ‬Enums always integer sized(-b) ‫را ﺑﭙﻴﻤﺎﻳﻴﺪ و ﻣﻘﺎﺑﻞ‬

.‫ ﻧﻤﻲدﻫﺪ‬error ‫دﻳﮕﺮ‬ -‫ ﻣﻲ‬BDS 2006 ‫ ﻧﻤﻲﺷﻮد ﮔﺮﻓﺖ وﻟﻲ در‬cin ‫ را ﺑﺎ‬enum ‫ ﻳﻚ‬Visul C++ 2005 ‫درﭘﺎﻳﺎن ﺑﮕﻮﻳﻢ ﻛﻪ در‬ .‫ ﻫﻢ ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد‬warning ‫ﺷﻮد وﻟﻲ ﻳﻚ‬ :‫ﺣﺎﻻ ﺑﻪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻧﮕﺎه ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; enum {aa = 100 , bb, cc}; int main() { cout<< bb << endl; cout<< typeid(cc).name();

144

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ _getch(); }

Output (BDS 2006): 101 enum Output (Visual C++ 2005): 101 enum <unnamed-tag>

.‫ ﺑﺮاي ﺗﻌﺮﻳﻒ ﺛﺎﺑﺖﻫﺎ ﻣﻨﺎﺳﺐ اﺳﺖ‬enum ‫ اﻳﻦ ﺟﻮر ﺑﻪ ﻛﺎر ﺑﺮدن‬.‫ در اﻳﻦ ﺟﺎ ﺑﺪون اﺳﻢ ﺑﻪ ﻛﺎر رﻓﺘﻪ‬enum :‫ اﺟﺮا ﻧﻤﻲﺷﻮد‬BDS 2006 ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ در‬ #include <conio.h> #include <iostream> using namespace std; enum A { aa = 100, bb, cc }; int main() { cout<< A::bb << endl; cout<< typeid(A::bb).name() << endl; _getch(); }

Output (Visual C++ 2005): 101 enum A

Visual C++ 2005 ‫ اﻳﻦ در‬.A::b ‫ ﻧﻮﺷﺘﻪ ﺷﺪه‬b ‫ ﻣﻲﮔﻴﺮد اﻳﻦ اﺳﺖ ﻛﻪ ﺑﻪ ﺟﺎي‬BDS 2006 ‫ﺧﻄﺎﻳﻲ ﻛﻪ‬ .‫ اﺳﺖ‬warning ‫ﻓﻘﻂ ﻳﻚ‬ ‫ وﻟﻲ‬static ‫ ﻣﻲﺷﻮد ﻧﻮﺷﺖ‬enum ‫ ﻣﻮﻗﻊ ﺗﻌﺮﻳﻒ ﺟﻠﻮي‬Visual C++ 2005 ‫ﻧﻜﺘﻪي دﻳﮕﺮ اﻳﻦ اﺳﺖ ﻛﻪ در‬ .‫ از اﻳﻦ ﺧﻄﺎ ﻣﻲﮔﻴﺮد‬BDS 2006 :‫ را ﻧﺸﺎن ﻣﻲدﻫﺪ‬typedef ‫ ﺑﺎ اﺳﺘﻔﺎده از‬enum ‫ﺑﺮﻧﺎﻣﻪي ﺑﻌﺪي ﺗﻌﺮﻳﻒ ﻳﻚ‬ #include <conio.h> #include <iostream> using namespace std;

145

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪typedef enum‬‬ ‫{‬ ‫‪aa = 100,‬‬ ‫‪bb,‬‬ ‫‪cc‬‬ ‫;‪} AA‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪cout<< bb << endl‬‬ ‫;‪cout<< typeid(bb).name() << endl‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪101‬‬ ‫‪AA‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫‪101‬‬ ‫‪enum AA‬‬

‫)را ه @? ! ‬

‫ﻫﻤﺎن ﻃﻮر ﻛﻪ ﻳﻚ آراﻳﻪي ﻣﻌﻤﻮﻟﻲ را ﺑﻪ ﺻﻮرت‬ ‫;]‪int a[20‬‬

‫ﺗﻌﺮﻳﻒ ﻣﻲﻛﻨﻴﻢ‪ ،‬ﻣﻲﺗﻮاﻧﻴﻢ ﻳﻚ آراﻳﻪي دوﮔﺎﻧﻪ ﻣﺜﻞ‬ ‫;]‪int b[20][30‬‬

‫ﻳﺎ ﻳﻚ آراﻳﻪي ﺳﻪ ﮔﺎﻧﻪ ﻣﺜﻞ‬ ‫;]‪int c[20][30][50‬‬

‫ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‪ .‬ﺑﺎ ‪ b‬ﺑﺎﻳﺪ ﻣﺜﻞ ﻳﻚ **‪ int‬و ﺑﺎ ‪ c‬ﺑﺎﻳﺪ ﻣﺜﻞ ﻳﻚ ***‪ int‬رﻓﺘﺎر ﻛﺮد‪.‬‬ ‫ﻣﺜﺎل زﻳﺮ ﺟﺪول ﺿﺮب را ﻣﻲﺳﺎزد‪ .‬در ‪conio.h‬ي ﻛﻪ ﺗﻮﺳﻂ ‪ Borland‬ﺗﻨﻈﻴﻢ ﺷﺪه‪ ،‬ﺗﺎﺑﻊ )(‪ gotoxy‬ﻫﺴﺖ‬ ‫ﻛﻪ ‪) cursor‬ﻣﻜﺎن ﻧﻤﺎي ﭼﺸﻤﻚ زن ﻛﻪ ﻣﺤﻞ ﻧﻮﺷﺘﻦ را در ﺻﻔﺤﻪي ﻧﻤﺎﻳﺶ ﻧﺸﺎن ﻣﻲدﻫﺪ( را ﺑﻪ ﻣﻜﺎن ﺧﺎﺻﻲ از‬ ‫ﺻﻔﺤﻪي ﻧﻤﺎﻳﺶ ﻣﻲﺑﺮد‪ .‬ﻣﺜﻼ‬ ‫;)‪gotoxy(10,10‬‬ ‫;"‪cout<< "hello‬‬

‫‪146‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫اول ‪ cursor‬را ﺑﻪ ﺧﻂ دﻫﻢ ﻣﻲﺑﺮد ﺑﻌﺪ ‪ 10‬واﺣﺪ ﺑﻪ ﺳﻤﺖ راﺳﺖ ﻣﻲرود و ﺑﻌﺪ ‪ hello‬را ﭼﺎپ ﻣﻲﻛﻨﺪ‪ .‬در‬ ‫‪compiler‬ﻫﺎي ‪ Microsoft‬اﻳﻦ ﺗﺎﺑﻊ وﺟﻮد ﻧﺪارد‪ .‬ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻛﻪ ﺟﺪول ﺿﺮب را ﻧﻤﺎﻳﺶ ﻣﻲ‪-‬‬ ‫دﻫﺪ در ‪ Visual C++ 2005‬اﺟﺮا ﻧﻤﻲﺷﻮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)]‪void Matrix(int a[10][10‬‬ ‫{‬ ‫;‪int i,j‬‬ ‫)‪for(i = 0; i < 10; i++‬‬ ‫)‪for(j = 0; j < 10; j++‬‬ ‫;)‪a[i][j] = (i+1) * (j+1‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;]‪int a[10][10‬‬ ‫;)‪Matrix(a‬‬ ‫)‪for(int i = 0; i < 10; i++‬‬ ‫{‬ ‫)‪for(int j = 0; j < 10; j++‬‬ ‫{‬ ‫;)‪gotoxy(3*(i+1),j+1‬‬ ‫;]‪cout<< a[i][j‬‬ ‫}‬ ‫}‬ ‫;)(‪getch‬‬ ‫}‬

‫‪10‬‬ ‫‪20‬‬ ‫‪30‬‬ ‫‪40‬‬ ‫‪50‬‬ ‫‪60‬‬ ‫‪70‬‬ ‫‪80‬‬ ‫‪90‬‬ ‫‪100‬‬

‫)ﻫﺸﺖ ﻧﻪ ﺗﺎ؟ اﮔﺮ ﺑﻠﺪ ﻧﻴﺴﺘﻴﻦ ﭘﺲ از ﻛﻼس ﺑﺮوﻳﺪ ﺑﻴﺮون !‬

‫‪9‬‬ ‫‪18‬‬ ‫‪27‬‬ ‫‪36‬‬ ‫‪45‬‬ ‫‪54‬‬ ‫‪63‬‬ ‫‪72‬‬ ‫‪81‬‬ ‫‪90‬‬

‫‪8‬‬ ‫‪16‬‬ ‫‪24‬‬ ‫‪32‬‬ ‫‪40‬‬ ‫‪48‬‬ ‫‪56‬‬ ‫‪64‬‬ ‫‪72‬‬ ‫‪80‬‬

‫‪7‬‬ ‫‪14‬‬ ‫‪21‬‬ ‫‪28‬‬ ‫‪35‬‬ ‫‪42‬‬ ‫‪49‬‬ ‫‪56‬‬ ‫‪63‬‬ ‫‪70‬‬

‫‪6‬‬ ‫‪12‬‬ ‫‪18‬‬ ‫‪24‬‬ ‫‪30‬‬ ‫‪36‬‬ ‫‪42‬‬ ‫‪48‬‬ ‫‪54‬‬ ‫‪60‬‬

‫‪5‬‬ ‫‪10‬‬ ‫‪15‬‬ ‫‪20‬‬ ‫‪25‬‬ ‫‪30‬‬ ‫‪35‬‬ ‫‪40‬‬ ‫‪45‬‬ ‫‪50‬‬

‫‪Output (BDS 2006):‬‬ ‫‪1 2 3 4‬‬ ‫‪2 4 6 8‬‬ ‫‪3 6 9 12‬‬ ‫‪4 8 12 16‬‬ ‫‪5 10 15 20‬‬ ‫‪6 12 18 24‬‬ ‫‪7 14 21 28‬‬ ‫‪8 16 24 32‬‬ ‫‪9 18 27 36‬‬ ‫‪10 20 30 40‬‬

‫(‬

‫ﺣﺎﻻ ﺑﺎﻳﺪ وارد ﺟﺰﺋﻴﺎت ﺧﺴﺘﻪ ﻛﻨﻨﺪه ﺑﺸﻮﻳﻢ‪ .‬اوﻻ آراﻳﻪ ﻣﻮﻗﻊ ورود ﺑﻪ ﺗﺎﺑﻊ ﭼﻪ ﺗﻐﻴﻴﺮي ﻣﻲﻛﻨﺪ؟‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪147‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ void f(int a[10][10]) { cout<<"\nin f():\n" << typeid(a).name(); } int main() { int a[10][10]; cout<< typeid(a).name() << endl; f(a); getch(); }

Output (BDS 2006): int[10][10] in f(): int ( *)[10] Output (Visual C++ 2005): int [10][10] in f(): int (*)[10]

:‫ ﻣﻲﺗﻮاﻧﺪ ﻫﺮ ﻳﻚ از ﺣﺎﻟﺖﻫﺎي زﻳﺮ را داﺷﺘﻪ ﺑﺎﺷﺪ و اﻳﻦﻫﺎ ﺑﺎ ﻫﻢ ﻓﺮﻗﻲ ﻧﺪارﻧﺪ‬f()‫در واﻗﻊ ﭘﺎراﻣﺘﺮ‬ void f(int a[222][10]) void f(int a[][10]) void f(int (*a)[10])

:‫ﻫﻤﻴﻦ در ﻣﻮرد آراﻳﻪﻫﺎي ﺳﻪ ﮔﺎﻧﻪ و ﺑﻴﺶﺗﺮ ﻫﻢ درﺳﺖ اﺳﺖ‬ #include <conio.h> #include <iostream> using namespace std; void f(int a[10][10][24]) { cout<<"\nin f():\n" << typeid(a).name(); } int main() { int a[10][10][24]; cout<< typeid(a).name() << endl; f(a); getch(); }

Output (BDS 2006): int[10][10][24] in f(): int ( *)[10][24]

148

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪Output (Visual C++ 2005):‬‬ ‫]‪int [10][10][24‬‬ ‫‪in f():‬‬ ‫]‪int (*)[10][24‬‬

‫ﺣﺎﻻ اﮔﺮ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;]‪int a[10][24‬‬

‫ﻓﻜﺮ ﻣﻲﻛﻨﻴﺪ ]‪ a[5‬ﻣﻌﻨﻲ داﺷﺘﻪ ﺑﺎﺷﺪ ﻳﺎ ﻧﻪ؟ ﻣﻌﻨﻲ دارد و ﻣﻌﻨﻲ آن را در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻣﻲﺑﻴﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;]‪int a[10][24‬‬ ‫;]‪int b[24‬‬ ‫;‪cout<< typeid(a[5]).name() << endl‬‬ ‫;)(‪cout<< typeid(b).name‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫]‪int[24‬‬ ‫]‪int[24‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫]‪int [24‬‬ ‫]‪int [24‬‬

‫]‪ a[5‬ﻳﻚ ﺧﻮد ﻳﻚ آراﻳﻪي ‪ 24‬ﺗﺎﻳﻲ از ‪int‬ﻫﺎ اﺳﺖ‪ .‬ﭘﺲ ﺑﺎ ﻧﻮﺷﺘﻦ‬ ‫;]‪int a[10][24‬‬

‫ﻣﺎ ‪ 10‬آراﻳﻪي ‪ 24‬ﺗﺎﻳﻲ ﺗﻌﺮﻳﻒ ﻣﻲﻛﻨﻴﻢ ﻛﻪ اﺗﻔﺎﻗﺎ ﺣﺎﻓﻈﻪي آنﻫﺎ ﻫﻢ ﭘﺸﺖ ﺳﺮ ﻫﻢ ﻗﺮار دارد‪ .‬ﭘﺲ ﻣﻲﺗﻮاﻧﻴﻢ‬ ‫ﺑﮕﻮﻳﻴﻢ آراﻳﻪي دوﮔﺎﻧﻪ آراﻳﻪاي از آراﻳﻪﻫﺎي ﻣﻌﻤﻮﻟﻲ اﺳﺖ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﻣﻄﻤﺌﻦ ﺑﺸﻮﻳﺪ ﻛﻪ ﺣﺎﻓﻈﻪﻫﺎ ﭘﺸﺖ ﺳﺮ ﻫﻢ‬ ‫ﻫﺴﺘﻨﺪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ را ﺑﺒﻴﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;}‪int a[3][3] = {1,2,3,4,5,6,7,8,9‬‬ ‫;‪int* p = (int*)a‬‬ ‫)‪for(int i = 0; i < 9; i++‬‬ ‫;" " << ]‪cout<< p[i‬‬ ‫;)(‪getch‬‬

‫‪149‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫}‬

‫‪9‬‬

‫‪8‬‬

‫‪7‬‬

‫‪6‬‬

‫‪5‬‬

‫‪4‬‬

‫‪Output:‬‬ ‫‪1 2 3‬‬

‫‪ p‬ﻳﻚ اﺷﺎره ﮔﺮ ﺑﻪ اول ﺣﺎﻓﻈﻪي ﺗﺨﺼﻴﺺ داده ﺷﺪه ﺑﻪ آراﻳﻪي ‪ a‬اﺳﺖ‪ .‬اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻧﺸﺎن ﻣﻲدﻫﺪ ﻛﻪ ﺣﺎﻓﻈﻪي‬ ‫آرﻳﻪي دوﮔﺎﻧﻪ در ﻳﻚ ﺟﺎ ﻗﺮار دارد و ﭼﻨﺪ ﺗﻜﻪ و در ﺟﺎﻫﺎي ﻣﺨﺘﻠﻒ ﻧﻴﺴﺖ‪ .‬ﻣﻲﺗﻮاﻧﺴﺘﻢ ﺑﻪ ﺟﺎي‬ ‫;‪int* p = (int*)a‬‬

‫ﺑﻨﻮﻳﺴﻢ‪:‬‬ ‫;)]‪int* p = &(a[0][0‬‬

‫ﭼﺮا؟‬ ‫ﻣﺴﺄﻟﻪي دﻳﮕﺮ دادن ﻣﻘﺪار اوﻟﻴﻪ اﺳﺖ ﻛﻪ در ﻣﺜﺎل ﻗﺒﻠﻲ دﻳﺪﻳﺪ‪ .‬در ﻣﺜﺎلﻫﺎي زﻳﺮ ﻧﺤﻮهي دادن ﻣﻘﺪار اوﻟﻴﻪ و ﻣﺴﺎﺋﻞ‬ ‫ﻣﺮﺑﻮط ﺑﻪ آنﻫﺎ را ﺗﻮﺿﻴﺢ دادهام‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;}‪int a[3][3] = {1,2,3,4,5,6,7,8,9‬‬ ‫;]‪cout<< a[1][0‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪4‬‬

‫ﻣﻲداﻧﻴﻢ ﻛﻪ ]‪ a[3][3‬ﺳﻪ آراﻳﻪي ﺳﻪ ﺗﺎﻳﻲ اﺳﺖ‪ .‬در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ‪ 2 ،1‬و ‪ 3‬در آراﻳﻪي اول‪ 5 ،4 ،‬و ‪ 6‬در آراﻳﻪ‪-‬‬ ‫ي دوم و ‪ 8 ،7‬و ‪ 9‬در آراﻳﻪي ﺳﻮم ﻗﺮار ﻣﻲﮔﻴﺮد‪ .‬ﻣﻨﻈﻮر از ]‪ a[1][0‬آراﻳﻪي دوم و ‪ int‬اول آن اﺳﺖ ﻛﻪ‬ ‫ﻣﻘﺪارش ‪ 4‬اﺳﺖ‪ .‬ﺑﻪ ﻣﻨﻈﻮر راﺣﺘﻲ ِ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ‪ C++ ،‬ﺑﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ اﺟﺎزه ﻣﻲدﻫﺪ ﻛﻪ ﺑﺮاي روﺷﻦ ﺗﺮ ﺑﻮدن‬ ‫ﺑﺮﻧﺎﻣﻪ‪ ،‬ﻫﻨﮕﺎم دادن ﻣﻘﺪار اوﻟﻴﻪ از ‪) brace‬ﻳﻌﻨﻲ }{(ﻫﺎي اﺿﺎﻓﻪ ﻫﻢ اﺳﺘﻔﺎده ﻛﻨﺪ ﻳﻌﻨﻲ ﺑﻪ ﺟﺎي‬ ‫;}‪int a[3][3] = {1,2,3,4,5,6,7,8,9‬‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;}}‪int a[3][3] = {{1,2,3},{4,5,6},{7,8,9‬‬

‫ﻳﺎ ﺣﺘﻲ‬ ‫;}‪int a[3][3] = {1,2,3,{4,5,6},7,8,9‬‬

‫‪150‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺣﺎﻻ ﻓﺮض ﻛﻨﻴﺪ ﻣﻲﺧﻮاﻫﻴﻢ ﻳﻚ آراﻳﻪي دوﮔﺎﻧﻪ روي ‪ heap‬درﺳﺖ ﻛﻨﻴﻢ‪ .‬اﻳﻦ ﻛﺎر دو ﺣﺎﻟﺖ دارد‪ .‬ﮔﻔﺘﻢ ﻛﻪ‬ ‫آراﻳﻪي دوﮔﺎﻧﻪ‪ ،‬آراﻳﻪاي از آراﻳﻪﻫﺎﺳﺖ‪ .‬در ﺣﺎﻟﺖ اول‪ ،‬ﻣﺎ آراﻳﻪاي را ﻛﻪ از آراﻳﻪﻫﺎﺳﺖ روي ‪ stack‬ﺗﻌﺮﻳﻒ‬ ‫ﻣﻲﻛﻨﻴﻢ اﻣﺎ ﺧﻮد آراﻳﻪﻫﺎ را از ‪ heap‬ﻣﻲﮔﻴﺮﻳﻢ‪:‬‬ ‫;]‪int* a[10‬‬ ‫)‪for(int i = 0; i < 10; i++‬‬ ‫;]‪a[i] = new int [24‬‬

‫ﻛﻪ ﻣﺜﻞ‬ ‫;]‪int a[10][24‬‬

‫اﺳﺖ‪ .‬ﺣﺎﻟﺖ دوم اﻳﻦ اﺳﺖ ﻛﻪ ﻛﻼ ﻫﻤﻪ ﭼﻴﺰ روي ‪ heap‬ﺑﺎﺷﺪ‪:‬‬ ‫;‪int x = 3‬‬ ‫;‪int y = 4‬‬ ‫;]‪int** a = new int* [x‬‬ ‫)‪for(int i = 0; i < x; i++‬‬ ‫;]‪a[i] = new int [y‬‬

‫ﺧﻮﺑﻲ آن اﻳﻦ اﺳﺖ ﻛﻪ ﻫﻢ ‪ x‬و ﻫﻢ ‪ y‬ﻣﺘﻐﻴﺮ اﺳﺖ و ﻻزم ﻧﻴﺴﺖ ﺛﺎﺑﺖ ﺑﺎﺷﻨﺪ ﻣﻲداﻧﻴﺪ ﻛﻪ در‬ ‫;]‪int a[x][y‬‬

‫‪ x‬و ‪ y‬ﺑﺎﻳﺪ ﺛﺎﺑﺖ ﺑﺎﺷﻨﺪ‪ .‬در ﻣﺜﺎل زﻳﺮ از ﺣﺎﻟﺖ دوم اﺳﺘﻔﺎده ﺷﺪه اﺳﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫;‪" = " << a[i][j] << endl‬‬

‫)(‪int main‬‬ ‫{‬ ‫;‪int x = 3‬‬ ‫;‪int y = 4‬‬ ‫;]‪int** a = new int* [x‬‬ ‫)‪for(int i = 0; i < x; i++‬‬ ‫;]‪a[i] = new int [y‬‬ ‫)‪for(int i = 0; i < x; i++‬‬ ‫)‪for(int j = 0; j < y; j++‬‬ ‫;‪a[i][j] = i + j‬‬ ‫)‪for(int i = 0; i < x; i++‬‬ ‫)‪for(int j = 0; j < y; j++‬‬ ‫<< ‪cout<< i << " + " << j‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪0‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪1‬‬ ‫‪2‬‬

‫‪151‬‬

‫‪www.pupuol.com‬‬

‫=‬ ‫=‬ ‫=‬ ‫=‬ ‫=‬ ‫=‬

‫‪Output:‬‬ ‫‪0 + 0‬‬ ‫‪0 + 1‬‬ ‫‪0 + 2‬‬ ‫‪0 + 3‬‬ ‫‪1 + 0‬‬ ‫‪1 + 1‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬

‫‪2‬‬ ‫‪3‬‬ ‫‪0‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬

‫=‬ ‫=‬ ‫=‬ ‫=‬ ‫=‬ ‫=‬

‫‪+‬‬ ‫‪+‬‬ ‫‪+‬‬ ‫‪+‬‬ ‫‪+‬‬ ‫‪+‬‬

‫‪1‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪2‬‬ ‫‪2‬‬ ‫‪2‬‬

‫وﻗﺘﻲ ﺑﻪ اﻳﻦ ﺷﻜﻞ آراﻳﻪاي از ‪ heap‬درﻳﺎﻓﺖ ﻣﻲﻛﻨﻴﻢ روﺷﻦ اﺳﺖ ﻛﻪ ﻣﻤﻜﻦ اﺳﺖ ﺣﺎﻓﻈﻪﻫﺎي ﺗﺨﺼﻴﺺ داده ﺷﺪه‬ ‫ﭘﺸﺖ ﺳﺮ ﻫﻢ ﻧﺒﺎﺷﻨﺪ و ﺗﻜﻪ ﺗﻜﻪ و در ﺟﺎﻫﺎي ﻣﺨﺘﻠﻒ ﺑﺎﺷﻨﺪ‪ .‬ﻣﺜﺎل زﻳﺮ اﻳﻦ ﮔﻔﺘﻪ را ﺛﺎﺑﺖ ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;]‪int* a[3‬‬ ‫)‪for(int i = 0; i < 3; i++‬‬ ‫;]‪a[i] = new int [3‬‬ ‫;‪a[0][0] = 1, a[0][1] = 2, a[0][2] = 3‬‬ ‫;‪a[1][0] = 4, a[1][1] = 5, a[1][2] = 6‬‬ ‫;‪a[2][0] = 7, a[2][1] = 8, a[2][2] = 9‬‬ ‫;)]‪int* p = &(a[0][0‬‬ ‫)‪for(int i = 0; i < 9; i++‬‬ ‫;" " << ]‪cout<< p[i‬‬ ‫;‪cout<< endl‬‬ ‫;‪int* q = (int*) a‬‬ ‫)‪for(int i = 0; i < 9; i++‬‬ ‫;" " << ]‪cout<< q[i‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪1245112‬‬

‫‪3‬‬

‫‪9388112‬‬

‫‪9‬‬

‫‪1245036‬‬

‫‪12 4 5 6 12 7‬‬ ‫‪9388128 9388144 3‬‬

‫‪1 2 3‬‬ ‫‪9388112‬‬

‫‪Output (Visual C++ 2005):‬‬ ‫‪3552424‬‬

‫‪3562736‬‬

‫‪-33686019 -1414812757 -1414812757 0 0 589833‬‬ ‫‪3562968 3563040 -858993460 1245112 4269318 1‬‬

‫‪1 2 3‬‬ ‫‪3562896‬‬

‫وﻗﺘﻲ روي ‪ heap‬ﻫﺴﺘﻴﻢ ﻣﻲﺗﻮاﻧﻴﻢ آراﻳﻪﻫﺎي ﻋﺠﻴﺐ وﻏﺮﻳﺐ ﺗﺮي ﻫﻢ ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ ﻣﺜﻼ آراﻳﻪﻫﺎي از آراﻳﻪﻫﺎي ﺑﺎ‬ ‫ﻃﻮل ﻣﺘﻔﺎوت‪:‬‬ ‫;‪int x =5‬‬ ‫;]‪int** a = new int* [x‬‬ ‫)‪for(int i = 0; i < x; i++‬‬ ‫;]‪a[i] = new int [i+1‬‬

‫‪152‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫وﻟﻲ ﺑﺎﻳﺪ ﻣﻮاﻇﺐ ﺑﺎﺷﻴﻢ ﻛﻪ ﺑﻪ ﺣﺎﻓﻈﻪي اﺧﺘﺼﺎص ﻧﻴﺎﻓﺘﻪ دﺳﺖ ﻧﺰﻧﻴﻢ ﻣﺜﻼ در اﻳﻦ ‪a‬ي اﺧﻴﺮ ]‪ a[0][4‬ﺑﻪ ﺟﺎﻳﻲ از‬ ‫ﺣﺎﻓﻈﻪ اﺷﺎره دارد ﻛﻪ ﺗﺤﺖ ﻛﻨﺘﺮل ﻣﺎ ﻧﻴﺴﺖ و دﺳﺘﻜﺎري آن ﻣﻲﺗﻮاﻧﺪ ﺧﻄﺮﻧﺎك ﺑﺎﺷﺪ‪.‬‬ ‫اﮔﺮ آراﻳﻪاي )روي ‪ heap‬ﻳﺎ ‪ (stack‬ﻣﺜﻞ ‪ a‬داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﺑﺮاي دﺳﺘﻴﺎﺑﻲ ﺑﻪ ﻋﻨﺼﺮ دوم از آراﻳﻪي ﺳﻮم ﻣﻲﻧﻮﻳﺴﻴﻢ‬ ‫]‪ a[2][1‬وﻟﻲ ﻣﻲﺗﻮاﻧﻴﻢ از راه ﻃﺒﻴﻌﻲ ﻫﻢ اﺳﺘﻔﺎده ﻛﻨﻴﻢ و ﺑﻨﻮﻳﺴﻴﻢ )‪ *(*(a+2)+1‬ﺑﻪ ﻣﺜﺎل زﻳﺮ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;}‪int a[3][3] = {1,2,3,4,5,6,7,8,9‬‬ ‫;‪cout<< a[2][1] << endl‬‬ ‫;‪cout<< *(a[2] + 1) << endl‬‬ ‫;)‪cout<< *(*(a+2)+1‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪8‬‬ ‫‪8‬‬ ‫‪8‬‬

‫اﻳﻦ در ﻣﻮرد آراﻳﻪاي ﻣﺜﻞ‬ ‫;]‪int a[10‬‬

‫ﻫﻢ درﺳﺖ اﺳﺖ و ﻣﺜﻼ ]‪ a[2‬ﺑﺮاﺑﺮ اﺳﺖ ﺑﺎ )‪ *(a+2‬ﭼﻮن ‪ a‬ﻫﻤﺎن ]‪ &a[0‬و ‪ a+2‬ﻫﻤﺎن ]‪.&a[2‬‬ ‫در ﻧﻬﺎﻳﺖ ﺑﺎﻳﺪ ﺑﮕﻮﻳﻢ ﻛﻪ ﺗﻘﺮﻳﺒﺎ در ﻫﻤﻪي ﺟﺎﻫﺎﻳﻲ ﻛﻪ آراﻳﻪي دوﮔﺎﻧﻪ ﻻزم اﺳﺖ ﻣﻲﺷﻮد از آراﻳﻪي ﻣﻌﻤﻮﻟﻲ‬ ‫اﺳﺘﻔﺎده ﻛﺮد‪ :‬ﻓﺮض ﻛﻨﻴﺪ ‪ x‬و ‪ y‬دو ﻋﺪد ﺻﺤﻴﺢ ﻣﺜﺒﺖ و ﺛﺎﺑﺖ ﺑﺎﺷﻨﺪ‪ .‬وﻗﺘﻲ ﻣﻲﻧﻮﻳﺴﻴﻢ‪:‬‬ ‫;]‪int a[x][y‬‬

‫ﺑﻪ ﺗﻌﺪاد ﺣﺎﺻﻞ ﺿﺮب ‪ x‬و ‪ int ،y‬روي ﺣﺎﻓﻈﻪ ﺑﻪ وﺟﻮد ﻣﻲآﻳﺪ‪ .‬ﻣﺎ ﻣﻲﺗﻮاﻧﻴﻢ ﻫﻤﻴﻦ ﺣﺎﻓﻈﻪ را ﺑﺎ ﻧﻮﺷﺘﻦ‬ ‫;]‪int b[x*y‬‬

‫ﺑﻪ وﺟﻮد ﺑﻴﺎورﻳﻢ‪ .‬اﻣﺎ ﺳﺆال اﻳﻦ اﺳﺖ ﻛﻪ ﺑﻪ ﺟﺎي ]‪ a[i][j‬ﭼﻪ ﺑﻨﻮﻳﺴﻴﻢ؟ ﺧﻴﻠﻲ ﺳﺎده اﺳﺖ ﺑﺎﻳﺪ ﻧﻮﺷﺖ‬ ‫]‪ .b[i*y+j‬در واﻗﻊ ﻗﺮار اﺳﺖ ‪ x‬ﺗﺎ آراﻳﻪ ﺑﻪ ﻃﻮل ‪ y‬داﺷﺘﻪ ﺑﺎﺷﻴﻢ‪ a[i][j] .‬ﺑﻪ ﻋﻨﺼﺮ )‪(j+1‬ام از‬ ‫)‪(i+1‬اﻣﻴﻦ آراﻳﻪ اﺷﺎره دارد‪ .‬ﺑﺮاي ‪ ،b‬ﻣﻲﺗﻮاﻧﻴﻢ ﺗﺼﻮر ﻛﻨﻴﻢ ﻛﻪ اﻳﻦ ‪ x‬آراﻳﻪ‪ ،‬ﭘﺸﺖ ﺳﺮ ﻫﻢ ﻫﺴﺘﻨﺪ‪ .‬ﺑﺮاي‬

‫‪153‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫دﺳﺘﺮﺳﻲ ﺑﻪ )‪(i+1‬اﻣﻴﻦ آراﻳﻪ‪ ،‬ﺑﺎﻳﺪ ‪ i‬آراﻳﻪ ﺑﻪ ﻃﻮل ‪ y‬را ﭘﺸﺖ ﺳﺮ ﺑﮕﺬارﻳﻢ ﻳﻌﻨﻲ ‪ i*y‬و ﺑﻌﺪ ﺑﺮاي رﺳﻴﺪن ﺑﻪ‬ ‫)‪(j+1‬اﻣﻴﻦ ‪ int‬ﻣﻲﻧﻮﻳﺴﻴﻢ ]‪ .b[i*y+j‬ﺑﺮاي روﺷﻦ ﺷﺪن ﻣﻄﻠﺐ ﻓﺮض ﻛﻨﻴﺪ‬ ‫‪x == 3‬‬ ‫‪y == 4‬‬

‫ﺣﺎﻻ دو ﺷﻜﻞ ﻧﻤﺎﻳﺶ آراﻳﻪ را ﻣﻘﺎﻳﺴﻪ ﻛﻨﻴﺪ‪:‬‬ ‫]‪[2][3‬‬

‫]‪[2][2‬‬

‫]‪[2][1‬‬

‫]‪[2][0‬‬

‫]‪[1][3‬‬

‫]‪[1][2‬‬

‫]‪[1][1‬‬

‫]‪[1][0‬‬

‫]‪[0][3‬‬

‫]‪[0][2‬‬

‫]‪[0][1‬‬

‫]‪[0][0‬‬

‫]‪[11‬‬

‫]‪[10‬‬

‫]‪[9‬‬

‫]‪[8‬‬

‫]‪[7‬‬

‫]‪[6‬‬

‫]‪[5‬‬

‫]‪[4‬‬

‫]‪[3‬‬

‫]‪[2‬‬

‫]‪[1‬‬

‫]‪[0‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻋﻨﺼﺮ ]‪ [i][j‬ﻫﻤﺎن ﻋﻨﺼﺮ ]‪ [4*i+j‬اﺳﺖ‪ .‬ﻣﺜﻼ ﻋﻨﺼﺮ ]‪ [2][3‬ﺑﺮاﺑﺮ اﺳﺖ ﺑﺎ ﻋﻨﺼﺮ‬ ‫]‪[4*2+3‬ﻳﻌﻨﻲ ]‪.[11‬‬ ‫ﺑﺎ اﻳﻦ روش ﻣﻲﺗﻮاﻧﻴﻢ ﺣﺘﻲ در ‪ heap‬ﻫﻢ ﺣﺎﻓﻈﻪي ﭘﺸﺖ ﺳﺮ ﻫﻤﻲ ﺑﺮاي آراﻳﻪﻫﺎﻳﻲ ﻛﻪ در ﻋﻤﻞ دوﮔﺎﻧﻪ ﻫﺴﺘﻨﺪ‬ ‫داﺷﺘﻪ ﺑﺎﺷﻴﻢ‪ .‬ﻣﺜﺎل ﺟﺪول ﺿﺮب را ﺑﺎ اﻳﻦ روش و ﺑﺎ آراﻳﻪي ﻣﻌﻤﻮﻟﻲ ﺗﻜﺮار ﻣﻲﻛﻨﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)]‪void Matrix(int a[100‬‬ ‫{‬ ‫;‪int i,j‬‬ ‫)‪for(i = 0; i < 10; i++‬‬ ‫)‪for(j = 0; j < 10; j++‬‬ ‫‪a[i * 10 + j] = (i+1) * (j+1);// where the action is‬‬ ‫}‬

‫)‪i++‬‬ ‫)‪< 10; j++‬‬ ‫;)‪( i + 1),j + 1‬‬ ‫‪* 10 + j];// where the action is‬‬

‫‪154‬‬

‫‪www.pupuol.com‬‬

‫)(‪int main‬‬ ‫{‬ ‫;]‪int a[100‬‬ ‫;)‪Matrix(a‬‬ ‫;‪for(int i = 0; i < 10‬‬ ‫{‬ ‫‪for(int j = 0; j‬‬ ‫{‬ ‫* ‪gotoxy(3‬‬ ‫‪cout<< a[i‬‬ ‫}‬ ‫}‬ ‫;)(‪getch‬‬ ‫}‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ Output (BDS 2006): 1 2 3 4 2 4 6 8 3 6 9 12 4 8 12 16 5 10 15 20 6 12 18 24 7 14 21 28 8 16 24 32 9 18 27 36 10 20 30 40

5 10 15 20 25 30 35 40 45 50

6 12 18 24 30 36 42 48 54 60

7 14 21 28 35 42 49 56 63 70

8 16 24 32 40 48 56 64 72 80

9 18 27 36 45 54 63 72 81 90

10 20 30 40 50 60 70 80 90 100

void* ‫ا ر ! ع‬

‫ ﺑﻨﺎﺑﺮاﻳﻦ ﺑﺮاي ﻣﺸﺨﺺ ﺷﺪن ﺟﺎﻳﻲ از ﺣﺎﻓﻈﻪ ﻛﻪ ﺑﻪ‬.‫ ﭼﻬﺎر ﺑﺎﻳﺖ اﺳﺖ‬pointer ‫ﻫﺎي اﻣﺮوزي ﻫﺮ‬compiler ‫در‬ ‫ در واﻗﻊ ﻧﻮع‬.‫ي از ﻫﺮ ﻧﻮع اﺳﺖ‬void* pointer .‫ ﻧﻴﺴﺖ‬pointer ‫آن اﺷﺎره ﻣﻲﺷﻮد ﻧﻴﺎزي ﺑﻪ داﻧﺴﺘﻦ ﻧﻮع‬ :‫ ﺑﻴﺶ ﺗﺮ زﻣﺎﻧﻲ ﺑﻪ ﻛﺎر ﻣﻲرود ﻛﻪ ﻧﻮع ﭘﺎراﻣﺘﺮﻫﺎي ﻳﻚ ﺗﺎﺑﻊ ﻣﺸﺨﺺ ﻧﻴﺴﺖ‬C ‫ در‬.‫ﻣﺸﺨﺼﻲ ﻧﺪارد‬ #include <conio.h> #include <iostream> using namespace std; const int INT = 100; const int CHAR = 101; bool isLess(void* a, void* b, int type) { if(type == INT) { int* aa = (int*)a; int* bb = (int*)b; if(*aa < *bb) return true; } else if(type == CHAR) { char* aa = (char*)a; char* bb = (char*)b; if(*aa < *bb) return true; } return false; } int main() { char ch1 = 'a'; char ch2 = 'b'; cout<< isLess(&ch1,&ch2,CHAR) << endl;

155

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪int a = 2‬‬ ‫;‪int b = 3‬‬ ‫;‪cout<< isLess(&a,&b,INT) << endl‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬ ‫‪1‬‬

‫ﺗﺎﺑﻊ )(‪ isLess‬ﻣﻲﺑﻴﻨﺪ ﻛﻪ آﻳﺎ ‪ *a‬از ‪ *b‬ﻛﻢ ﺗﺮ اﺳﺖ ﻳﺎ ﻧﻪ‪ *a .‬و ‪ *b‬ﻣﻤﻜﻦ اﺳﺖ ‪ int‬ﻳﺎ ‪ char‬ﺑﺎﺷﻨﺪ‪.‬‬ ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺗﺎﺑﻊ )(‪ isLess‬ﺑﻴﺶ از ﺣﺪ ﻃﻮﻻﻧﻲ اﺳﺖ‪ .‬در ‪ C++‬اﻣﻜﺎن اﺳﺘﻔﺎده از ‪ template‬ﻧﻴﺎز ﺑﻪ‬ ‫*‪ void‬را در اﻳﻦ ﻣﻮارد ﺗﻘﺮﻳﺒﺎ از ﺑﻴﻦ ﻣﻲﺑﺮد‪.‬‬ ‫در ‪ C++‬دو ﺧﻂ‬ ‫;‪int a‬‬ ‫;‪char* c = &a‬‬

‫ﺧﻄﺎ دارد اﻣﺎ‬ ‫;‪int a‬‬ ‫;‪void* c = &a‬‬

‫ﺧﻄﺎ ﻧﺪارد‪.‬‬

‫@? ' ‬

‫ﺣﺎل ﺷﻤﺎ دﺳﺖ ﻛﻢ آن ﭼﻪ را در زﺑﺎن ‪ C‬ﻫﺴﺖ ﻣﻲداﻧﻴﺪ و ﺑﻪ اﻧﺪازهي ﻳﻚ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ‪ C‬ﻗﺪرت دارﻳﺪ و ﻣﻲ‪-‬‬ ‫ﺗﻮاﻧﻴﺪ ﺑﺮﻧﺎﻣﻪﻫﺎي ﺧﻮﺑﻲ ﺑﻨﻮﻳﺴﻴﺪ‪ .‬ﻓﻜﺮ ﻣﻲﻛﻨﻢ در اﻳﻦ ﺷﺮاﻳﻂ اﻧﺠﺎم ﭼﻨﺪ ﺗﻤﺮﻳﻦ ﻻزم ﺑﺎﺷﺪ‪.‬‬ ‫‪ (1‬ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻋﺪد ﺻﺤﻴﺢ ‪ n‬را از ﻛﺎرﺑﺮ ﺑﮕﻴﺮد و ﺑﻌﺪ ‪ n‬ﻋﺪد ﺻﺤﻴﺢ از ﻛﺎرﺑﺮ ﺑﮕﻴﺮد و آن ﻫﺎ را‬ ‫ﭼﺎپ ﻛﻨﺪ‪ .‬ﺑﺮﻧﺎﻣﻪ را ﻃﻮري ﺑﻨﻮﻳﺴﻴﺪ ﻓﻘﻂ ﺑﻪ اﻧﺪازه ﻻزم و ﻧﻪ ﺑﻴﺶ ﺗﺮ ﺣﺎﻓﻈﻪ ﺑﺨﻮاﻫﺪ‪.‬‬ ‫راﻫﻨﻤﺎﻳﻲ‪ :‬ﺣﺎﻓﻈﻪ را از ‪ heap‬ﺑﮕﻴﺮﻳﺪ‪.‬‬ ‫‪ (2‬ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ در ﺗﺎﺑﻊ )(‪ main‬از ﺳﻪ ﺑﻠﻮك ﺗﻮ در ﺗﻮ اﺳﺘﻔﺎده ﺑﺸﻮد و در ﻫﺮ ﺑﻠﻮك ﻣﺘﻐﻴﺮي ﺑﺎ‬ ‫ﻧﺎم ‪ a‬ﺑﺎ ﻣﻘﺪار ﻣﺘﻔﺎوت ﻣﻮﺟﻮد ﺑﺎﺷﺪ‪ .‬ﺑﻌﺪ ﺑﺮﻧﺎﻣﻪ را ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﺪ ﺑﻪ ﻃﻮري ﻛﻪ ﻫﺮ ﺑﻠﻮك ﺑﺎ ﻳﻚ ﺗﺎﺑﻊ‬ ‫ﺟﺎﻳﮕﺰﻳﻦ ﺑﺸﻮد‪.‬‬ ‫‪ (3‬ﻓﺮض ﻛﻨﻴﺪ در ‪ C++‬ﻋﻤﻠﮕﺮﻫﺎي ﻣﻨﻄﻘﻲ &&‪ || ،‬و ! وﺟﻮد ﻧﺪارﻧﺪ‪ .‬ﺗﺎﺑﻊﻫﺎي‬ ‫;)‪bool and(bool a,bool b‬‬

‫‪156‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;)‪bool or(bool a,bool b‬‬ ‫;)‪bool not(bool a‬‬

‫را ﻃﻮري ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻛﺎر ﻋﻤﻠﮕﺮﻫﺎي ﻣﻨﻄﻘﻲ را اﻧﺠﺎم دﻫﻨﺪ‪.‬‬ ‫راﻫﻨﻤﺎﻳﻲ‪ :‬از ‪ if‬اﺳﺘﻔﺎده ﻛﻨﻴﺪ‪.‬‬ ‫‪ (4‬ﺗﺎﺑﻌﻲ ﺑﺎ ‪ prototype‬زﻳﺮ ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻳﻚ رﺷﺘﻪ از ﻛﺎرﺑﺮ ﻣﻲﮔﻴﺮد ﻳﻚ ﻛﭙﻲ از آن رﺷﺘﻪ در ‪heap‬‬ ‫درﺳﺖ ﻣﻲﻛﻨﺪ و اﺷﺎره ﮔﺮي ﺑﻪ رﺷﺘﻪي ﺟﺪﻳﺪ ﺑﺮ ﻣﻲﮔﺮداﻧﺪ‪:‬‬ ‫;)‪char* newStr(char* old_string‬‬

‫اﻳﻦ ﺗﺎﺑﻊ زﻳﺎد ﺑﻪ درد ﻣﻲﺧﻮرد‪ .‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﺧﺮوﺟﻲ ﺑﺎﻳﺪ ﺑﻌﺪ از اﺗﻤﺎم ﻛﺎر ][ ‪ delete‬ﺷﻮد‪ .‬ﺳﻌﻲ‬ ‫ﻛﻨﻴﺪ ﻳﻚ ‪ header file‬ﺑﺮاي ﺧﻮدﺗﺎن درﺳﺖ ﻛﻨﻴﺪ و اﻳﻦ ﮔﻮﻧﻪ ﺗﺎﺑﻊﻫﺎ در آن ﻗﺮار ﺑﺪﻫﻴﺪ‪.‬‬ ‫‪ (5‬ﺗﺎﺑﻌﻲ ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻳﻚ آراﻳﻪ از ‪int‬ﻫﺎ )ﺑﻪ ﻫﻤﺮاه ﻃﻮل آراﻳﻪ( را ﻣﻲﮔﻴﺮد و ﺑﺪون اﻳﻦ ﻛﻪ آراﻳﻪي‬ ‫ﺟﺪﻳﺪي ﺗﻌﺮﻳﻒ ﻛﻨﺪ ﺗﺮﺗﻴﺐ ‪int‬ﻫﺎ را ﺑﺮﻋﻜﺲ ﻣﻲﻛﻨﺪ‪ .‬ﻣﺜﻼ اﮔﺮ اول ‪ 1,2,3,4,5,6‬ﺑﻮد ﺑﻌﺪ از از‬ ‫اﺟﺮاي ﺗﺎﺑﻊ ﻣﻲﺷﻮد ‪.6,5,4,3,2,1‬‬ ‫راﻫﻨﻤﺎﻳﻲ‪ :‬ﭼﻨﺪ ﻣﺪاد رﻧﮕﻲ را ﻛﻨﺎر ﻫﻢ ﺑﮕﺬارﻳﺪ و دوﺗﺎ دوﺗﺎ ﺟﺎي آنﻫﺎ را ﻋﻮض ﻛﻨﻴﺪ ﺗﺎ ﺗﺮﺗﻴﺐ آنﻫﺎ‬ ‫ﻣﻌﻜﻮس ﺷﻮد‪ .‬ﺑﻌﺪ ﺑﺮﻧﺎﻣﻪ را ﻃﻮري ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻫﻤﺎن ﻛﺎر ﺷﻤﺎ را اﻧﺠﺎم ﺑﺪﻫﺪ‪.‬‬ ‫‪ (6‬ﻳﻚ ‪ struct‬ﺑﺎ ﻧﺎم ‪ student‬درﺳﺖ ﻛﻨﻴﺪ ﻛﻪ ﻧﺎم‪ ،‬ﺷﻤﺎرهي ردﻳﻒ و ﻧﻤﺮهي ﻳﻚ داﻧﺶ آﻣﻮز را ﻧﮕﻪ‬ ‫ﻣﻲدارد‪ .‬آراﻳﻪاي از اﻳﻦ ‪ struct‬درﺳﺖ ﻛﻨﻴﺪ و از ﻛﺎرﺑﺮ ﺑﺨﻮاﻫﻴﺪ ﺑﻪ ﻫﻤﻪي ﻋﻨﺎﺻﺮ آراﻳﻪ )ﻛﻪ ﻫﺮ ﻛﺪام‬ ‫ﻳﻚ ‪ student‬اﺳﺖ( ﻣﻘﺪار ﺑﺪﻫﺪ‪ .‬ﺑﻌﺪ ﺑﺮﻧﺎﻣﻪ ﺑﺎﻳﺪ ﺷﺎﮔﺮد اول )ﻳﻌﻨﻲ ﻛﺴﻲ ﻛﻪ ﺑﻴﺶ ﺗﺮﻳﻦ ﻧﻤﺮه را‬ ‫ﮔﺮﻓﺘﻪ( ﻣﻌﺮﻓﻲ ﻛﻨﺪ‪.‬‬ ‫‪ (7‬اﻳﻦ ﺗﺎﺑﻊﻫﺎ را در ﻧﻈﺮ ﺑﮕﻴﺮﻳﺪ‪:‬‬ ‫;‪const int n = 5‬‬ ‫)‪int f(const void* a,const void* b‬‬ ‫{‬ ‫;)‪int aa = *((int*)a‬‬ ‫;)‪int bb = *((int*)b‬‬ ‫)‪if(bb > aa‬‬ ‫;‪return -1‬‬ ‫;)‪return (aa > bb‬‬ ‫}‬ ‫)]‪void sort(int a[n‬‬ ‫{‬ ‫;)‪qsort(a,n,sizeof(int),f‬‬ ‫}‬

‫اﻳﻦ ﻛﻪ اﻳﻦﻫﺎ دﻗﻴﻘﺎ ﭼﻪ ﻛﺎر ﻣﻲﻛﻨﻨﺪ زﻳﺎد ﻣﻬﻢ ﻧﻴﺴﺖ ﺗﻨﻬﺎ ﭼﻴﺰ ﻣﻬﻢ اﻳﻦ اﺳﺖ ﻛﻪ ﺗﺎﺑﻊ )(‪ sort‬ﻳﻚ‬ ‫آراﻳﻪي ‪ 5‬ﻋﻨﺼﺮي از ‪ int‬ﻫﺎ را از ﻛﻮﭼﻚ ﺑﻪ ﺑﺰرگ ﻣﺮﺗﺐ ﻣﻲﻛﻨﺪ‪.‬‬

‫‪157‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ اﺳﻢ و اﻣﺘﻴﺎز ‪ 5‬ورزﺷﻜﺎر را از ﻛﺎرﺑﺮ ﺑﮕﻴﺮد‪ ،‬اﻣﺘﻴﺎزﻫﺎ را از ﻛﻮﭼﻚ ﺑﻪ ﺑﺰرگ ﻣﺮﺗﺐ‬ ‫ﻛﻨﺪ و اﺳﻢ ورزﺷﻜﺎران را ﺑﻪ ﺗﺮﺗﻴﺐ اﻣﺘﻴﺎز آنﻫﺎ )از ورزﺷﻜﺎر ﺑﺎ ﻛﻢ ﺗﺮﻳﻦ اﻣﺘﻴﺎز ﺑﻪ ورزﺷﻜﺎر داراي ﺑﻴﺶ‬ ‫ﺗﺮﻳﻦ اﻣﺘﻴﺎز( ﺑﻨﻮﻳﺴﺪ‪ .‬از ‪ struct‬اﺳﺘﻔﺎده ﻧﻜﻨﻴﺪ‪.‬‬ ‫‪ (8‬ﺑﺎ اﺳﺘﻔﺎده از ﺗﺎﺑﻊ )(‪ sort‬در ﺗﻤﺮﻳﻦ ﻗﺒﻞ ﺗﺎﺑﻌﻲ ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻳﻚ آراﻳﻪي ‪ 5‬ﺗﺎﻳﻲ را ﺑﮕﻴﺮد و از ﺑﺰرگ‬ ‫ﺑﻪ ﻛﻮﭼﻚ ﻣﺮﺗﺐ ﻛﻨﺪ )ﻧﻪ از ﻛﻮﭼﻚ ﺑﻪ ﺑﺰرگ(‪ .‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﻧﺒﺎﻳﺪ ﺑﻪ ﺗﻌﺮﻳﻒ ﺗﺎﺑﻊﻫﺎي )(‪ f‬و‬ ‫)(‪ sort‬در ﺗﻤﺮﻳﻦ ﻗﺒﻞ دﺳﺖ ﺑﺰﻧﻴﺪ‪.‬‬

‫' ه ‪ A#‬‬

‫اﻧﺠﺎم ﺗﻤﺮﻳﻦﻫﺎي ﺳﺨﺖ‪ ،‬اﻓﺮاد ﺑﺎ اﺳﺘﻌﺪاد را واﻗﻌﺎ ﺑﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﻋﻼﻗﻪ ﻣﻨﺪ ﻣﻲﻛﻨﺪ‪ .‬ﺑﺮاي ﻫﻤﻴﻦ ﻻزم اﺳﺖ ﭼﻨﺪ‬ ‫ﺗﻤﺮﻳﻦ ﺳﺨﺖ را ﻫﻢ ﺣﻞ ﻛﻨﻴﺪ‪ .‬در واﻗﻊ ﻣﻲﺧﻮاﻫﻢ اﻧﺠﺎم ﻫﺮ ﻳﻚ از آنﻫﺎ دﺳﺖ ﻛﻢ ﻳﻚ ﺳﺎﻋﺖ از وﻗﺖ ارزﺷﻤﻨﺪ‬

‫ﺷﻤﺎ را ﺑﮕﻴﺮد‬

‫‪ .‬اﻟﺒﺘﻪ اﻳﻦ در ﺑﺮاﺑﺮ زﻣﺎﻧﻲ ﻛﻪ ﭘﺮوژهﻫﺎي ﺳﻨﮕﻴﻦ ﺗﺮ از ﻳﻚ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻣﻲﮔﻴﺮد‬

‫ﻫﻴﭻ اﺳﺖ‪ .‬ﺗﻮﺻﻴﻪ ﻣﻲﻛﻨﻢ )‬

‫( ﺗﺎ ﻧﻴﻤﻲ از آنﻫﺎ را اﻧﺠﺎم ﻧﺪادهاﻳﺪ ﻓﺼﻞﻫﺎي ﺑﻌﺪي را ﺷﺮوع ﻧﻜﻨﻴﺪ‪ .‬ﻣﻦ در اﻳﻦ‬

‫ﻧﻮﺷﺘﻪ ﻓﻘﻂ زﺑﺎن ‪ C++‬را ﻳﺎد ﻣﻲدﻫﻢ ﻧﻪ ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﺻﻮرت ﺣﺮﻓﻪاي‪ .‬ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ ﻳﻚ ﻗﺪرت ذاﺗﻲ اﺳﺖ ﻛﻪ‬ ‫ﻧﻤﻲﺷﻮد آن را ﻳﺎد داد‪ .‬اﻟﺒﺘﻪ روش ﺣﻞ ﺑﻌﻀﻲ از ﻣﺴﺎﺋﻞ ﻣﻮﺟﻮد اﺳﺖ اﻣﺎ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﺑﺎﻳﺪ ﺑﺘﻮاﻧﺪ ﻣﺴﺄﻟﻪﻫﺎي ﺟﺪﻳﺪ را‬ ‫ﺧﻮدش ﺣﻞ ﻛﻨﺪ‪ .‬اﻣﻴﺪوارم در ﺣﻞ ﺗﻤﺮﻳﻦﻫﺎي زﻳﺮ ﻣﻮﻓﻖ ﺑﺎﺷﻴﺪ‬

‫‪.‬‬

‫‪ (1‬اﻟﻒ( ﻣﻲداﻧﻴﺪ ﻛﻪ ﻳﻚ ﻋﺪد اول‪ ،‬ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ و ﺑﺰرگ ﺗﺮ از ‪ 1‬اﺳﺖ ﻛﻪ ﺣﺎﺻﻞ ﺿﺮب دو ﻋﺪد‬ ‫ﺻﺤﻴﺢ و ﺑﺰرگ ﺗﺮ از ‪ 1‬دﻳﮕﺮ ﻧﻴﺴﺖ‪ .‬ﻣﺜﻼ اول ﻧﻴﺴﺖ ﭼﻮن و و ﺻﺤﻴﺢ ﺑﺰرگ‬ ‫ﺗﺮ از ﻫﺴﺘﻨﺪ‪ .‬وﻟﻲ اول اﺳﺖ ﭼﻮن ﻓﻘﻂ ﻣﻲﺷﻮد ﻧﻮﺷﺖ ﻳﺎ ‪ .‬ﺗﺎﺑﻌﻲ ﺑﺎ‬ ‫‪ ِ prototype‬زﻳﺮ ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻋﺪدﻫﺎي اول را ﻣﺸﺨﺺ ﻛﻨﺪ‪:‬‬ ‫;)‪bool isprime(unsigned a‬‬

‫‪158‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ب( ﻫﺮ ﻋﺪد ﺻﺤﻴﺢ ﻣﺜﺒﺖ را ﻣﻲﺷﻮد ﺑﻪ ﺻﻮرت ﺣﺎﺻﻞ ﺿﺮﺑﻲ از ﻋﺪدﻫﺎي اول ﻧﻮﺷﺖ ﻣﺜﻼ‬ ‫

‪ .‬ﺗﺎﺑﻌﻲ ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ ﺑﮕﻴﺮد و ﺗﺠﺰﻳﻪ آن را ﺑﻪ ﻋﻮاﻣﻞ اول‬ ‫ﺑﻨﻮﻳﺴﺪ ﻣﺜﻼ ﺑﺎ دادن ﺧﺮوﺟﻲ زﻳﺮ را ﭼﺎپ ﻛﻨﺪ‪:‬‬ ‫‪2^2‬‬ ‫‪3^3‬‬ ‫‪7^1‬‬

‫‪ (2‬ﺑﺎ ﻛﻤﻚ )(‪ gotoxy‬ﺗﺎﺑﻌﻲ ﺑﺎ اﻳﻦ ‪:prototype‬‬ ‫;)‪void Table(int x,int y‬‬

‫ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻣﺜﻼ ﺧﺮوﺟﻲ )‪ Table(4,3‬ﺑﻪ اﻳﻦ ﺻﻮرت ﺑﺎﺷﺪ‪:‬‬

‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﻣﺤﻴﻂ ﮔﺮاﻓﻴﮕﻲ ﻧﻴﺴﺖ )اﮔﺮ ‪ compiler‬ﺷﻤﺎ )(‪ gotoxy‬ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ ﺑﺎﻳﺪ ﺷﻤﺎ را از اﻧﺠﺎم اﻳﻦ‬ ‫ﺗﻤﺮﻳﻦ ﻣﻌﺎف ﻛﻨﻢ ﮔﺮﭼﻪ اﻧﺠﺎم آن ﺧﻴﻠﻲ آﻣﻮزﻧﺪه اﺳﺖ(‪.‬‬

‫‪ (3‬ﺗﺎﺑﻌﻲ ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ آراﻳﻪي از اﻋﺪاد ﺻﺤﻴﺢ را ﺑﮕﻴﺮد و ﻣﺮﺗﺐ ﻛﻨﺪ‪ .‬ﻣﺜﻼ اﮔﺮ )(‪ f‬آن ﺗﺎﺑﻊ ﺑﺎﺷﺪ ﺑﺎ اﺟﺮاي‬ ‫;}‪int a[5] = {1,7,4,-1 ,5‬‬ ‫;)‪f(a‬‬

‫]‪ a[0‬ﺗﺎ ]‪ a[4‬ﻋﺒﺎرت ﺑﺎﺷﻨﺪ از ‪ 5 ،4 ،1 ،-1‬و ‪ 7‬ﻛﻪ از ﻛﻮﭼﻚ ﺑﻪ ﺑﺰرگ ﻣﺮﺗﺐ ﺷﺪهاﻧﺪ‪ .‬ﺧﻮدﺗﺎن‬ ‫ﻓﻜﺮ ﻛﻨﻴﺪ و راﻫﻲ ﺑﺮاي ﻣﺮﺗﺐ ﻛﺮدن ﭘﻴﺪا ﻛﻨﻴﺪ و دﻧﺒﺎل راهﻫﺎﻳﻲ ﻛﻪ ﻗﺒﻼ ﭘﻴﺪا ﺷﺪه ﻧﮕﺮدﻳﺪ‪.‬‬

‫‪159‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ (4‬ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﺣﺎﺻﻞ !‪ 50‬را ﭼﺎپ ﻛﻨﺪ‪ 50! .‬ﺣﺎﺻﻞ ﺿﺮب اﻋﺪاد ‪ 1‬ﺗﺎ ‪ 50‬اﺳﺖ‪) .‬ﺣﻞ اﻳﻦ‬ ‫ﺗﻤﺮﻳﻦ ﺧﺴﺘﻪ ﻛﻨﻨﺪه اﺳﺖ‪ .‬ﺑﻪ ﻫﺮ ﺣﺎل ﺗﻼش ﺧﻮدﺗﺎن را ﺑﻜﻨﻴﺪ‪ .‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﻓﻘﻂ ﺑﺎﻳﺪ ﺟﻮاب ﭼﺎپ ﺷﻮد‬ ‫و ﮔﺮﻧﻪ ﻫﻴﭻ ﻧﻮﻋﻲ )ﺣﺘﻲ ‪ (__int128‬ﻇﺮﻓﻴﺖ ﻛﺎﻓﻲ ﺑﺮاي اﻳﻦ ﻛﻪ اﻳﻦ ﻋﺪد را در ﺧﻮد ﺟﺎ ﺑﺪﻫﺪ ﻧﺪارد‪.‬‬ ‫ﺟﻮاب‪:‬‬ ‫‪30414093201713378043612608166064768844377641568960512000000000000‬‬

‫‪ (5‬ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻋﺪد ‪ n‬را از ﻛﺎرﺑﺮ ﺑﮕﻴﺮد‪ ،‬ﺑﻌﺪ اول ‪ n‬ﺗﺎ ﻋﺪد از ﻛﺎرﺑﺮ ﺑﮕﻴﺮد و ﺑﻌﺪ آنﻫﺎ را ﭼﺎپ‬ ‫ﻛﻨﺪ‪ .‬ﺗﺮﺗﻴﺐ ﭼﺎپ ﻣﻬﻢ ﻧﻴﺴﺖ‪ .‬از ﺣﺎﻓﻈﻪي ‪ heap‬اﺳﺘﻔﺎده ﻧﻜﻨﻴﺪ‪ .‬از آراﻳﻪ اﺳﺘﻔﺎده ﻧﻜﻨﻴﺪ‪.‬‬ ‫راﻫﻨﻤﺎﻳﻲ‪ :‬از ﻳﻚ ﺗﺎﺑﻊ ﺑﺎزﮔﺸﺘﻲ اﺳﺘﻔﺎده ﻛﻨﻴﺪ‪.‬‬

‫‪160‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ‪ # 6L‬م‬ ‫در دو ﻓﺼﻞ ﻗﺒﻞ ﺗﻘﺮﻳﺒﺎ ﺑﺎ ﻧﺼﻒ اﻣﻜﺎﻧﺎت ‪ C++‬آﺷﻨﺎ ﺷﺪﻳﺪ‪ .‬در اﻳﻦ ﻓﺼﻞ ﺑﺎ ﻧﺼﻒ دﻳﮕﺮ ‪ C++‬ﻳﻌﻨﻲ ﺑﺎ ﻗﻮي‬ ‫ﺗﺮﻳﻦ اﺑﺰار ‪ C++‬ﻛﻪ ﺑﺮگ ﺑﺮﻧﺪهي ‪ C++‬در ﺑﺮاﺑﺮ ‪ C‬اﺳﺖ آﺷﻨﺎ ﻣﻲﺷﻮﻳﺪ‪ .‬اﻳﻦ اﺑﺰار ﻛﻼس )‪ (class‬اﺳﺖ‪.‬‬ ‫ﺗﻘﺮﻳﺒﺎ ﻫﻤﻪي ﺑﺮﻧﺎﻣﻪﻫﺎي ‪ C++‬در ﻗﺎﻟﺐ ﻛﻼسﻫﺎ ﻧﻮﺷﺘﻪ ﻣﻲﺷﻮﻧﺪ‪ .‬ﻛﻼسﻫﺎ ﻛﻤﻚ ﻣﻲﻛﻨﻨﺪ ﻛﻪ ارﺗﺒﺎﻃﻲ ﺑﻴﻦ دﻧﻴﺎي‬ ‫واﻗﻌﻲ و دﻧﻴﺎي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﺑﺮﻗﺮار ﺷﻮد‪ class .‬در واﻗﻊ ﻫﻤﺎن ‪ struct‬اﺳﺖ ﻛﻪ در ﻓﺼﻞ اول ﺑﺎ آن آﺷﻨﺎ‬ ‫ﺷﺪﻳﺪ )ﺑﻪ ﺟﺰ ﻳﻚ ﺗﻔﺎوت ﺧﻴﻠﻲ ﺟﺮﺋﻲ(‪ .‬ﺑﻪ ﻫـﺮ ﻛﻼس ﻣﻲﺷﻮد ﺑﻪ ﭼﺸﻢ ﻳﻚ ﻣﻮﺟﻮد واﻗﻌﻲ ﻧﮕﺎه ﻛﺮد ﻛﻪ وﻳﮋﮔﻲ‪-‬‬ ‫ﻫﺎﻳﻲ دارد و ﻛﺎرﻫﺎﻳﻲ را ﻣﻲﺗﻮاﻧﺪ اﻧﺠﺎم ﺑﺪﻫﺪ‪ .‬ﻣﺜﻼ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻳﻚ ﺑﺮﻧﺎﻣﻪ ﺑﻨﻮﻳﺴﻴﻢ ﻛﻪ ﺷﻄﺮﻧﺞ ﺑﺎزي ﻣﻲﻛﻨﺪ ﻣﻲ‪-‬‬ ‫ﺗﻮاﻧﻴﻢ ﻳﻚ ﻛﻼس ﺑﺎ ﻧﺎم ‪ board‬داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﻛﻪ ﻧﻘﺶ ﺻﻔﺤﻪي ﺷﻄﺮﻧﺞ را دارد‪ .‬ﻳﻚ ﻛﻼس ﺑﺎ ﻧﺎم ‪ pawn‬داﺷﺘﻪ‬ ‫ﺑﺎﺷﻴﻢ ﻛﻪ ﻧﻘﺶ ﭘﻴﺎدهي ﺷﻄﺮﻧﺞ را ﺑﺎزي ﻣﻲﻛﻨﺪ و‪ . ...‬ﻛﻼس ‪ pawn‬ﻣﻲﺗﻮاﻧﺪ ﺗﺎﺑﻌﻲ ﺑﻪ ﻧﺎم ‪ move‬داﺷﺘﻪ ﺑﺎﺷﺪ ﻛﻪ‬ ‫ﺣﺮﻛﺖ ﭘﻴﺎده را ﺑﻪ ﻋﻬﺪه دارد و ﻛﻼس ‪ board‬ﻣﻲﺗﻮاﻧﺪ ﻳﻚ آراﻳﻪي دوﮔﺎﻧﻪي ‪ 8‬در ‪ 8‬داﺷﺘﻪ ﺑﺎﺷﺪ‪.‬‬

‫ ‪O‬سه ‬

‫‪S Q1‬س ‪!/ Q1‬ع * ‪ 1‬ا‪ .C4‬ر ‪T‬ن ‪ struct LF‬اﺳﺖ ﻛﻪ ﻗﺒﻼ ﻣﻌﺮﻓﻲ ﻛﺮدم‪ .‬ﺑﺮاي اﻳﺠﺎد ﻳﻚ ﻛﻼس از‬ ‫اﻳﻦ ﻓﺮﻣﻮل اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ‪:‬‬ ‫]ا‪class [g6‬‬ ‫{‬ ‫‪public:‬‬ ‫;د‪456‬ر _^]\[)‪od (1‬ون ‪opm‬ار او ‪ k‬‬ ‫;د‪456‬ر _^]\[)‪od (2‬ون ‪opm‬ار او ‪ k‬‬ ‫‪.‬‬ ‫‪.‬‬ ‫_^]\[ _‪(1) dZ‬‬ ‫_^]\[ _‪(2) dZ‬‬ ‫‪.‬‬ ‫‪.‬‬ ‫‪.‬‬ ‫;}‬

‫‪161‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫د‪456‬رﻫﺎي _^]\[ ﻧﺒﺎﻳﺪ ‪ initialize‬ﺷﻮﻧﺪ‪ .‬اﮔﺮ ﻃﺮز اﺳﺘﻔﺎده از ‪struct‬ﻫﺎ را ﻓﺮاﻣﻮش ﻛﺮدهاﻳﺪ ﺑﻬﺘﺮ اﺳﺖ‬ ‫دوﺑﺎره ﻧﮕﺎﻫﻲ ﺑﻪ آنﻫﺎ ﺑﻴﻨﺪازﻳﺪ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Car‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪double speed‬‬ ‫)‪void SetSpeed(double x‬‬ ‫{‬ ‫;‪speed = x‬‬ ‫}‬ ‫)(‪int GetSpeed‬‬ ‫{‬ ‫;‪return speed‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;}‪Car myCar = {0‬‬ ‫;)‪myCar.SetSpeed(10‬‬ ‫;)(‪cout<< myCar.GetSpeed‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪10‬‬

‫اول‪ ،‬ﻣﺘﻐﻴﺮي ﺑﺎ ﻧﺎم ‪ myCar‬از ﻧﻮع ‪ Car‬ﺗﻌﺮﻳﻒ ﻣﻲﺷﻮد‪ myCar .‬ﺷﺎﻣﻞ ﻣﺘﻐﻴﺮي ﺑﺎ ﻧﻮع ‪ double‬ﺑﻪ ﻧﺎم‬ ‫‪ speed‬اﺳﺖ‪ .‬ﺗﺎﺑﻊﻫﺎ ﺣﺎﻓﻈﻪاي از ‪ myCar‬اﺷﻐﺎل ﻧﻤﻲﻛﻨﻨﺪ )ﺑﺎ ‪ sizeof‬اﻣﺘﺤﺎن ﻛﻨﻴﺪ!(‪ .‬ﻣﻲﺗﻮاﻧﺴﺘﻢ ﺑﺎ ﻧﻮﺷﺘﻦ‬ ‫‪ myCar.speed = 10‬ﻣﻘﺪار ‪ speed‬در ‪ myCar‬را ﺗﻐﻴﻴﺮ ﺑﺪﻫﻢ اﻣﺎ اﻳﻦ ﻛﺎر را ﺑﺎ )(‪ SetSpeed‬اﻧﺠﺎم‬ ‫دادهام‪ .‬در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻣﻲﺗﻮاﻧﻴﺪ ﺑﻪ ﺟﺎي ‪ class‬ﺑﻨﻮﻳﺴﻴﺪ ‪ struct‬و ﻫﻴﭻ ﭼﻴﺰ ﺗﻐﻴﻴﺮ ﻧﻤﻲﻛﻨﺪ‪.‬‬ ‫ﻣﻲﺑﻴﻨﻴﻢ ﺗﺎ زﻣﺎﻧﻲ ﻛﻪ ﺗﺎﺑﻊﻫﺎي )(‪ SetSpeed‬و)(‪ GetSpeed‬ﻫﺴﺖ ﻧﻴﺎزي ﺑﻪ دﺳﺘﺮﺳﻲ ﻣﺴﺘﻘﻴﻢ ﺑﻪ ‪speed‬‬

‫ﻧﻴﺴﺖ‪ .‬ﭘﺲ ﻣﻲﺗﻮاﻧﻴﻢ دﺳﺘﺮﺳﻲ ﺑﻪ ‪ speed‬را ﻣﺤﺪود ﻛﻨﻴﻢ‪ .‬ﺑﺮاي اﻳﻦ ﻛﺎر ﺑﻪ ﺟﺎي اﻳﻦ ﻛﻪ ‪ speed‬را در‬ ‫ﻣﺤﺪودهي ‪ public‬ﻣﻌﺮﻓﻲ ﻛﻨﻴﻢ ﺑﺎﻳﺪ آن را در ﻣﺤﺪودهي ‪ private‬ﻣﻌﺮﻓﻲ ﻛﻨﻴﻢ ﻣﺜﻞ ﻣﺜﺎل زﻳﺮ )اﻣﺎ دﻳﮕﺮ‬ ‫ﻧﻤﻲﺷﻮد )ﺑﺎ }‪ (={0‬ﺑﻪ ‪ myCar‬ﻣﻘﺪار اوﻟﻴﻪ داد(‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪162‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪class Car‬‬ ‫{‬ ‫‪private:‬‬ ‫;‪double speed‬‬ ‫‪public:‬‬ ‫)‪void SetSpeed(double x‬‬ ‫{‬ ‫;‪speed = x‬‬ ‫}‬ ‫)(‪int GetSpeed‬‬ ‫{‬ ‫;‪return speed‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪Car myCar‬‬ ‫;)‪myCar.SetSpeed(10‬‬ ‫;)(‪cout<< myCar.GetSpeed‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪10‬‬

‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ در)(‪ main‬ﻧﻤﻲﺷﻮد ﻧﻮﺷﺖ ;‪ myCar.speed = 10‬ﭼﻮن دﺳﺘﺮﺳﻲ ﺑﻪ ‪ speed‬ﻣﺤﺪود ﺷﺪه‬ ‫و ﻓﻘﻂ ﺗﺎﺑﻊﻫﺎي ﻣﻮﺟﻮد در ﻛﻼس ﺣﻖ اﺳﺘﻔﺎده و ﺗﻐﻴﻴﺮ آن را دارﻧﺪ‪ .‬در اﻳﻦ ﻣﺜﺎل ﻣﻲﺷﻮد ‪ private:‬را ﺣﺬف‬ ‫ﻛﺮد زﻳﺮا در ‪ class‬اﮔﺮ ﻣﺸﺨﺺ ﻧﺸﻮد ﺑﻪ ﻃﻮر ‪ ،default‬ﻫﻤﻪ ﭼﻴﺰ ‪ private‬اﺳﺖ‪ .‬در ‪ struct‬ﻫﻤﻪ ﭼﻴﺰ ﺑﻪ‬ ‫ﻃﻮر ‪ public ،default‬اﺳﺖ‪ .‬اﻳﻦ ﺗﻨﻬﺎ ﻓﺮق ‪ struct‬و ‪ class‬اﺳﺖ‪.‬‬ ‫ﺑﻪ ﻣﺘﻐﻴﺮﻫﺎي درون ﻳﻚ ﻛﻼس ‪ member variable‬و ﺑﻪ ﺗﺎﺑﻊﻫﺎي درون آن ‪ member function‬ﻳﺎ‬ ‫‪ method‬ﻣﻲﮔﻮﻳﻨﺪ‪.‬‬ ‫‪method‬ﻫﺎ ﻫﻢ ﻣﻲﺗﻮاﻧﻨﺪ ‪ private‬ﺗﻌﺮﻳﻒ ﺷﻮﻧﺪ )ﺗﻠﻔﻆ‪» :‬ﭘﺮاي وت« ﻣﻌﻨﻲ‪» :‬ﺧﺼﻮﺻﻲ«‬

‫(‪ .‬ﺷﺎﻳﺪ ﺑﮕﻮﻳﻴﺪ ﭼﺮا‬

‫اﺻﻼ ﭼﻴﺰي را ‪ private‬ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‪ .‬دﻟﻴﻞ آن اﻳﻦ اﺳﺖ ﻛﻪ در ‪ ،C++‬ﻫﺪف از اﻳﺠﺎد ﻳﻚ ﻛﻼس‪ ،‬ﺳﺎﺧﺘﻦ ﻳﻚ‬ ‫ﺟﻮر ﻛﭙﺴﻮل اﺳﺖ ﻛﻪ ﻛﺎرﺑﺮ )ﻛﻪ اﻳﻦ ﺑﺎر ﻫﻤﺎن ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ اﺳﺖ( ﻗﺮار ﻧﻴﺴﺖ ﺑﻪ ﻫﻤﻪي ﻗﺴﺖﻫﺎي آن اﺣﺎﻃﻪ‬ ‫داﺷﺘﻪ ﺑﺎﺷﺪ‪ .‬ﺑﺎ ﻛﻼس ﻓﻘﻂ ﭼﻴﺰﻫﺎﻳﻲ را در اﺧﺘﻴﺎر ﻛﺎرﺑﺮ ﻗﺮار ﻣﻲدﻫﻴﻢ ﻛﻪ ﺑﻪ درد او ﻣﻲﺧﻮرد‪ .‬ﭼﺮا ﺑﺎﻳﺪ ذﻫﻦ او‬ ‫ﻣﺸﻐﻮل ﻳﺎد ﮔﺮﻓﺘﻦ ﻃﺮز اﺳﺘﻔﺎده از ‪method‬ﻫﺎﻳﻲ ﺑﺸﻮد ﻛﻪ اﺻﻼ ﺑﺎ آنﻫﺎ ﻛﺎر ﻧﺪارد؟ در ﺿﻤﻦ اﺳﺘﻔﺎده از اﻳﻦ‬ ‫ﺟﻮر ‪method‬ﻫﺎ ﻣﻤﻜﻦ اﺳﺖ در ﻛﺎر ﻛﻼس اﺧﺘﻼل اﻳﺠﺎد ﻛﻨﺪ و ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ اﻣﻦ ﻛﻪ از اﻫﺪاف ﻛﻼسﻫﺎﺳﺖ‬

‫‪163‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫از ﺑﻴﻦ ﺑﺮود‪ .‬ﻣﺜﻼ ﻓﺮض ﻛﻨﻴﺪ ﻛﻼﺳﻲ داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﻛﻪ ﺑﻪ ﻋﻨﻮان رﺷﺘﻪ از آن اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ‪ .‬اﻳﻦ ﻛﻼس ﺣﺘﻤﺎ‬ ‫ﻣﺘﻐﻴﺮﻫﺎ و ﺗﺎﺑﻊﻫﺎﻳﻲ ﺑﺮاي ﺗﺨﺼﻴﺺ ﺣﺎﻓﻈﻪ دارد‪ .‬اﻣﺎ ﻛﺎرﺑﺮ ﻧﺒﺎﻳﺪ ﺑﻪ آنﻫﺎ دﺳﺘﺮﺳﻲ داﺷﺘﻪ ﺑﺎﺷﺪ ﭼﻮن آنﻫﺎ ﺑﻪ ﻃﻮر‬ ‫ﺧﻮدﻛﺎر در ﻣﻮﻗﻊ ﻟﺰوم ﻓﺮاﺧﻮاﻧﺪه ﻣﻲﺷﻮﻧﺪ‪ .‬ﻳﻚ ﻛﻼس ﻣﺜﻞ ﻳﻚ ﺳﺎزﻣﺎن )ﻣﺜﻼ ﺑﻴﻤﺎرﺳﺘﺎن( اﺳﺖ ﻛﻪ ﻣﺮاﺟﻌﻴﻦ ﻓﻘﻂ‬ ‫ﺑﻪ ﺑﻌﻀﻲ ﺑﺨﺶﻫﺎي آن ﻣﺮاﺟﻌﻪ ﻣﻲﻛﻨﻨﺪ‪ .‬ﻫﻤﺮاه ﺑﻴﻤﺎر در اﺗﺎق ﻣﺮاﻗﺒﺖﻫﺎي وﻳﮋه ﺟﺎﻳﻲ ﻧﺪارد‪ .‬ﻫﻤﻴﻦ ﻣﺤﺪودﻳﺖ‪-‬‬ ‫ﻫﺎﺳﺖ ﻛﻪ ﺑﻪ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﻧﻈﻢ ﻣﻲدﻫﺪ و اﺷﺘﺒﺎﻫﺎت را در ﺑﺮﻧﺎﻣﻪي ﻧﻬﺎﻳﻲ ﻛﻢ ﻣﻲﻛﻨﺪ‪.‬‬

‫‪ constructor‬و ‪destructor‬‬

‫اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻣﻮﻗﻊ اﻳﺠﺎد ﻣﺘﻐﻴﺮ از ﻧﻮع ﻳﻚ ﻛﻼس ﻛﺎري اﻧﺠﺎم ﺑﺸﻮد‪ ،‬از ‪ constructor‬اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ‪.‬‬ ‫‪ constructor‬ﻳﻚ ‪ ِ method‬ﻫﻢ اﺳﻢ ﺑﺎ ﺧﻮد ﻛﻼس اﺳﺖ و ﺧﺮوﺟﻲ ﻧﺪارد‪ .‬در ﻣﺜﺎل زﻳﺮ ﻧﺤﻮهي ﻛﺎر‬ ‫‪ constructor‬را ﻣﻲﺑﻴﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Cat‬‬ ‫{‬ ‫‪public:‬‬ ‫‪Cat() // constructor‬‬ ‫{‬ ‫;)(‪Meow(); Meow‬‬ ‫;‪cout<< endl‬‬ ‫;)(‪Meow(); Meow‬‬ ‫;‪age = 0‬‬ ‫}‬ ‫‪private:‬‬ ‫)(‪void Meow‬‬ ‫{‬ ‫;"‪cout<< "Meow\n‬‬ ‫}‬ ‫‪public:‬‬ ‫;‪int age‬‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪Cat Tom‬‬ ‫;‪Tom.age = 3‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪164‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪Output:‬‬ ‫‪Meow‬‬ ‫‪Meow‬‬ ‫‪Meow‬‬ ‫‪Meow‬‬

‫ﺗﺎﺑﻊ ‪ Meow() private‬ﺗﻌﺮﻳﻒ ﺷﺪه‪ Cat() constructor .‬اﺳﺖ‪ .‬ﻣﻲﺑﻴﻨﻴﺪ ﻫﻴﭻ ﺧﺮوﺟﻲاي ﺑﺮاي آن‬ ‫ﻣﺸﺨﺺ ﻧﺸﺪه و ﺑﻪ ﻃﻮر ﻛﻠﻲ ﻧﺒﺎﻳﺪ ﺑﺮاي ‪ constructor‬ﺧﺮوﺟﻲ ﻣﺸﺨﺺ ﻛﺮد‪ Cat() .‬ﭼﻨﺪ ﺑﺎر ﺗﺎﺑﻊ‬ ‫)(‪ Meow‬را ﻣﻲﺧﻮاﻧﺪ و ﻣﺘﻐﻴﺮ ‪ age‬را ﺻﻔﺮ ﻗﺮار ﻣﻲدﻫﺪ‪ .‬ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺗﺮﺗﻴﺐ ﺗﻌﺮﻳﻒ ﻣﺘﻐﻴﺮﻫﺎ و ‪method‬ﻫﺎ در‬ ‫ﻳﻚ ﻛﻼس ﻣﻬﻢ ﻧﻴﺴﺖ‪ .‬درﺿﻤﻦ ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ در ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ دو ﺑﺎر از ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ public‬اﺳﺘﻔﺎده ﺷﺪه‪.‬‬ ‫در ﺗﺎﺑﻊ )(‪ main‬ﻣﺴﺘﻘﻴﻤﺎ ‪ constructor‬ﺧﻮاﻧﺪه ﻧﺸﺪه اﺳﺖ وﻟﻲ ﭼﻮن ﻣﺘﻐﻴﺮي ﺑﺎ ﻧﻮع ‪ Cat‬ﺗﻌﺮﻳﻒ ﺷﺪه‪،‬‬ ‫‪ constructor‬ﻓﺮا ﺧﻮاﻧﺪه ﻣﻲﺷﻮد‪.‬‬ ‫‪ constructor‬ﻧﻤﻲﺗﻮاﻧﺪ ﺧﺮوﺟﻲ داﺷﺘﻪ ﺑﺎﺷﺪ وﻟﻲ ﻣﻲﺗﻮاﻧﺪ ﭘﺎراﻣﺘﺮ داﺷﺘﻪ ﺑﺎﺷﺪ و ﻣﻲﺗﻮاﻧﺪ ‪ overload‬ﺷﻮد ﻳﻌﻨﻲ‬ ‫ﻣﻲﺷﻮد ﭼﻨﺪ ‪ constructor‬داﺷﺖ‪ .‬اﻳﻦ ﻣﺜﺎل را ﺑﺒﻴﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Cat‬‬ ‫{‬ ‫‪public:‬‬ ‫)(‪Cat‬‬ ‫{‬ ‫;"‪cout<< "not a mouse‬‬ ‫}‬ ‫)‪Cat(int a‬‬ ‫{‬ ‫;‪cout<< "a cat with age: " << a << endl‬‬ ‫}‬ ‫)‪Cat(int a, char* c‬‬ ‫{‬ ‫;‪cout<< c << endl‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)"‪Cat Tom(2,"I am Tom‬‬ ‫;)‪Cat Romeo(3‬‬ ‫;‪Cat Juliet‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪165‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪Output:‬‬ ‫‪I am Tom‬‬ ‫‪a cat with age: 3‬‬ ‫‪not a mouse‬‬

‫ﺑﻪ ﻧﺤﻮهي ﺗﻌﺮﻳﻒ ﻳﻚ ﻣﺘﻐﻴﺮ ﺑﺎ ﻧﻮع ‪ Cat‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪ .‬آرﮔﻮﻣﺎنﻫﺎ ﺑﻌﺪ از ﻣﺘﻐﻴﺮ ﻧﻮﺷﺘﻪ ﺷﺪهاﻧﺪ‪ compiler .‬ﺑﺎ ﺗﻮﺟﻪ‬ ‫ﺑﻪ ﻧﻮع و ﺗﻌﺪاد ﻣﺘﻐﻴﺮﻫﺎ ‪ constructor‬ﻣﻨﺎﺳﺐ را اﻧﺘﺨﺎب ﻣﻲﻛﻨﺪ‪.‬‬ ‫ﻧﻮعﻫﺎي ﻃﺒﻴﻌﻲ ﻣﺜﻞ ‪ int‬را ﻫﻢ ﻣﻲﺷﻮد ﻧﻮﻋﻲ ﻛﻼس ﺑﻪ ﺣﺴﺎب آورد ﻛﻪ ﺣﺪاﻗﻞ دو ‪ constructor‬دارد‪ .‬ﻳﻜﻲ‬ ‫ﺑﺪون ﭘﺎراﻣﺘﺮ و ﻳﻜﻲ ﺑﺎ ﻳﻚ ﭘﺎراﻣﺘﺮ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪int a(23‬‬ ‫;‪int b‬‬ ‫;‪cout<< a‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪23‬‬

‫ﭘﺲ ‪ 23‬ﺑﻪ ﻋﻨﻮان ﻣﻘﺪار اوﻟﻴﻪي ‪ a‬در ﻧﻈﺮ ﮔﺮﻓﺘﻪ ﺷﺪه‪ .‬اﻣﺎ ﺗﺎ ﺑﻪ ﺣﺎل ﻣﻘﺪار اوﻟﻴﻪ را ﺑﺎ = ﻣﻲدادﻳﻢ‪ .‬ﺑﺎﻳﺪ ﺑﮕﻮﻳﻢ ﻛﻪ‬ ‫‪constructor‬ﻫﺎي ﺗﻚ ﭘﺎراﻣﺘﺮي را ﻣﻲﺷﻮد ﺑﺎ = ﻫﻢ ﻓﺮاﺧﻮاﻧﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Cat‬‬ ‫{‬ ‫‪public:‬‬ ‫)(‪Cat‬‬ ‫{‬ ‫;"‪cout<< "not a mouse‬‬ ‫}‬ ‫)‪Cat(int a‬‬ ‫{‬ ‫;‪cout<< "a cat with age: " << a << endl‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪Cat Tom = 2‬‬

‫‪166‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ getch(); }

Output: a cat with age: 2 int ‫ ﺑﻪ ﻃﻮر ﻧﻤﺎدﻳﻦ ﻣﻲﺗﻮاﻧﻴﻢ ﺗﺼﻮر ﻛﻨﻴﻢ‬.‫ )ﻣﺜﻞ( دادن ﻣﻘﺪار اوﻟﻴﻪ اﺳﺖ‬constructor ‫ﭘﺲ دادن ﭘﺎراﻣﺘﺮ ﺑﻪ‬

:‫ﻳﻚ ﻛﻼس اﺳﺖ ﺑﻪ اﻳﻦ ﺷﻜﻞ‬ class int { int a; public: int(){} int(int x) { a = x; } };

.‫اﻟﺒﺘﻪ اﻳﻦ ﺗﺼﻮر ﻛﺎﻣﻞ ﻧﻴﺴﺖ و ﺑﺎ آﺷﻨﺎﻳﻲ ﺑﻴﺶ ﺗﺮ ﺑﺎ ﻛﻼس ﻣﻲﺗﻮاﻧﺪ ﻛﻢ ﻛﻢ ﻛﺎﻣﻞ ﺗﺮ ﺷﻮد‬ ‫ در ﻣﺜﺎل زﻳﺮ ﻳﻚ رﺷﺘﻪ ﺑﻪ ﻳﻚ‬.‫ ﺗﺒﺪﻳﻞ ﻧﻮع ﺑﻪ آن ﻛﻼس را اﻣﻜﺎن ﭘﺬﻳﺮ ﻣﻲﻛﻨﺪ‬،‫ ِ ﻳﻚ ﻛﻼس‬constructor :‫ ﻣﻲﺷﻮد‬cast ‫ﻛﻼس‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat() // constructor 1 { // does nothing } Cat(char* str) // constructor 2 { cout<< "The constructor called\n"; cout<< str << "\n\n"; } }; int main() { (Cat)"hello"; // explicit casting Cat Tom; Tom = "Tom"; // implicit casting getch(); }

Output:

167

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪The constructor called‬‬ ‫‪hello‬‬ ‫‪The constructor called‬‬ ‫‪Tom‬‬

‫در واﻗﻊ "‪ "Tom‬ﻛﻪ ﻧﻮﻋﺶ *‪ char‬اﺳﺖ ﺑﻪ \‪ Cat cast n‬ﺷﺪه‪ .‬در اﻳﻦ ﻣﺜﺎل ﺑﻪ ﺟﺎي‬ ‫;"‪(Cat)"hello‬‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;)"‪Cat("hello‬‬

‫و اﻳﻦ دو ﺗﺎ ﺑﺎ ﻫﻢ ﻓﺮﻗﻲ ﻧﺪارﻧﺪ‪ .‬ﺑﻪ ﺟﺎي '‪ (int)'a‬ﻫﻢ ﻣﻲﺷﻮد ﻧﻮﺷﺖ )'‪.int('a‬‬ ‫اﮔﺮ ﺑﺮاي ﻛﻼﺳﻲ ﻣﺜﻞ ﻛﻼس ‪Cat constructor‬ﻫﺎﻳﻲ ﺑﻨﻮﻳﺴﻴﻢ ﻛﻪ ﻫﻤﻪ ﭘﺎراﻣﺘﺮ دارﻧﺪ )ﺣﺪاﻗﻞ ﻳﻚ ﭘﺎراﻣﺘﺮ(‬ ‫دﻳﮕﺮ ﻧﻤﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;‪Cat Tom‬‬

‫و ﺣﺘﻤﺎ دادن ﭘﺎراﻣﺘﺮ )ﻳﻌﻨﻲ آرﮔﻮﻣﺎن‬

‫( ﻻزم اﺳﺖ‪ .‬ﻣﺜﻼ اﮔﺮ ﻳﻜﻲ از ‪constructor‬ﻫﺎ دو ﭘﺎراﻣﺘﺮ ﺑﺎ ﻧﻮع ‪int‬‬

‫داﺷﺘﻪ ﺑﺎﺷﺪ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;)‪Cat Tom(2,3‬‬

‫دادن آرﮔﻮﻣﺎن ﺑﻪ ‪ constructor‬را ‪ initialize‬ﻛﺮدن ﻳﺎ دادن ﻣﻘﺪار اوﻟﻴﻪ ﻣﻲﮔﻮﻳﻴﻢ‪.‬‬ ‫ﻫﻤﺎن ﻃﻮر ﻛﻪ ﻗﺒﻼ ﮔﻔﺘﻢ اﮔﺮ ‪constructor‬ي ﺗﻨﻬﺎ ﻳﻚ ﭘﺎراﻣﺘﺮ داﺷﺘﻪ ﺑﺎﺷﺪ ﻣﻲﺷﻮد ﺑﺮاي ‪ initialize‬ﻛﺮدن از‬ ‫»=« اﺳﺘﻔﺎده ﻛﺮد‪.‬‬ ‫ﺑﻪ ﻫﺮ ﻣﺘﻐﻴﺮ ﺑﺎ ﻧﻮع ﻳﻚ ﻛﻼس ﻳﻚ ‪) object‬ﻳﺎ ‪ (instance‬از آن ﻛﻼس ﻣﻲﮔﻮﻳﻴﻢ‪ .‬در ﻣﺜﺎل ﻗﺒﻞ ‪ Tom‬ﻳﻚ‬ ‫‪ object‬از ﻧﻮع ‪ Cat‬اﺳﺖ‪ .‬ﺑﺮاي ﻛﻼس ‪ Cat‬در ﻣﺜﺎل ﻗﺒﻞ )"‪ Cat("TT‬ﻳﻚ ‪ object‬از ﻧﻮع ‪ Cat‬اﺳﺖ‪ .‬در‬ ‫واﻗﻊ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﮕﻮﻳﻴﻢ ‪ constructor‬ﻳﻚ ‪ Cat‬ﻣﻲﺳﺎزد و آن را ﺑﺮﻣﻲﮔﺮداﻧﺪ )ﻳﻌﻨﻲ ‪ return‬ﻣﻲﻛﻨﺪ(‪.‬‬ ‫‪ constructor‬ﺑﻪ ﻣﻌﻨﻲ »ﺳﺎزﻧﺪه« اﺳﺖ‪.‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Cat‬‬ ‫{‬ ‫‪public:‬‬

‫‪168‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)‪Cat(int a, int b‬‬ ‫{‬ ‫;"‪cout<< "Constructor called\n‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪Cat Tom = Cat(1,1‬‬ ‫;‪cout<< typeid(Cat(1,1)).name() << endl‬‬ ‫;))‪cout<< sizeof(Cat(1,1‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪Constructor called‬‬ ‫‪Cat‬‬ ‫‪8‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫‪Constructor called‬‬ ‫‪class Cat‬‬ ‫‪1‬‬

‫)‪ ِ Cat(1,1‬اوﻟﻲ‪ constructor ،‬را ﻓﺮا ﻣﻲﺧﻮاﻧﺪ ﻳﻚ ‪ object‬از ﻧﻮع ‪ Cat‬درﺳﺖ ﻣﻲﻛﻨﺪ‪ .‬دو‬ ‫)‪ ِ Cat(1,1‬ﺑﻌﺪي ‪ constructor‬را ﻓﺮا ﻧﻤﻲﺧﻮاﻧﻨﺪ ﭼﻮن آرﮔﻮﻣﺎنﻫﺎي ‪ typeid‬و ‪ sizeof‬ﻫﺴﺘﻨﺪ‪ .‬ﻣﻲ‪-‬‬ ‫ﺑﻴﻨﻴﺪ ﻛﻪ در ‪compiler‬ﻫﺎي ‪ Borland‬و ‪ Microsoft‬اﺳﻢ ﻛﻼس ﺑﺎ ‪ typeid‬ﻣﺘﻔﺎوت ﺑﻴﺎن ﻣﻲﺷﻮد )ﻣﺜﻞ‬ ‫‪ struct‬ﻳﺎ ‪ enum‬ﻛﻪ ﻗﺒﻼ دﻳﺪﻳﺪ(‪ .‬ﻛﻼس ‪ Cat‬ﻫﻴﭻ ﻣﺘﻐﻴﺮي ﻧﺪارد ﭘﺲ ﻇﺎﻫﺮا ﺑﺎﻳﺪ ‪) size‬اﻧﺪازه( آن ﺻﻔﺮ‬ ‫ﺑﺎﺷﺪ اﻣﺎ ‪compiler‬ﻫﺎي ﻣﺨﺘﻠﻒ ﻫﺮ ﻛﺪام ﭼﻴﺰي اﻋﻼم ﻣﻲﻛﻨﻨﺪ‪ .‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﺑﻪ ﺟﺎي‬ ‫;)‪Cat Tom = Cat(1,1‬‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;)‪class Cat Tom = Cat(1,1‬‬

‫ﺣﺘﻲ ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;)‪struct Cat Tom = Cat(1,1‬‬

‫ﻧﻤﻲﺷﻮد ﻳﻚ ‪ constructor‬را ﺑﻪ ﻋﻨﻮان ﻳﻚ ‪ method‬ﻓﺮاﺧﻮاﻧﺪ ﻣﺜﻼ در ﻣﺜﺎل ﺑﺎﻻ ﻧﻤﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‬ ‫)‪.Tom.Cat(1,2‬‬ ‫‪ constructor‬ﻳﻌﻨﻲ »ﺳﺎزﻧﺪه« ﻳﻌﻨﻲ ﻣﺘﻐﻴﺮ را ﻣﻲﺳﺎزد‪ .‬ﺣﺎل ﻛﻪ ‪ ،constructor‬ﻣﺘﻐﻴﺮ را ﻣﻲﺳﺎزد ﻣﻮﻗﻊ از ﺑﻴﻦ‬ ‫رﻓﺘﻦ ﻣﺘﻐﻴﺮ‪ ،‬ﻣﺘﻐﻴﺮ ﺑﺎﻳﺪ ﺧﺮاب ﺷﻮد‪ .‬ﻣﻲﺗﻮاﻧﻴﻢ ﻳﻚ ‪ method‬ﺧﺮاب ﻛﻨﻨﺪه ﻫﻢ داﺷﺘﻪ ﺑﺎﺷﻴﻢ‪ .‬ﺑﻪ ‪ method‬ﺧﺮاب‬

‫‪169‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ﻫﻢ اﺳﻢ‬،‫ ﻫﻢ‬destructor .‫ ﺧﺮوﺟﻲ ﻧﺪارد‬constructor ‫ ﻣﺎﻧﻨﺪ‬destructor .‫ ﻣﻲﮔﻮﻳﻨﺪ‬destructor ‫ﻛﻨﻨﺪه‬ constructor ،‫ ﺑﺮ ﻋﻜﺲ‬destructor .‫ﻛﻼس اﺳﺖ ﺑﻪ ﺟﺰ اﻳﻦ ﻛﻪ ﺟﻠﻮي اﺳﻢ آن ﻳﻚ »~« ﻗﺮار ﻣﻲﮔﻴﺮد‬ ‫ را ﺑﺮ ﻋﻜﺲ‬destructor .‫ ﻛﺮد‬overload ‫ﻧﻤﻲﺗﻮاﻧﺪ ﭘﺎراﻣﺘﺮ داﺷﺘﻪ ﺑﺎﺷﺪ و ﺑﻨﺎﺑﺮاﻳﻦ ﻧﻤﻲﺷﻮد آن را‬ :‫ ﻓﺮاﺧﻮاﻧﺪ‬method ‫ ﻣﻲﺷﻮد ﻣﺜﻞ ﻳﻚ‬constructor #include <conio.h> #include <iostream> using namespace std; class Mouse { public: int a; Mouse() { cout<< "Constructor called\n"; } ~Mouse() // dectructor { cout<< "Destructor called\n"; } }; int main() { { Mouse Jerry; } getch(); }

Output: Constructor called Destructor called

.‫ ﺑﻪ ﻣﺤﺾ ﺧﺮوج از ﺑﻠﻮك اﻳﻦ ﻣﺘﻐﻴﺮ ﺑﺎﻳﺪ از ﺑﻴﻦ ﺑﺮود‬.‫ ﺗﻌﺮﻳﻒ ﺷﺪه‬Mouse ‫ از ﻧﻮع‬Jerry ‫در ﻳﻚ ﺑﻠﻮك ﻣﺘﻐﻴﺮ‬ .‫ ﻫﻢ ﺧﻮد ﺑﻪ ﺧﻮد از ﺑﻴﻦ ﻣﻲرود‬Jerry.a ‫ ﻓﺮاﺧﻮاﻧﺪه ﻣﻲﺷﻮد و‬destructor

copy constructor

:prototype ‫اﮔﺮ ﺗﺎﺑﻌﻲ ﺑﺎ اﻳﻦ‬ void f(Cat pussy_cat);

170

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ اﻣﺎ ﭼﻪ‬.‫( ﻣﻲﺷﻮد‬copy) ‫ ﻛﭙﻲ‬pussy_cat ‫ در‬Tom ‫ ﭼﻪ اﺗﻔﺎﻗﻲ ﻣﻲاﻓﺘﺪ؟‬f(Tom) ‫داﺷﺘﻪ ﺑﺎﺷﻴﻢ و ﺑﻨﻮﻳﺴﻴﻢ‬ ‫ ﻳﻜﻲ ﻳﻜﻲ ﻛﭙﻲ‬Cat ‫ﺟﻮري ﻛﭙﻲ ﻣﻲﺷﻮد؟ اﮔﺮ ﻧﺤﻮهي ﻛﭙﻲ ﺷﺪن را ﻣﺸﺨﺺ ﻧﻜﻨﻴﻢ ﻣﺘﻐﻴﺮﻫﺎي ﺗﻌﺮﻳﻒ ﺷﺪه در‬ :‫ﻣﻲﺷﻮﻧﺪ ﻣﺜﻞ اﻳﻦ‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: int a; int b; }; void f(Cat pussy_cat) { cout<< pussy_cat.a << endl; cout<< pussy_cat.b; } int main() { Cat Tom = {2,5}; f(Tom); getch(); }

Output: 2 5

.‫ ﻣﻘﺪار ﻣﺴﺎوي دارﻧﺪ‬Tom.a ‫ و‬pussy_cat.a ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬ copy constructor‫ اﻳﻦ ﻛﺎر ﺑﻪ وﺳﻴﻠﻪي‬.‫ﻣﻤﻜﻦ اﺳﺖ ﺑﺨﻮاﻫﻴﻢ ﻧﺤﻮهي ﻛﭙﻲ ﻛﺮدن را ﺧﻮدﻣﺎن ﻣﺸﺨﺺ ﻛﻨﻴﻢ‬ ‫ اﺳﺖ ﻛﻪ ﺗﻨﻬﺎ‬constructor ‫ ﻳﻚ‬Cat ‫ ﺑﺮاي ﻳﻚ ﻛﻼس ﻣﺜﻞ‬copy constructor ‫ ﻳﻚ‬.‫اﻣﻜﺎن ﭘﺬﻳﺮ اﺳﺖ‬ :‫ اﻳﻦ ﻣﺜﺎل را ﺑﺒﻴﻨﻴﺪ‬.‫ دارد‬Cat& ‫ﻳﻚ ﭘﺎراﻣﺘﺮ ﺑﺎ ﻧﻮع‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: int a; int b; Cat(int aParam, int bParam) { a = aParam; b = bParam;

171

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ } Cat(Cat& argument) { cout<< "copy constructor called\n"; a = argument.b; b = argument.a; } }; void f(Cat pussy_cat) { cout<< pussy_cat.a << endl; cout<< pussy_cat.b; } int main() { Cat Tom(2,5); f(Tom); getch(); }

Output: copy constructor called 5 2

‫ ﻗﺮار ﻣﻲﮔﻴﺮد‬pussy_cat ‫ در‬Tom ‫ ﻣﻮﻗﻌﻲ ﻛﻪ‬.(5 ‫ و‬2 ‫ ﭼﺎپ ﺷﺪه )ﻧﻪ‬2 ‫ و‬5 ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺑﺮ ﺧﻼف ﻣﻌﻤﻮل‬ ‫ ﻫﻢ ﺗﻌﺮﻳﻒ‬Cat ‫ ﻣﻲﺗﻮاﻧﻴﻢ ﻣﺘﻐﻴﺮي ﺑﺎ ﻧﻮع‬Cat ‫ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ در ﻛﻼس‬.‫ ﺧﻮاﻧﺪه ﻣﻲﺷﻮد‬copy constructor .(‫ دارد‬Cat ‫ ﻧﻮع‬copy constructor ‫ﻛﻨﻴﻢ )ﭘﺎراﻣﺘﺮ‬ ‫ ﻧﺪارد ﻣﺘﻐﻴﺮﻫﺎ ﺑﻪ ﻃﺮﻳﻖ‬copy constructor ،Zoo ‫ﺣﺎﻻ ﺑﻪ ﻣﺜﺎل زﻳﺮ دﻗﺖ ﻛﻨﻴﺪ ﻛﻪ ﻧﺸﺎن ﻣﻲدﻫﺪ وﻗﺘﻲ ﻛﻼس‬ :‫ﻋﺎدي ﻳﻜﻲ ﻳﻜﻲ ﻛﭙﻲ ﻣﻲﺷﻮﻧﺪ‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat(){} // default constructor Cat(Cat& argument) // copy constructor { cout<< "Cat copy constructor called\n"; } }; class Zoo { public: Cat Romeo; Cat Juliet;

172

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ Zoo(){} // default constructor }; void f(Zoo aZoo){} int main() { Zoo London_Zoo; f(London_Zoo); getch(); }

Output: Cat copy constructor called Cat copy constructor called

ِ ‫ ﺷﺪن‬copy ‫ ﻧﺪارد ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﻣﻮﻗﻊ‬copy constructor ‫ دارد وﻟﻲ‬Cat ‫ دو ﻣﺘﻐﻴﺮ ﺑﺎ ﻧﻮع‬Zoo ‫ﻣﻲﺑﻴﻨﻴﺪ‬ ‫ ﻳﻚ‬London_Zoo) .‫ ﻓﺮاﺧﻮاﻧﺪه ﺷﺪهاﻧﺪ‬Juliet ‫ و‬Romeo ‫ﻫﺎي‬copy constructor ،London_Zoo ‫ ﻗﺼﺪ ﻣﻦ از اﻳﻦ ﻣﺜﺎل اﺻﻼ ﺗﻮﻫﻴﻦ ﺑﻪ »ﺑﺎغ وﺣﺶ ﻟﻨﺪن« ﻳﺎ ﺑﻪ »روﻣﺌﻮ‬. copy ‫ داﺷﺘﻪ ﺑﺎﺷﺪ دﻳﮕﺮ‬Zoo copy constructor ‫ اﻣﺎ اﮔﺮ‬.(

‫ﺑﺎغ وﺣﺶ اﺳﺖ ﻛﻪ ﺗﻨﻬﺎ دو ﮔﺮﺑﻪ دارد‬ ‫و ژوﻟﻴﺖ« ﻧﻴﺴﺖ ﺑﺪ ﺑﺮداﺷﺖ ﻧﻜﻨﻴﺪ‬

:‫ ﺧﻮاﻧﺪه ﻧﻤﻲﺷﻮد‬Cat ‫ ِ ﻛﻼس‬constructor #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat(){} // default constructor Cat(Cat& argument) // copy constructor { cout<< "Cat copy constructor called\n"; } }; class Zoo { public: Cat Romeo; Cat Juliet; Zoo(){} // default constructor Zoo(Zoo& aZoo) { cout<< "Zoo copy constructor called\n"; } }; void f(Zoo aZoo){} int main() { Zoo London_Zoo;

173

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ f(London_Zoo); getch(); }

Output: Zoo copy constructor called

‫ از آن ﺟﺎﻳﻲ ﻛﻪ‬.‫ واﮔﺬار ﺷﺪه‬Zoo ‫ ﻣﻮﺟﻮد در‬copy constructor ‫در واﻗﻊ وﻇﻴﻔﻪي ﻛﭙﻲ ﻛﺮدن ﻛﺎﻣﻼ ﺑﻪ‬ ‫ اﺳﺘﻔﺎده ﻛﻨﻴﻢ و اﻳﻦ ﻛﺎر ﺑﻪ ﻃﻮر ﻃﺒﻴﻌﻲ اﻣﻜﺎن‬Cat ‫ ﻣﻮﺟﻮد در‬copy constructor ‫ﻣﻤﻜﻦ اﺳﺖ ﺑﺨﻮاﻫﻴﻢ از‬ :‫ را اﻧﺠﺎم دﻫﺪ ﻣﺜﻼ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‬copy constructor ‫ داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﻛﻪ ﻛﺎر‬Cat ‫ﻧﺪارد ﺑﻬﺘﺮ اﺳﺖ ﺗﺎﺑﻌﻲ در‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat(){} // default constructor void CopyFunction(Cat& pussy) { cout<< "copying Cat\n"; } Cat(Cat& argument) // copy constructor { CopyFunction(argument); } }; class Zoo { public: Cat Romeo; Cat Juliet; Zoo(){} // default constructor Zoo(Zoo& aZoo) { Romeo.CopyFunction(aZoo.Romeo); Juliet.CopyFunction(aZoo.Juliet); cout<< "Zoo copy constructor called\n"; } }; void f(Zoo aZoo){} int main() { Zoo London_Zoo; f(London_Zoo); getch(); }

Output:

174

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ copying Cat copying Cat Zoo copy constructor called

‫ )از ﺟﻤﻠﻪ‬constructor ‫ را ﺗﻌﺮﻳﻒ ﻛﺮدهام اﻳﻦ اﺳﺖ ﻛﻪ ﻧﻤﻲﺷﻮد ﻳﻚ‬CopyFunction() ‫ﻋﻠﺖ اﻳﻦ ﻛﻪ‬ .‫( را ﺑﻪ ﺷﻜﻠﻲ ﻛﻪ در اﻳﻦ ﺟﺎ ﻧﻴﺎز دارﻳﻢ ﻓﺮاﺧﻮاﻧﺪ‬copy constructor ‫ داﺷﺘﻪ ﺑﺎﺷﺪ‬constructor ‫ در ﺑﺎﻻ ﭼﻪ‬Zoo ‫ﻫﺎ ﻧﻤﻲاﻓﺘﺪ ﻳﻌﻨﻲ‬constructor ‫ﺑﺪ ﻧﻴﺴﺖ ﺑﮕﻮﻳﻢ ﻛﻪ اﻳﻦ اﺗﻔﺎق ﺑﺮاي‬ :‫ ﻓﺮا ﺧﻮاﻧﺪه ﻣﻲﺷﻮد‬Cat ِ constructor ،Zoo ‫ ﻫﻨﮕﺎم ﺗﻌﺮﻳﻒ ﻳﻚ ﻣﺘﻐﻴﺮ ﺟﺪﻳﺪ ﺑﺎ ﻧﻮع‬،‫ﭼﻪ ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat() // default constructor { cout<< "Cat constructor\n"; } }; class Zoo { public: Cat Romeo; Cat Juliet; Zoo() // default constructor { cout<< "Zoo constructor\n"; } }; int main() { Zoo London_Zoo; getch(); }

Output: Cat constructor Cat constructor Zoo constructor

‫ ﻣﻮﺟﻮد در‬copy constructor ‫ ﺑﻪ ﻋﻬﺪهي‬Zoo ‫ در‬Cat ‫ﺑﻪ اﻳﻦ ﺗﺮﺗﻴﺐ ﮔﺮﭼﻪ وﻇﻴﻔﻪي ﻛﭙﻲ ﻛﺮدن ﻣﺘﻐﻴﺮﻫﺎي‬ ‫ در اﻳﻦ‬C++ ‫ ﻣﻦ ﻓﻜﺮ ﻣﻲﻛﻨﻢ‬.‫ ﺧﻮدﺷﺎن اﺳﺖ‬constructor ‫ اﺳﺖ وﻟﻲ وﻇﻴﻪي ﺳﺎﺧﺘﻦ آنﻫﺎ ﺑﻪ ﻋﻬﺪهي‬Zoo .‫ﻣﻮارد ﻛﻤﻲ ﺿﻌﻒ دارد ﻛﻪ ﺑﺎﻳﺪ اﺻﻼح ﺷﻮد‬ 175

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ داﺷﺘﻪ ﺑﺎﺷﺪ )ﭼﻮن در اﻳﻦ‬Cat ‫ ﻧﻮع‬Cat& ‫ ﻧﻤﻲﺗﻮاﻧﺪ ﺑﻪ ﺟﺎي ﻧﻮع‬Cat ‫ ِ ﻛﻼس‬copy constructor ‫ﭘﺎراﻣﺘﺮ‬ ‫ ﻣﻲﺗﻮاﻧﺪ ﻳﻜﻲ از اﻳﻦ اﺷﻜﺎل را داﺷﺘﻪ‬copy constructor ‫ ﺑﻪ ﻃﻮر ﻛﻠﻲ‬.(‫ﺻﻮرت ﺧﻮدش ﺑﻪ ﻛﭙﻲ ﺷﺪن ﻧﻴﺎز دارد‬ :‫ﺑﺎﺷﺪ‬ Cat(Cat&) Cat(const Cat&) Cat(const Cat&, int = 1); Cat(const Cat&, int = 1 , char = 8); . .

:‫ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﺗﻮﺟﻪ ﻛﻨﻴﺪ‬.‫ ﻗﺎﺑﻞ ﺣﺬف اﺳﺖ‬const ‫ﻛﻪ‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat(){}// default costructor Cat(Cat& argument, int = 5 ,char y = 4) // copy constructor { cout<< "copy constrcutor\n"; } }; void f(Cat pussy){} int main() { Cat Romeo,Juliet; f(Romeo); getch(); }

Output: copy constructor

:‫ ﻓﺮا ﺧﻮاﻧﺪه ﻣﻲﺷﻮد‬copy constructor ‫ ﻫﻢ‬return ‫ﻣﻮﻗﻊ‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat() { // do nothing }

176

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ Cat(const Cat& pussy) { cout<< "copy constructor"; } }; Cat f() { Cat Tom; return Tom; } int main() { f(); _getch(); }

Output: copy constructor Tom ‫ داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﺑﺎﻳﺪ ﻳﻚ ﻛﭙﻲ از‬main() ‫ ﺑﺮاي اﻳﻦ ﻛﻪ ﺷﻴﺌﻲ در‬.‫ اﺳﺖ‬f() ‫ ﻳﻚ ﺷﻲء در‬Tom ‫در واﻗﻊ‬

.‫ اﻧﺠﺎم ﻣﻲدﻫﺪ‬copy constructor ‫ اﻳﻦ ﻛﺎر را‬.‫ﺗﻬﻴﻪ ﻛﻨﻴﻢ‬ :‫ ﻓﺮا ﺧﻮاﻧﺪه ﺷﺪه‬copy constructor ‫در ﻣﺜﺎل زﻳﺮ‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat(){} // default costructor Cat(const Cat& argument) // copy constructor { cout<< "copy constructor\n"; } }; int main() { Cat Tom; Cat kitten = Tom; getch(); }

Output: copy constructor

‫ ﺣﺎل اﮔﺮ ﺑﻪ ﺟﺎي‬.‫ ﺑﺎ ﺗﺴﺎوي ﻓﺮاﺧﻮاﻧﺪه ﺷﺪه‬Cat ‫ ﺗﻚ ﭘﺎراﻣﺘﺮي ﻛﻼس‬constructor ‫در اﻳﻦ ﻣﺜﺎل‬ Cat kitten = Tom;

177

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪Cat& kitten = Tom‬‬

‫ﻳﺎ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;)‪Cat& kitten(Tom‬‬

‫دﻳﮕﺮ ‪ copy constructor‬ﻓﺮا ﺧﻮاﻧﺪه ﻧﻤﻲﺷﻮد‪ .‬اﻳﻦ ﻓﻘﻂ در ﻣﻮرد ‪ copy constructor‬درﺳﺖ اﺳﺖ‪.‬‬

‫ ‪explicit‬‬

‫از ﻓﺼﻞﻫﺎي ﮔﺬﺷﺘﻪ ﺑﻪ ﻳﺎد دارﻳﺪ ﻛﻪ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;'‪char ch = 'a‬‬ ‫;‪int a = ch‬‬

‫و ﺑﻪ ﻃﻮر ﭘﻨﻬﺎن )‪ implicit) ch‬ﻛﻪ ﻧﻮع ‪ char‬دارد ﺑﻪ ﻳﻚ ‪ int‬ﺗﺒﺪﻳﻞ ﻣﻲﺷﻮد‪ .‬و ﻣﻲداﻧﻴﺪ ﻛﻪ ﻧﻤﻲﺷﻮد‬ ‫ﻧﻮﺷﺖ‪:‬‬ ‫;‪int* p = new int‬‬ ‫;‪int a = p‬‬

‫و ﺑﻪ ﺟﺎي آن ﺑﺎﻳﺪ ﻧﻮﺷﺖ‪:‬‬ ‫;‪int* p = new int‬‬ ‫;‪int a = (int) p‬‬

‫ﺑﻪ اﻳﻦ ﺟﻮر ﺗﺒﺪﻳﻞ ﻧﻮع‪ ،‬ﺗﺒﺪﻳﻞ ﻧﻮع آﺷﻜﺎر )‪ (explicit‬ﻣﻲﮔﻮﻳﻴﻢ‪.‬‬ ‫ﮔﻔﺘﻢ ﻛﻪ اﮔﺮ ﻛﻼس ‪ Cat‬ﻳﻚ ‪ constructor‬ﺑﻪ ﺷﻜﻞ‬ ‫)‪Cat(int a‬‬ ‫}‪{...‬‬

‫داﺷﺘﻪ ﺑﺎﺷﺪ آن وﻗﺖ ﻣﻲﺷﻮد ﻳﻚ ﺗﺒﺪﻳﻞ ﻧﻮع ﭘﻨﻬﺎن داﺷﺖ‪:‬‬ ‫;‪Cat Tom = 2‬‬

‫ﺣﺎﻻ اﮔﺮ ﻧﺨﻮاﻫﻴﻢ ﻳﻚ ‪ ،constructor‬اﺟﺎزهي ﺗﺒﺪﻳﻞ ﻧﻮع ﭘﻨﻬﺎن ﺑﺪﻫﺪ ﻛﺎﻓﻲ اﺳﺖ ﺟﻠﻮي ﺗﻌﺮﻳﻒ‬ ‫‪ constructor‬ﺑﻨﻮﻳﺴﻴﻢ ‪ explicit‬ﺗﺎ ﺗﻨﻬﺎ ﺗﺒﺪﻳﻞ ﻧﻮع آﺷﻜﺎر ﻗﺎﺑﻞ اﻧﺠﺎم ﺑﺎﺷﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Cat‬‬ ‫{‬ ‫‪public:‬‬

‫‪178‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)‪explicit Cat(int d‬‬ ‫{‬ ‫;"‪cout<< "Cat(int d)\n‬‬ ‫}‬ ‫;}‬

‫‪// error‬‬

‫)(‪int main‬‬ ‫{‬ ‫;‪// Cat Romeo = 2‬‬ ‫;‪Cat Tom = (Cat) 2‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫)‪Cat(int d‬‬

‫ﺣﺎل ﻣﺎ ﻣﻲﺗﻮاﻧﻴﻢ ﺗﺼﻮر ﺧﻮدﻣﺎن را از ‪ int‬ﺑﻪ ﻋﻨﻮان ﻛﻼس ﺑﻪ اﻳﻦ ﺻﻮرت ﻛﺎﻣﻞ ﺗﺮ ﻛﻨﻴﻢ‪:‬‬ ‫‪class int‬‬ ‫{‬ ‫;‪int a‬‬ ‫‪public:‬‬ ‫}{)(‪int‬‬ ‫)‪int(int x‬‬ ‫{‬ ‫;‪a = x‬‬ ‫}‬ ‫)‪explicit int(char* c‬‬ ‫{‬ ‫;‪a = (int) c‬‬ ‫}‬ ‫;}‬

‫ﺗﻮﺟﻪ داﺷﺘﻪ ﺑﺎﺷﻴﺪ ﻛﻪ اﻳﻦ ﻓﻘﻂ ﻳﻚ ﺗﺼﻮر اﺳﺖ ﻛﻪ ﻣﺎ را ﺑﺎ ‪ int‬آﺷﻨﺎ ﺗﺮ ﻣﻲﻛﻨﺪ‪ .‬وﮔﺮﻧﻪ اﻳﻦ ﺧﻄﻮط در ‪C++‬‬ ‫اﺳﺎﺳﺎ ﺧﻄﺎ دارﻧﺪ‪.‬‬

‫ ‪this‬‬

‫‪ E‬ض ‪ Cat .‬ﻳﻚ ﻛﻼس ﺑﺎﺷﺪ و ‪ Tom‬ﻳﻚ ‪ object‬ﺑﺎ ﻧﻮع ‪ Cat‬و ‪ Cat‬ﻳﻚ ‪ method‬داﺷﺘﻪ ﺑﺎﺷﺪ‪ .‬آﻳﺎ‬ ‫اﻳﻦ ‪ method‬ﺑﻪ ‪ Tom‬دﺳﺘﺮﺳﻲ دارد؟ ﻣﺜﻼ ﻣﻲﺗﻮاﻧﺪ ‪ Tom‬را ‪ return‬ﻛﻨﺪ؟ ﺟﻮاب ﻣﺜﺒﺖ اﺳﺖ‪ .‬در ﻫﺮ‬ ‫‪ method‬از ﻳﻚ ﻛﻼس ﺑﺎ ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ this‬ﻣﻲﺷﻮد ﺑﻪ ‪object‬ي ﻛﻪ از ﻧﻮع آن ﻛﻼس ﺳﺎﺧﺘﻪ ﺷﺪه )و‬

‫‪179‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ method‬از ﻃﺮﻳﻖ آن ﻓﺮاﺧﻮاﻧﻲ ﻣﻲﺷﻮد( دﺳﺘﺮﺳﻲ داﺷﺖ‪ .‬ﻣﺜﻼ در ﻫﺮ ‪ method‬در ‪ Cat‬ﻛﻪ ﺑﻪ وﺳﻴﻠﻪي ‪Tom‬‬

‫ﻓﺮاﺧﻮاﻧﺪه ﺷﻮد ‪ this‬ﻳﻚ ‪ pointer‬ﺑﻪ ‪ Tom‬اﺳﺖ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Boy‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int intelligence‬‬ ‫)(‪Boy f‬‬ ‫{‬ ‫;‪intelligence = 5‬‬ ‫;‪this -> intelligence = 5‬‬ ‫;‪return *this‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪Boy Hubert‬‬ ‫;)(‪Boy Hub = Hubert.f‬‬ ‫;‪cout<< Hub.intelligence‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪5‬‬

‫روﺷﻦ اﺳﺖ ﻛﻪ ‪ intelligence‬و ‪ this->intelligence‬ﻳﻜﻲ ﻫﺴﺘﻨﺪ‪ .‬در اﻳﻦ ﺟﺎ ‪ this‬وﻗﺘﻲ ﺑﻪ‬ ‫ﻛﺎر رﻓﺘﻪ ﻛﻪ ﺗﺎﺑﻊ )(‪ f‬ﺑﺎ ‪ Hubert‬ﻓﺮاﺧﻮاﻧﺪه ﺷﺪه و ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﺑﻪ ‪ Hubert‬اﺷﺎره دارد‪ .‬در واﻗﻊ ‪this‬‬

‫ﻫﻤﺎن ‪ &Hubert‬اﺳﺖ‪.‬‬

‫‪operator‬ه ‬

‫وﻗﺘﻲ ‪ a‬و ‪ int ،b‬ﺑﺎﺷﻨﺪ‪ ،‬ﻣﻲﺷﻮد آنﻫﺎ را ﺑﺎ ﻫﻢ ﺟﻤﻊ ﻛﺮد و ‪ a+b‬ﻫﻢ \‪ int n‬اﺳﺖ‪ .‬ﺣﺎﻻ اﮔﺮ ‪ Romeo‬و‬ ‫‪ Juliet‬دو ﺷﻲء ﺑﺎ ﻧﻮع ‪ Cat‬ﺑﺎﺷﻨﺪ‪ ،‬آﻳﺎ ﻣﻲﺷﻮد آنﻫﺎ را ﺑﺎ ﻫﻢ ﺟﻤﻊ ﻛﺮد؟ ‪operator‬ﻫﺎ اﻳﻦ ﻛﺎر را اﻣﻜﺎن‬ ‫ﭘﺬﻳﺮ ﻣﻲﻛﻨﻨﺪ‪) operator .‬ﻋﻤﻠﮕﺮ( در واﻗﻊ ﻳﻚ ﺗﺎﺑﻊ اﺳﺖ‪ .‬ﻣﺜﻼ ‪ operator +‬ﻳﻚ ﺗﺎﺑﻊ ﺑﺎ دو ﭘﺎراﻣﺘﺮ اﺳﺖ‪.‬‬ ‫وﻟﻲ ﺑﺮاي ﻓﺮاﺧﻮاﻧﻲ ‪ ،operator‬ﺑﻪ ﺟﺎي اﻳﻦ ﻛﻪ ﺑﻨﻮﻳﺴﻴﻢ )‪ +(2,3‬ﻣﻲﻧﻮﻳﺴﻴﻢ ‪ .2+3‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬

‫‪180‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ using namespace std; class Cat { public: Cat(){} // default costructor Cat(const Cat& argument) // copy constructor { cout<< "copy constructor\n"; } }; #pragma argsused Cat operator + (Cat pussy1, Cat pussy2) { return pussy1; } int main() { Cat Romeo, Juliet; Cat kitten; kitten = Romeo + Juliet; getch(); }

Output: copy constructor copy constructor copy constructor

‫ ﻣﻌﻨﻲ دارد و ﻛﺎر آن‬Borland ‫ﻫﺎي‬compiler ‫ ﺗﻨﻬﺎ در‬#pragma argsused ‫ﻫﻤﺎن ﻃﻮر ﻛﻪ ﻣﻲداﻧﻴﺪ‬ ‫ ﻧﻮﺷﺘﻦ آن در‬.‫ اﺳﺖ ﻛﻪ ﺑﻪ ﺧﺎﻃﺮ اﺳﺘﻔﺎده ﻧﻜﺮدن از ﻳﻚ ﭘﺎراﻣﺘﺮ ﺑﻪ وﺟﻮد ﻣﻲآﻳﺪ‬warning ‫ﺣﺬف ﻳﻚ‬ ‫ ﻓﺮا‬copy constructor ‫ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺳﻪ ﺑﺎر‬.‫ درﺳﺖ ﻣﻲﻛﻨﺪ‬warning ‫ ﻳﻚ‬Microsoft ‫ﻫﺎي‬compiler ‫ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ دو ﺗﺎ از اﻳﻦﻫﺎ ﻛﻢ ﺷﻮد ﻣﻲﺗﻮاﻧﻴﻢ ﺑﺎ اﺿﺎﻓﻪ‬.return ‫ دو ﺗﺎ ﺑﺮاي ﭘﺎراﻣﺘﺮﻫﺎ و ﻳﻜﻲ ﺑﺮاي‬.‫ﺧﻮاﻧﺪه ﺷﺪه‬ :‫ ﺑﺮﻧﺎﻣﻪ را ﺑﻪ اﻳﻦ ﺻﻮرت ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﻢ‬،& ‫ﻛﺮدن دو‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat(){} // default costructor Cat(const Cat& argument) // copy constructor { cout<< "copy constructor\n"; } };

181

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #pragma argsused Cat& operator + (Cat& pussy1, Cat pussy2) { return pussy1; } int main() { Cat Romeo, Juliet; Cat kitten; kitten = Romeo + Juliet; getch(); }

Output: copy constructor

‫ اﮔﺮ در‬.‫ ﻫﻢ & ﺑﮕﺬارﻳﺪ‬pussy2 ‫ ﺧﻮاﻧﺪه ﻧﺸﻮد ﻗﺒﻞ از ﭘﺎراﻣﺘﺮ‬copy constructor ‫اﮔﺮ ﻣﻲﺧﻮاﻫﻴﺪ اﺻﻼ‬ ‫ اﻳﺮاد‬BDS 2006 (update1)،‫ ﺣﺬف ﺷﻮد‬const ‫ﻛﻠﻤﻪي ﻛﻠﻴﺪي‬copy constructor ‫ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ در‬ ‫ و ﻧﺴﺨﻪﻫﺎي ﻗﺪﻳﻤﻲ‬Microsoft ِ compiler .‫ اﺳﺖ‬compiler ‫ﻣﻲﮔﻴﺮد و اﺟﺮا ﻧﻤﻲﺷﻮد ﻛﻪ ﺑﻪ ﻧﻈﺮ اﺷﻜﺎل از‬ ‫ ﺗﺎﺑﻊ‬operator ‫ اﮔﺮ ﺑﻪ ﺟﺎي‬BDS 2006 ‫ وﻟﻲ‬.‫ اﻳﻦ اﺷﻜﺎل را ﻧﻤﻲﮔﻴﺮﻧﺪ‬Borland ‫ﻫﺎي‬compiler ‫ﺗﺮ‬ .‫ﺑﮕﺬارﻳﻢ اﻳﺮاد ﻧﻤﻲﮔﻴﺮد‬ :‫ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‬.‫ ﺑﺎﺷﺪ‬postfix ‫ ﻳﺎ‬prefix ‫ آﺷﻨﺎ ﻫﺴﺘﻴﺪ و ﻣﻲداﻧﻴﺪ ﻛﻪ ﻣﻲﺗﻮاﻧﺪ‬++ ‫ﺑﺎ ﻋﻤﻠﮕﺮ‬ #include <conio.h> #include <iostream> using namespace std; class Cat {}; void operator ++(Cat& pussy) // prefix { cout<< "prefix\n"; } void operator ++(Cat& pussy,int) // postfix { cout<< "postfix\n"; } int main() { Cat Tom; ++Tom; // prefix Tom++; // postfix _getch(); }

Output:

182

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪prefix‬‬ ‫‪postfix‬‬

‫ﺗﻌﺪاد ﭘﺎراﻣﺘﺮﻫﺎي ﻫﺮ ‪ ،operator‬ﻣﺸﺨﺺ اﺳﺖ و ﻧﻤﻲﺷﻮد اﻳﻦ ﺗﻌﺪاد را ﺗﻐﻴﻴﺮ داد اﻣﺎ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ در ﺑﺎﻻ دو‬ ‫ﺑﺎر ‪ operator ++‬را ﺗﻌﺮﻳﻒ ﻛﺮدهام و در ﻳﻜﻲ از ﺗﻌﺮﻳﻒﻫﺎ ﺑﻴﺶ از ﻳﻚ ﭘﺎرﻣﺘﺮ ﺑﻪ ﻛﺎر ﺑﺮدهام‪ .‬اﻳﻦ در واﻗﻊ‬ ‫اﻣﻜﺎﻧﻲ اﺳﺖ ﻛﻪ زﺑﺎن ‪ C++‬در اﺧﺘﻴﺎر ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻗﺮار داده ﺗﺎ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﺑﺘﻮاﻧﺪ ﺑﮕﻮﻳﺪ ﻛﻪ ‪ ++‬ﺑﻪ ﻋﻨﻮان ﻳﻚ‬ ‫‪ postfix‬ﺗﻌﺮﻳﻒ ﻣﻲﺷﻮد‪ .‬ﭘﺎراﻣﺘﺮ دوم اﺻﻼ اﺳﺘﻔﺎده ﻧﻤﻲﺷﻮد‪ .‬ﺑﺮاي ﺗﻮﺿﻴﺢ ﺑﻴﺶ ﺗﺮ ﺑﺎﻳﺪ ﺑﮕﻮﻳﻢ ﻛﻪ ‪ ++‬ﻣﻲﺗﻮاﻧﺪ ﺑﻪ‬ ‫ﻋﻨﻮان ‪ prefix‬اﺳﺘﻔﺎده ﺑﺸﻮد ﻣﺜﻞ ‪ ++a‬ﻳﺎ ﺑﻪ ﻋﻨﻮان ‪ postfix‬اﺳﺘﻔﺎده ﺑﺸﻮد ﻣﺜﻞ ‪ .a++‬اﮔﺮ ‪ operator ++‬ﺑﻪ‬ ‫ﻋﻨﻮان ‪ prefix‬ﺗﻌﺮﻳﻒ ﺷﻮد ﻣﻲﺗﻮاﻧﻴﻢ آن را ﺑﻪ ﻋﻨﻮان ‪ postfix‬ﻫﻢ ﺑﻪ ﻛﺎر ﺑﺒﺮﻳﻢ اﻣﺎ ﻳﻚ ‪ warning‬ﮔﺮﻓﺘﻪ‬ ‫ﻣﻲﺷﻮد‪ .‬ﻋﻜﺲ اﻳﻦ اﻣﻜﺎن ﻧﺪارد ﻳﻌﻨﻲ اﮔﺮ ‪ operator ++‬ﺑﻪ ﻋﻨﻮان ‪ postfix‬ﺗﻌﺮﻳﻒ ﺷﻮد ﻧﻤﻲﺷﻮد آن را ﺑﻪ‬ ‫ﻋﻨﻮان ‪ prefix‬ﺑﻪ ﻛﺎر ﺑﺮد‪.‬‬ ‫ﻣﻲداﻧﻴﻢ ﻛﻪ وﻗﺘﻲ ‪ a‬ﻳﻚ ‪ int‬ﺑﺎﺷﺪ ﺑﺎ ﻣﻘﺪار ‪ ،2‬ﺧﺮوﺟﻲ ‪ ++a‬ﺑﺮاﺑﺮ ﺑﺎ ‪ 3‬و ﺧﺮوﺟﻲ ‪ a++‬ﺑﺮاﺑﺮ ﺑﺎ ‪ 2‬اﺳﺖ‪ .‬ﺑﻬﺘﺮ‬ ‫اﺳﺖ ﻣﺎ ﻫﻢ اﻳﻦ ﻗﺎﻋﺪه را در ﺧﺮوﺟﻲ ‪ postfix‬و ‪ prefix‬رﻋﺎﻳﺖ ﻛﻨﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Cat‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int a‬‬ ‫;}‬ ‫‪Cat operator ++(Cat& pussy) // prefix‬‬ ‫{‬ ‫;‪pussy.a++‬‬ ‫;‪Cat ret = pussy‬‬ ‫;‪return ret‬‬ ‫}‬ ‫‪Cat operator ++(Cat& pussy,int) // postfix‬‬ ‫{‬ ‫;‪Cat ret = pussy‬‬ ‫;‪pussy.a++‬‬ ‫;‪return ret‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;}‪Cat Tom = {2‬‬ ‫;}‪Cat Silvester = {2‬‬ ‫‪cout<< (Tom++).a‬‬ ‫‪<< endl; // output: 2‬‬ ‫‪cout<< (++Silvester).a << endl; // output: 3‬‬ ‫‪cout<< Tom.a‬‬ ‫‪<< endl; // output: 3‬‬

‫‪183‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ cout<< Silvester.a

<< endl; // output: 3

_getch(); }

Output: 2 3 3 3

.‫اﻟﺒﺘﻪ ﻫﻤﻪ ﭼﻴﺰ در دﺳﺖ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ اﺳﺖ و اﮔﺮ او ﺑﺨﻮاﻫﺪ ﻣﻲﺗﻮاﻧﺪ ﺧﺮوﺟﻲ را ﻫﺮ ﭼﻴﺰي ﺑﮕﺬارد‬ :‫– ﻫﻢ درﺳﺖ اﺳﺖ‬- ‫ ﮔﻔﺘﻢ ﺑﺮاي‬++ ‫ﻣﺸﺎﺑﻪ ﭼﻴﺰﻫﺎﻳﻲ ﻛﻪ ﺑﺮاي‬ #include <conio.h> #include <iostream> using namespace std; class Cat {}; void operator --(Cat& pussy) // prefix { cout<< "prefix\n"; } void operator --(Cat& pussy,int) // postfix { cout<< "postfix\n"; } int main() { Cat Tom; --Tom; // prefix Tom--; // postfix _getch(); }

Output: prefix postfix

:‫ﺑﻪ ﻣﺜﺎل زﻳﺮ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; class Cat {

184

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪public:‬‬ ‫;‪int a‬‬ ‫;}‬ ‫)‪Cat& operator - (Cat& pussy, int a‬‬ ‫{‬ ‫;‪pussy.a -= a‬‬ ‫;‪return pussy‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;}‪Cat Tom = {20}, Kitty = {10‬‬ ‫;‪Tom - 2 = Kitty‬‬ ‫;‪cout<< Tom.a‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪10‬‬ ‫در اﻳﻦ ﺟﺎ ‪ Tom-2‬ﺑﺮ ﺧﻼف ﻣﻌﻤﻮل ﻳﻚ ‪ LValue‬اﺳﺖ زﻳﺮا ﻣﺎ اﻳﻦ ﻃﻮر ﺧﻮاﺳﺘﻪاﻳﻢ‪ .‬در واﻗﻊ ﻧﻮﺷﺘﻦ ‪Tom-‬‬

‫‪ 2=Kitty‬ﺑﺎ ‪ Tom=Kitty‬ﻓﺮﻗﻲ ﻧﺪارد‪ .‬ﻧﻮﺷﺘﻦ ‪ Tom-3‬ﺳﻪ واﺣﺪ از ‪ Tom.a‬ﻛﻢ ﻣﻲﻛﻨﺪ اﻟﺒﺘﻪ ﺑﻬﺘﺮ ﺑﻮد ﺑﺮاي‬ ‫اﻳﻦ ﻛﺎر از =‪ operator -‬اﺳﺘﻔﺎده ﻣﻲﻛﺮدﻳﻢ‪.‬‬ ‫وﻗﺘﻲ ﻳﻚ ‪ operator‬ﺗﻌﺮﻳﻒ ﻣﻲﻛﻨﻴﻢ ﺣﺪاﻗﻞ ﻳﻜﻲ از ﭘﺎراﻣﺘﺮﻫﺎي آن ﺑﺎﻳﺪ ‪) class‬ﻳﺎ ‪ (struct‬ﺑﺎﺷﺪ‪.‬‬ ‫‪ operator‬ﺟﺪﻳﺪ ﻧﻤﻲﺷﻮد ﺧﻠﻖ ﻛﺮد‪ .‬ﻣﺜﻼ ** ‪ operator‬ﻧﺪارﻳﻢ‪ .‬ﺗﻌﺪاد ﭘﺎراﻣﺘﺮﻫﺎي ‪operator‬ﻫﺎي‬ ‫ﻣﻮﺟﻮد را ﻫﻢ ﻧﻤﻲﺷﻮد ﻋﻮض ﻛﺮد‪.‬‬ ‫ﺣﺎﻻ ﺑﮕﺬارﻳﺪ ﺗﻨﻬﺎ ‪ operator‬ﺳﻪ ﭘﺎراﻣﺘﺮي ‪ C++‬ﻳﻌﻨﻲ ‪ ?:‬را ﻣﻌﺮﻓﻲ ﻛﻨﻢ‪ .‬اﻳﻦ ‪ operator‬را ﺑﺮاي ﻛﻼسﻫﺎ‬ ‫ﻫﻢ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻪ ﻛﺎر ﺑﺒﺮﻳﻢ و ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻧﻤﻲﺗﻮاﻧﺪ آن را ﺗﻌﺮﻳﻒ ﻛﻨﺪ‪ .‬ﻓﺮﻣﻮل اﻳﻦ ‪ operator‬اﻳﻦ اﺳﺖ‪:‬‬ ‫]‪opm‬ار)‪4i Zd (2‬ع)‪opm] : [(2‬ار)‪4i Zd (1‬ع)‪23] ? [(1‬ار‪[/‬‬

‫ﻛﻪ ﻧﻮع ﺧﺮوﺟﻲ آن ‪4i‬ع)‪ (1‬ﻳﺎ ‪4i‬ع)‪ (2‬اﺳﺖ‪4i .‬ع)‪ (1‬و ‪4i‬ع)‪(2‬ﺑﺎﻳﺪ ﻳﻚ ﺟﻮر ﺑﺎﺷﻨﺪ ﻳﺎ ﺣﺪاﻗﻞ ﻳﻜﻲ‬ ‫از ‪4i‬ع)‪ (1‬ﻳﺎ ‪4i‬ع)‪ (2‬ﻗﺎﺑﻞ ﺗﺒﺪﻳﻞ ﺑﻪ دﻳﮕﺮي ﺑﺎﺷﺪ‪ .‬اﻳﻦ ﻛﻪ ﻛﺪام ﻗﺎﺑﻞ ﺗﺒﺪﻳﻞ ﺑﻪ دﻳﮕﺮي ﺑﺎﺷﺪ ﺑﻪ ‪compiler‬‬ ‫ﺑﺴﺘﮕﻲ دارد‪ .‬اﮔﺮ ]‪23‬ار‪ [/‬درﺳﺖ ﺑﺎﺷﺪ ﺧﺮوﺟﻲ اﻳﻦ ﻋـﺒﺎرت ‪opm‬ار)‪ (1‬اﺳﺖ وﮔﺮﻧﻪ ﺧﺮوﺟﻲ‬ ‫‪opm‬ار)‪ (2‬اﺳﺖ‪ .‬ﻣﺜﺎل زﻳﺮ ﻃﺮز اﺳﺘﻔﺎده از اﻳﻦ ﻋﻤﻠﮕﺮ را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪185‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ int main() { int a = 2; int b = 3; char* c = a > b ? "hello" : "bye"; cout<< c; _getch(); }

Output: bye

.‫ دارﻧﺪ‬char* ‫" اﺳﺖ ﻛﻪ ﻫﺮ دو ﻧﻮع‬bye" ‫( ﻫﻤﺎن‬2)‫ار‬opm ‫" و‬hello" ‫( ﻫﻤﺎن‬1)‫ار‬opm ‫در اﻳﻦ ﺟﺎ‬ ‫ ﻧﺴﺒﺖ‬c ‫" ﺑﻪ‬bye" ‫( ﻳﻌﻨﻲ‬2)‫ار‬opm ‫ ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ‬.‫ اﺳﺖ ﻛﻪ در اﻳﻦ ﺟﺎ ﻧﺎدرﺳﺖ اﺳﺖ‬a>b ‫ ﻫﻤﺎن‬/‫ار‬23 .‫ ﭼﺎپ ﺷﺪه‬c ‫ در ﻧﻬﺎﻳﺖ‬.‫داده ﺷﺪه‬ :‫در واﻗﻊ ﻓﺮﻣﻮل ﺑﺎﻻ ﻣﻌﺎدل اﺳﺖ ﺑﺎ اﻳﻦ‬ f(/‫ار‬23,( 1) ‫ع‬4i

Zd (1)‫ار‬opm,(2)‫ع‬4i Zd (2)‫ار‬opm)

:‫ ﺑﻪ اﻳﻦ ﺷﻜﻞ ﺗﻌﺮﻳﻒ ﻣﻲﺷﻮد‬f() ‫ﻛﻪ در آن‬ (1)‫ع‬4i f(bool a,(1)‫ع‬4i x,(2)‫ع‬4i y) {

(1)‫ع‬4i yy = y; // convert if(a) return x; else return yy; }

:‫ﻳﺎ اﻳﻦ ﻃﻮري ﺗﻌﺮﻳﻒ ﻣﻲﺷﻮد‬ (2)‫ع‬4i f(bool a,(1)‫ع‬4i x,(2)‫ع‬4i y) {

(2)‫ع‬4i xx = x; // convert if(a) return xx; else return y; }

:‫ﺑﻪ اﻳﻦ ﻣﺜﺎل ﺗﻮﺟﻪ ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; struct A { int a;

186

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ }; int main() { char ch = 'a'; int a = 5; cout<< ( 5 < 'a' ? a : ch

) << endl;

A X = {1}, Y = {5}; cout<< typeid(false ? X : Y).name(); _getch(); }

Output (BDS 2006): 5 A Output (Visual Studio 2005): 5 struct A

‫ را ﻣﻲﺷﻮد‬ch ‫ ﻫﻢ ﻧﻮع ﻧﻴﺴﺘﻨﺪ‬a ‫ و‬ch ‫ ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﺑﺎ اﻳﻦ ﻛﻪ‬.‫ ﭼﺎپ ﺷﺪه‬a ،‫ ﮔﺰارهاي درﺳﺖ اﺳﺖ‬5<'a' ‫ﭼﻮن‬ ‫ اﻳﻦ را در ﻣﺜﺎل ﺑﻌﺪي‬.‫ اﻳﺮادي )ﺑﺮاي ﻫﻢ ﻧﻮع ﻧﺒﻮدن( ﻧﻤﻲﮔﻴﺮد‬compiler ‫ ﻛﺮد و ﺑﻨﺎﺑﺮاﻳﻦ‬cast ،int n\ ‫ﺑﻪ‬ ‫ اﺳﺖ ﭼﺎپ‬A ‫ را ﻛﻪ ﻫﻤﺎن‬X ‫ دوم ﻫﻢ ﺑﺎﻳﺪ ﮔﻔﺖ ﻛﻪ اﺳﻢ ﻧﻮع ﻣﺘﻐﻴﺮ‬cout ‫ در ﻣﻮرد‬.‫ﺑﻪ ﻃﻮر واﺿﺢ ﺗﺮ ﺧﻮاﻫﻴﺪ دﻳﺪ‬ .‫ﻣﻲﻛﻨﺪ‬ #include <conio.h> #include <iostream> using namespace std; class A { public: int a; A(int pa) { cout<< "constructor\n"; } }; int main() { A a(1); int b = 2; cout<< typeid(a.a < b ? a : (A)b ).name(); _getch(); }

Output (BDS 2006):

187

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ constructor A Output (Visual C++ 2005): constructor class A

‫ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻪ ﺟﺎي‬Visual C++ 2005 ‫در‬ cout<< typeid(a.a < b ? a : (A)b ).name();

:‫ﺑﻨﻮﻳﺴﻴﻢ‬ cout<< typeid(a.a < b ? a : b ).name();

،‫ ﺗﺒﺪﻳﻞ ﺷﻮد‬A n\ ‫ ﻣﻲﺗﻮاﻧﺪ ﺑﻪ‬b ‫ ﻋﻠﺖ اﻳﻦ ﻛﻪ‬.‫ ﺷﻮد‬A cast ‫ ﻣﻲﺗﻮﻧﺪ ﺑﻪ‬b ‫و ﺧﺮوﺟﻲ ﺑﺮﻧﺎﻣﻪ ﻓﺮﻗﻲ ﻧﻤﻲﻛﻨﺪ ﭼﻮن‬ .‫ ﻣﻨﺎﺳﺐ اﺳﺖ‬constructor ‫وﺟﻮد‬ :‫ داﺷﺘﻪ ﺑﺎﺷﻨﺪ‬prototype ‫ﻫﺎ ﻫﻢ ﻣﻲﺗﻮاﻧﻨﺪ‬operator #include <conio.h> #include <iostream> using namespace std; class Bubble{}; Bubble& operator << (Bubble& emp, int b); int main() { Bubble bout; bout<< 2 << 3 << 4; _getch(); } Bubble& operator << (Bubble& emp, int b) { cout<< b << endl; return emp; }

Output: 2 3 4

188

www.pupuol.com


â€Ťď­˜ď­˜ďť? ﺎďş&#x; ﺊďş?ﺸﺎ ďť­ ﺪﺭﺳ‏ ‍ ﭟن‏.‍ ďť›Ů„ ďť›‏main() ‍ اﺳďş˜ďť”ďşŽŘŻŮ‡ ďť›ﺎدها ﺗﺎ ďş‘ďş˜ا ďş—ďťŒﺎďť’ عا ďş‘ ďş‘ďťŒﺪ از ﺗﺎﺑ‏prototype ‍دع ا ďş&#x;ﺎ از ‏ ‍ Ůˆ ا ﺎع عا ﺡد‏bout<< 2 << 3 ‍ ďťłďťœ اﺳďş– ďş—ا ďş‘ﺴ‏bout ‍ اع‏V bout<< 2 â€ŤďťŁďť˜ﺪاع‏ .‍ ďťƒع ادا داد‏ :‍ عا Ůˆاداع ďş‘ ﺧاﺪن Ůˆ ﺡďş˜ ďť›سﺎي ﺧدﺎن ďş‘ďťœ‏cin ‍ Ůˆâ€Źcout ‍ﺎ ďş—ا‏operator ‍ﺑﺎ اﺳďş˜ďť”ďşŽŘŻŮ‡ از‏ #include <conio.h> #include <iostream> using namespace std; class Int { public: int a; }; ostream& operator << (ostream&,Int& right_side) { cout<< right_side.a << endl; cout<< "printed\n"; return cout; } istream& operator >> (istream&,Int& right_side) { cin>> right_side.a; cout<< "got\n"; return cin; } int main() { Int a; cin>> a; cout<< a; _getch(); }

Output: 9 got 9 printed

‍ ďş‘ďť˜ŮŠ ﺴﺎﺋ ﺎďş‘ء ďş‘ ا ďş‘ﺎﺎ ﺡďş’ ďş‘‏.‍ داعد‏istream ‍ ؚ‏cin ‍ Ůˆâ€Źostream ‍ ؚ‏cout . *!6 .‍ﺑﺎﺎŮŠ ďť—ďş’ďťž اﺳﺖ‏

189

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ در ﻳﻚ‬method ‫ﻫﺎ را ﺑﻪ ﻋﻨﻮان ﺗﺎﺑﻊﻫﺎي ﻋﻤﻮﻣﻲ دﻳﺪﻳﻢ اﻣﺎ ﻣﻲﺷﻮد آنﻫﺎ را ﺑﻪ ﻋﻨﻮان‬operator ‫ﺗﺎ ﺑﻪ ﺣﺎل‬ ‫ وﻗﺘﻲ‬.‫ ﺗﻌﺮﻳﻒ ﻛﺮد‬method ‫ﻫﺎ را ﺗﻨﻬﺎ ﻣﻲﺷﻮد ﺑﻪ ﻋﻨﻮان‬operator ‫ در واﻗﻊ ﺑﻌﻀﻲ از‬.‫ﻛﻼس ﻫﻢ ﺑﻪ ﻛﺎر ﺑﺮد‬ ‫ ﺗﻌﺮﻳﻒ ﻣﻲﻛﻨﻴﻢ ﭘﺎراﻣﺘﺮ اول را ﺑﺎﻳﺪ ﺣﺬف ﻛﻨﻴﻢ ﭼﻮن ﺧﻮد ﺑﻪ ﺧﻮد‬method ‫ را ﺑﻪ ﻋﻨﻮان‬operator ‫ﻳﻚ‬ :‫* ﺑﻪ ﻋﻨﻮان آرﮔﻮﻣﺎن اول ﻗﺮار دارد‬this ‫ﻓﺮض ﺑﺮ آن اﺳﺖ ﻛﻪ‬ #include <conio.h> #include <iostream> using namespace std; class Int { public: int a; Int(int pa) { a = pa; } Int operator+(Int IntObject) { Int ret(a); ret.a += IntObject.a; return ret; } }; ostream& operator << (ostream&,Int& right_side) { cout<< right_side.a << endl; cout<< "printed\n\n"; return cout; } int main() { Int a(5); Int r = a + a; cout<< r; Int s = a + 2; cout<< s; _getch(); }

Output: 10 printed 7

190

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪printed‬‬

‫ﻧﻮﺷﺘﻪام ‪ a+a‬و ﻣﻘﺪارش را در ‪ r‬ﮔﺬاﺷﺘﻪام‪ r .‬ﻣﺠﻤﻮع دو ‪ a‬اﺳﺖ‪ .‬ﺑﺎ ‪ ،cout‬ﻛﻪ ﻗﺒﻼ ﺑﻪ آن ﻳﺎد دادهام ﭼﮕﻮﻧﻪ‬ ‫‪Int‬ﻫﺎ را ﭼﺎپ ﻛﻨﺪ‪ r ،‬را ﭼﺎپ ﻛﺮدم‪ .‬ﺷﺎﻳﺪ ﺑﮕﻮﻳﻴﺪ ﭼﺮا ﺧﻴﻠﻲ راﺣﺖ ﻧﻨﻮﺷﺘﻢ ;‪ .cout<<a+a‬ﻋﻠﺖ اﺷﻜﺎﻟﻲ‬ ‫اﺳﺖ ﻛﻪ در ‪compiler‬ﻫﺎي ‪ Borland‬وﺟﻮد دارد و از اﻳﻦ ﻃﺮز ﻧﻮﺷﺘﻦ اﻳﺮاد ﻣﻲﮔﻴﺮد‪Visual C++ 2005 .‬‬ ‫اﺷﻜﺎﻟﻲ ﻧﻤﻲﮔﻴﺮد‪ .‬اﻳﻦ ﻳﻚ ﺿﻌﻒ ﻃﺮاﺣﻲ در ‪ compiler‬ﻫﺎي ‪ Borland‬اﺳﺖ )و ﻣﻦ ﺑﺎ ﻧﺎاﻣﻴﺪي آرزو ﻣﻲﻛﻨﻢ‬ ‫ﻛﻪ ‪ Borland‬در ﻛﻨﺎر ﺳﻮد اﻗﺘﺼﺎدي ﺑﻪ ﻛﻴﻔﻴﺖ ‪compiler‬ﻫﺎي ﺧﻮد ﻫﻢ ﻓﻜﺮ ﻛﻨﺪ‬

‫( ‪ .‬ﻧﻜﺘﻪي دﻳﮕﺮ در‬

‫اﻳﻦ ﺑﺮﻧﺎﻣﻪ اﻳﻦ اﺳﺖ ﻛﻪ ﻧﻮﺷﺘﻪام ‪ a+2‬در ﺣﺎﻟﻲ ﻛﻪ ﻧﻮع ‪ int ،2‬اﺳﺖ ﻧﻪ ‪ .Int‬اﻳﻦ ﻫﻴﭻ اﻳﺮادي ﻧﺪارد ﭼﻮن‬ ‫‪constructor‬ي ﻫﺴﺖ ﻛﻪ ‪ int‬را ﺑﻪ ‪ Int cast‬ﻣﻲﻛﻨﺪ )ﺑﻪ ﻃﻮر ﭘﻨﻬﺎن(‪.‬‬ ‫ﻳﻚ ‪ operator‬را ﻣﻲﺷﻮد ﻛﺎﻣﻼ ﻣﺜﻞ ﻳﻚ ﺗﺎﺑﻊ ﻓﺮاﺧﻮاﻧﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Int‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int a‬‬ ‫)‪int operator- (int x‬‬ ‫{‬ ‫;‪return a - x‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;}‪Int a = {5‬‬ ‫;)‪cout<< a.operator- (3‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪2‬‬

‫اﻣﺎ در ﻣﻮرد ‪ ++‬ﺑﻪ ﻋﻨﻮان ‪ prefix‬و ‪:postfix‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Int‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int a‬‬ ‫)( ‪void operator++‬‬

‫‪191‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { cout<< "prefix\n"; } void operator ++(int) { cout<< "postfix\n"; } }; int main() { Int a = {5}; a.operator++ (); // prefix a.operator++ (2); // postfix _getch(); }

Output: prefix postfix

.‫ در اﻳﻦ ﺑﺮﻧﺎﻣﻪ را ﻣﻲﺷﻮد ﺑﺎ ﻫﺮ ﻋﺪد ﺻﺤﻴﺢ دﻳﮕﺮي ﻋﻮض ﻛﺮد ﭼﻮن از ﻣﻘﺪار آن اﺳﺘﻔﺎده ﻧﻤﻲﺷﻮد‬2 ‫ﻋﺪد‬ :‫ اﺳﺖ‬operator[] ‫ ﻳﻜﻲ از آنﻫﺎ‬.‫ ﺑﺎﺷﻨﺪ‬method ‫ﻫﺎ ﺑﺎﻳﺪ ﺣﺘﻤﺎ‬operator ‫ﮔﻔﺘﻢ ﺑﻌﻀﻲ از‬ #include <conio.h> #include <iostream> using namespace std; class Boy { public: int intelligence; void operator [](int a) { intelligence = a; } }; int main() { Boy Hub; Hub[136]; cout<< Hub.intelligence; _getch(); }

Output: 136

192

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ :‫ اﺳﺖ ﺑﺎ ﺗﻌﺪاد ﭘﺎراﻣﺘﺮ دﻟﺨﻮاه‬operator ‫)( ﻫﻢ ﻳﻚ‬ #include <conio.h> #include <iostream> using namespace std; class Boy { public: int intelligence; void operator ()(int a,int b) { intelligence = a + b; } }; int main() { Boy Hub; Hub(100,36); cout<< Hub.intelligence; _getch(); }

Output: 136

new

:‫ﺑﻪ ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻧﮕﺎه ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; int main() { int* a = new int (123); cout<< *a; _getch(); }

Output: 123

:‫ ﺣﺎل ﺑﻪ ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻧﮕﺎه ﻛﻨﻴﺪ‬.‫* ﻣﻘﺪار اوﻟﻴﻪ ﻣﻲدﻫﺪ‬a ‫( ﺑﻪ‬123) ‫ﭘﺲ‬ #include <conio.h> #include <iostream> using namespace std;

193

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫‪// output: 123‬‬ ‫‪// output: 1024‬‬

‫;)‪int (123‬‬ ‫;‪endl‬‬ ‫;)‪(a) int (1024‬‬ ‫;‪endl‬‬

‫‪// output: 10‬‬

‫)‪int main(void‬‬ ‫{‬ ‫‪int* a = new‬‬ ‫<< ‪cout<< *a‬‬ ‫‪int* b = new‬‬ ‫<< ‪cout<< *a‬‬ ‫;‪*a = 10‬‬ ‫;‪cout<< *b‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪123‬‬ ‫‪1024‬‬ ‫‪10‬‬

‫در اﻳﻦ ﺟﺎ ‪ a‬ﻣﺜﻞ ﻗﺒﻞ ﺑﻪ ﻃﻮر ﻋﺎدي ﺗﻌﺮﻳﻒ ﺷﺪه‪ *b .‬ﺣﺎﻓﻈﻪاي اﺳﺖ ﻛﻪ روي ‪ *a‬ﮔﺮﻓﺘﻪ ﺷﺪه اﺳﺖ و ﺑﺮاي ﻫﻤﻴﻦ‬ ‫‪ a‬و ‪ b‬ﻣﺴﺎوي ﻫﺴﺘﻨﺪ‪ .‬ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ وﻗﺘﻲ ﺑﻪ ‪ *a‬ﻣﻘﺪار ﻣﻲدﻫﻴﻢ ﻣﻘﺪار ‪ *b‬ﻫﻢ ﻋﻮض ﻣﻲﺷﻮد‪.‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪int* a = new(nothrow) int(8‬‬ ‫;‪cout<< *a‬‬ ‫;‪delete a‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪8‬‬ ‫در اﻳﻦ ﻣﺜﺎل ﺣﺎﻓﻈﻪاي ﺑﺮاي ﻳﻚ ‪ int‬اﺧﺘﺼﺎص داده ﺷﺪه و ﺑﺎ ‪ initialize ،8‬ﺷﺪه اﺳﺖ‪ .‬وﺟﻮد )‪(nothrow‬‬

‫ﻳﺎ )‪ (std::nothrow‬ﺑﺎﻋﺚ ﻣﻲﺷﻮد ﻛﻪ در ﺻﻮرت ﻋﺪم اﺧﺘﺼﺎص ﺣﺎﻓﻈﻪ ‪ raise ،exception‬ﻧﺸﻮد و ﻓﻘﻂ‬ ‫ﺻﻔﺮ ﺑﺮﮔﺮداﻧﺪه ﺷﻮد‪.‬‬ ‫‪ new‬را ﻣﻲﺗﻮاﻧﻴﻢ ‪ overload‬ﻛﻨﻴﻢ )در ﻛﻞ از ﻧﻈﺮ اﺻﻄﻼﺣﻲ ﻳﻚ ﻋﻤﻠﮕﺮ )‪ (operator‬را ﺗﻌﺮﻳﻒ ﻧﻤﻲﻛﻨﻴﻢ‬ ‫ﺑﻠﻜﻪ ‪ overload‬ﻣﻲﻛﻨﻴﻢ(‪.‬‬

‫ﺣﺎل ﺑﻪ ﻣﺜﺎﻟﻲ از ‪ overload‬ﻛﺮدن ‪ operator new‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫‪194‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <conio.h> #include <iostream> using namespace std; class Int { public: int a; int b; void* operator new(unsigned x) { cout<< "new operator called\n"; return &x; } }; int main() { new Int; // called new Int [5]; // not called cout<< typeid(*new Int).name(); // not called _getch(); }

Output (BDS 2006): new operator called Int Output (Visual C++ 2005): new operator called class Int

:‫ﭼﻨﺪ ﻧﻜﺘﻪ ﻫﺴﺖ‬ . ‫ ﺑﺎﺷﺪ‬void* ‫( ﺧﺮوﺟﻲ ﺑﺎﻳﺪ‬1 ‫ي ﻛﻪ در ﻳﻜﻲ از‬typedef ‫ )ﻳﺎ ﺑﺎ‬unsigned ‫ ﺑﺎﻳﺪ ﻧﻮع‬operator new ‫( اوﻟﻴﻦ ﭘﺎراﻣﺘﺮ‬2 . ‫( داﺷﺘﻪ ﺑﺎﺷﺪ‬size_t ‫ﻫﺎ ﻫﺴﺖ ﻧﻮع‬header file ‫ ﺷﺪه اﺳﺖ و ﺑﺮاي ﻫﻤﻴﻦ اﺳﺘﻔﺎده از ﻧﻮع ﺑﺮداري )ﻳﻌﻨﻲ‬new overload ‫( در اﻳﻦ ﻣﺜﺎل ﻓﻘﻂ ﻧﻮع اﺳﻜﺎﻟﺮ‬3 .‫ ﻣﺎ ﻧﺸﺪه اﺳﺖ‬operator ‫ در اﻳﻦ ﻣﺜﺎل ﺑﺎﻋﺚ ﻓﺮاﺧﻮاﻧﻲ‬new (‫آراﻳﻪاي‬ .‫ اﺳﺖ ﻓﺮاﺧﻮاﻧﺪه ﻧﻤﻲﺷﻮد‬typeid ‫ آرﮔﻮﻣﺎن‬new ‫( وﻗﺘﻲ‬4 .‫ دارد‬Int* ‫( ﺧﺮوﺟﻲ در ﻫﺮ ﺣﺎل ﻧﻮع‬5

195

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ .‫ را ﻧﺪارﻳﻢ‬this ‫ و‬b ‫ و‬a ‫ ﺣﻖ اﺳﺘﻔﺎده از‬operator new ‫( در ﺗﻌﺮﻳﻒ‬6 :‫ﻣﺜﺎل زﻳﺮ ﻛﺎﻣﻞ ﺗﺮ اﺳﺖ‬ #include <conio.h> #include <iostream> using namespace std; class Int { public: int a; int b; Int(){}; // default constructor; Int(const Int&) // copy constrcutor { cout<< "copy constructor\n"; } void* operator new(unsigned x,int y, double z) { cout<< "new operator called\n"; cout<< "y: " << y << endl; cout<< "z: " << z << endl; cout<< "x: " << x << endl; return &Int(); } }; int main() { Int t; Int* u = new(3,2.3) Int (t); getch(); }

Output: new operator called y: 3 z: 2.3 x: 8 copy constructor

-‫ ﭘﺎراﻣﺘﺮ اول را ﻧﺎدﻳﺪه ﻣﻲ‬،‫ ﻣﻮﻗﻊ ﻓﺮاﺧﻮاﻧﻲ‬.‫ اﺿﺎﻓﻪ ﺷﺪه‬operator new ‫در اﻳﻦ ﻣﺜﺎل ﭘﺎراﻣﺘﺮﻫﺎي دﻳﮕﺮي ﻫﻢ ﺑﻪ‬ ‫ در ﭘﺮاﻧﺘﺰ ﻗﺮار‬Int ‫ ﻛﻪ ﺑﻌﺪ از‬t ‫ ﻣﺘﻐﻴﺮ‬.‫ ﻟﻴﺴﺖ ﻣﻲﻛﻨﻴﻢ‬new ‫ﮔﻴﺮﻳﻢ و ﻣﻘﺪارﻫﺎي ﭘﺎراﻣﺘﺮﻫﺎي ﺑﻌﺪي را ﺑﻌﺪ از‬ ‫ ﭘﺎراﻣﺘﺮ اول ﻳﻌﻨﻲ‬.‫ اﺳﺘﻔﺎده ﻣﻲﺷﻮد‬copy constructor ‫ ﺑﺮاي دادن اﻳﻦ ﻣﻘﺪار اوﻟﻴﻪ از‬.‫ ﻣﻘﺪار اوﻟﻴﻪ اﺳﺖ‬،‫ﮔﺮﻓﺘﻪ‬ ‫ را در ﺑﺮ دارد و ﺑﺪون اﻳﻦ ﻛﻪ ﻣﺎ ﺑﻪ آن ﻣﻘﺪار ﺑﺪﻫﻴﻢ ﺧﻮد ﺑﻪ‬sizeof(Int) ‫ ﺗﻌﺪاد ﺑﺎﻳﺖﻫﺎي ﻣﻮرد ﻧﻴﺎز ﻳﻌﻨﻲ‬x

196

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ اﺳﺖ ﻳﺎ از‬heap ‫ اﺧﺘﺼﺎص داده ﻣﻲﺷﻮد از‬new ‫ ﺑﻪ ﻧﻈﺮ ﺷﻤﺎ ﺣﺎﻓﻈﻪاي ﻛﻪ در اﻳﻦ ﺟﺎ ﺑﺎ‬.‫ﺧﻮد ﻣﻘﺪار ﻣﻲﮔﻴﺮد‬ ‫؟‬stack new overload ‫ﻫﻤﻴﻦ ﺑﺮﻧﺎﻣﻪ را ﺑﺎ ﺑﺎ ﺗﻐﻴﻴﺮات ﺑﺴﻴﺎر ﺟﺰﺋﻲ ﻣﻲﺷﻮد ﺑﻪ ﺻﻮرت زﻳﺮ ﺗﻐﻴﻴﺮ داد ﻛﻪ ﺷﻜﻞ ﺑﺮداري‬

:(‫ﻣﻲﺷﻮد )و دﻳﮕﺮ ﻣﻘﺪار دادن اوﻟﻴﻪ ﺑﻪ ﺷﻜﻞ ﻗﺒﻞ ﻣﻌﻨﻲ ﻧﺪارد‬ #include <conio.h> #include <iostream> using namespace std; class Int { public: int a; int b; Int(){}; // default constructor; Int(const Int&) // copy constrcutor { cout<< "copy constructor\n"; } void* operator new[] (unsigned x,int y, double z) { cout<< "new operator called\n"; cout<< "y: " << y << endl; cout<< "z: " << z << endl; cout<< "x: " << x << endl; return &Int(); } }; int main() { Int* u = new(3,2.3) Int [4]; getch(); }

Output: new operator called y: 3 z: 2.3 x: 32

‫ دارد ﻛﻪ‬32 ‫ در اﻳﻦ ﺟﺎ ﻣﻘﺪار‬x .‫ ﺧﻮاﻧﺪه ﻧﺸﺪه‬copy constructor ‫ﭼﻮن اﻳﻦ ﺟﺎ ﻣﻘﺪار اوﻟﻴﻪاي در ﻛﺎر ﻧﻴﺴﺖ‬ .‫ اﺳﺖ‬Int ‫ﺑﺮاﺑﺮ ﺑﺎ ﺣﺠﻢ ﭼﻬﺎر‬ ‫ را ﻣﻲﺷﻮد ﺗﻨﻬﺎ ﺑﻪ ﻳﻜﻲ از ﺷﻜﻞﻫﺎي‬operator delete[] ‫ ﻳﺎ‬operator delete ‫در ﻳﻚ ﻛﻼس‬ :‫زﻳﺮ ﺗﻌﺮﻳﻒ ﻛﺮد‬

197

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ void void void void

operator operator operator operator

delete(void* a) {...} delete(void* a,unsigned x) {...} delete[](void* a) {...} delete[](void* a,unsigned x) {...}

‫ ﻣﻨﺎﺳﺐ )ﺑﺮ ﺣﺴﺐ‬new constructor ،‫در ﻫﺮ ﺣﺎل ﭼﻪ ﺧﻮدﻣﺎن ﺗﻌﺮﻳﻒ ﻛﺮده ﺑﺎﺷﻴﻢ ﭼﻪ ﺗﻌﺮﻳﻒ ﻧﻜﺮده ﺑﺎﺷﻴﻢ‬ ‫ را ﺑﺮاي ﻳﻚ ﻛﻼس ﻣﺜﻞ‬new ‫ اﮔﺮ ﻋﻤﻠﮕﺮ‬.‫ را ﻓﺮا ﻣﻲﺧﻮاﻧﺪ‬destructor ،delete ‫ﺗﻌﺪاد و ﻧﻮع ﭘﺎراﻣﺘﺮﻫﺎ( و‬ ‫ ﻫﻤﻴﺸﻪ‬،‫ در ﻧﻈﺮ ﺑﮕﻴﺮﻳﻢ‬Cat ‫ ﺗﺨﺼﻴﺺ داده ﻣﻲﺷﻮد؛‬Cat ‫اول ﺣﺎﻓﻈﻪاي ﺑﺮاي ﻳﻚ ﺷﻲء ﺟﺪﻳﺪ ﺑﺎ ﻧﻮع‬ ‫ ﺗﺒﺪﻳﻞ ﻣﻲﺷﻮد و ﺑﻪ ﺷﻜﻠﻲ ﻧﺎﺷﻴﺎﻧﻪ در‬Cat ‫ ﻣﻲﺷﻮد ﺑﻪ‬operator new return ‫ﺑﻌﺪ آن ﭼﻴﺰي ﻛﻪ در ﺗﻌﺮﻳﻒ‬ ‫ﺷﻲء ﺟﺪﻳﺪ ﻛﭙﻲ ﻣﻲﺷﻮد؛‬ .‫ ﻓﺮاﺧﻮاﻧﺪه ﻣﻲﺷﻮد‬constructor ‫در ﻧﻬﺎﻳﺖ‬ :‫ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; int Globe = 1111; class Cat { public: int age; Cat() { cout<< "Cat constructor\n"; age++; } void* operator new(unsigned) { cout<< "operator new\n"; return &Globe; } }; int main() { Cat* Tom_Home = new Cat; cout<< *( (int*) Tom_Home ) << endl; cout<< Tom_Home -> age << endl; getch(); }

// output: 1112 // output: 1112

Output: operator new Cat constructor 1112 1112

198

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ﻧﻮﺷﺘﻪام اﺟﺮا ﻣﻲﺷﻮد ﺑﻌﺪ‬operator new ‫ اول دﺳﺘﻮراﺗﻲ ﻛﻪ ﺧﻮد ﻣﻦ ﺑﺮاي ﺗﻌﺮﻳﻒ‬new Cat ‫ﺑﺎ ﻧﻮﺷﺘﻦ‬ 1111 ‫ ﻣﻲﺷﻮد )ﻣﻘﺪار‬copy ‫ ﺷﺪه در آن ﺑﻪ ﻃﻮر ﻧﺎﺷﻴﺎﻧﻪاي‬return ‫ ﺑﻪ وﺟﻮد ﻣﻲآﻳﺪ و ﻣﻘﺪار‬Cat ‫ﺷﻴﺌﻲ از ﻧﻮع‬

-‫ ﻳﻜﻲ زﻳﺎد ﻣﻲ‬age ‫ ﻓﺮاﺧﻮاﻧﺪه ﻣﻲﺷﻮد )ﻣﻘﺪار‬default constructor ‫ ﻗﺮار ﻣﻲﮔﻴﺮد( و در ﻧﻬﺎﻳﺖ‬age ‫در‬ ‫ دارد‬Cat* ‫ ﻛﻪ ﻧﻮع‬Tom_Home ‫ ﻳﻌﻨﻲ اول‬.‫( (* ﭼﺎپ ﺷﺪه‬int*) Tom_Home ) ‫ اول‬cout ‫ ﺑﺎ‬.(‫ﺷﻮد‬ ‫ اﻳﻦ ﻣﻘﺪار ﻫﻤﺎن ﻣﻘﺪاري اﺳﺖ ﻛﻪ ﺑﺎ ﭼﻬﺎر‬.‫ ﺷﺪه و ﺑﻌﺪ ﻣﻘﺪاري ﻛﻪ ﺑﻪ آن اﺷﺎره ﻣﻲﺷﻮد ﭼﺎپ ﺷﺪه‬int* cast ‫ﺑﻪ‬ .‫ ﭼﺎپ ﺷﺪه‬age ‫ در آﺧﺮ‬.‫* درﺳﺖ ﻣﻲﺷﻮد‬Tom_Home ‫ﺑﺎﻳﺖ اول‬ :‫ﻣﺜﺎل زﻳﺮ ﻛﺎﻣﻞ ﺗﺮ اﺳﺖ‬ #include <conio.h> #include <iostream> using namespace std; int Globe = 1111; class Cat { public: int age; Cat(int a) { cout<< "Cat constructor\n"; age = a; } ~Cat() { cout<< "Cat destructor\n"; age = -235; } void* operator new(unsigned) { cout<< "operator new\n"; return &Globe; } void operator delete(void*) { cout<< "operator delete\n"; } }; int main() { Cat* Tom_Home = new Cat(235); // operator new // Cat constructor cout<< Tom_Home -> age << endl; // 235 delete Tom_Home; // Cat destructor // operator delete cout<< Tom_Home -> age << endl; // -235 getch(); }

199

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ Output: operator new Cat constructor 235 Cat destructor operator delete -235

‫ ﺑﻌﺪ از‬operator delete ‫ ﺧﻮاﻧﺪه ﻣﻲﺷﻮد وﻟﻲ‬constructor ‫ ﻗﺒﻞ از‬operator new operator delete ‫ و‬operator new ‫ اﮔﺮ ﺗﻌﺮﻳﻒﻫﺎي ﺧﻮدﻣﺎن‬.‫ ﻓﺮاﺧﻮاﻧﺪه ﻣﻲﺷﻮد‬destructor

:‫ ﻓﺮاﺧﻮاﻧﺪه ﻣﻲﺷﻮﻧﺪ‬destructor ‫ و‬constructor ‫را ﺣﺬف ﻛﻨﻴﻢ ﺑﺎز ﻫﻢ‬ #include <conio.h> #include <iostream> using namespace std; int Globe = 1111; class Cat { public: int age; Cat(int a) { cout<< "Cat constructor\n"; age = a; } ~Cat() { cout<< "Cat destructor\n"; age = -235; } }; int main() { Cat* Tom_Home = new Cat(235); cout<< Tom_Home -> age << endl; delete Tom_Home; cout<< Tom_Home -> age << endl; getch(); }

Output: Cat constructor 235 Cat destructor 9371816

200

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪conversion operator‬‬

‫دﻳﺪﻳﻢ ﻛﻪ اﮔﺮ ﻛﻼس ‪ Cat‬ﻳﻚ ‪ constructor‬ﺑﻪ ﺷﻜﻞ )‪ Cat(int‬داﺷﺘﻪ ﺑﺎﺷﺪ‪ ،‬ﻫﺮ ‪ int‬را ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻪ‬ ‫‪ Cat cast‬ﻛﻨﻴﻢ‪ .‬آﻳﺎ ﻋﻜﺲ اﻳﻦ ﻫﻢ ﻣﻤﻜﻦ اﺳﺖ؟ آﻳﺎ ﻣﻲﺷﻮد ﻳﻚ ‪ Cat‬را ﺑﻪ ‪ int cast‬ﻛﺮد؟ اﻳﻦ ﻛﺎر وﻗﺘﻲ‬ ‫اﻣﻜﺎن ﭘﺬﻳﺮ اﺳﺖ ﻛﻪ ‪ conversion operator‬ﻣﻨﺎﺳﺐ در ﻛﻼس ‪ Cat‬ﺗﻌﺮﻳﻒ ﺷﺪه ﺑﺎﺷﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Int‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int a‬‬ ‫)( ‪operator int‬‬ ‫{‬ ‫;"‪cout<< "conversion operator\n‬‬ ‫;‪return a‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;}‪Int A = {5‬‬ ‫;‪int x = A‬‬ ‫;‪cout<< x‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪conversion operator‬‬ ‫‪5‬‬

‫‪ A‬ﺑﺎ ‪ conversion operator‬ﺑﻪ ‪ int‬ﺗﺒﺪﻳﻞ ﺷﺪه اﺳﺖ‪ conversion operator .‬ﭘﺎراﻣﺘﺮ و ﺧﺮوﺟﻲ ﻧﺪارد‬ ‫وﻟﻲ در آن از ‪ return‬اﺳﺘﻔﺎده ﻣﻲﺷﻮد ﺗﺎ ﻧﻮع ﻣﻮرد ﻧﻈﺮ ‪ return‬ﺷﻮد‪.‬‬

‫= ‪operator‬‬

‫درﺑﺎرهي = ‪ operator‬ﭼﻴﺰي اﺿﺎﻓﻪ ﺑﺮ آن ﭼﻪ در ﻣﻮرد ‪ operator‬ﮔﻔﺘﻢ ﻧﺪارم‪ .‬ﻣﻤﻜﻦ اﺳﺖ ﻗﺒﻼ ﺑﻪ اﻳﻦ ﻓﻜﺮ‬ ‫ﻛﺮده ﺑﺎﺷﻴﺪ ﻛﻪ اﻳﻦ ‪ operator‬و ‪ copy constructor‬ﺑﻪ ﻫﻢ ﻣﺮﺑﻮط ﻫﺴﺘﻨﺪ‪ .‬اﻣﺎ در ﺣﻘﻴﻘﺖ اﻳﻦ ﻃﻮر ﻧﻴﺴﺖ‪.‬‬ ‫اﮔﺮ در ﻳﻚ ﻛﻼس = ‪ operator‬ﺗﻌﺮﻳﻒ ﻧﺸﻮد ‪ compiler‬ﻳﻜﻲ ﺑﻪ ﺻﻮرت ‪ default‬در ﻧﻈﺮ ﻣﻲﮔﻴﺮد ﻛﻪ‬ ‫ﻣﺘﻐﻴﺮﻫﺎ را ﻳﻜﻲ ﻳﻜﻲ ‪ assign‬ﻣﻲﻛﻨﺪ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬

‫‪201‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat(){} // default constructor Cat(const Cat&) // copy constructor { cout<< "Cat copy constructor\n"; } void operator = (const Cat&) { cout<< "Cat assigns\n"; } }; class House { Cat Tom; }; void f(House Mine){} // a function int main() { House Mine,Yours; Mine = Yours; f(Yours); getch(); }

Output: Cat assigns Cat copy constructor

،‫ ﻣﻲﺷﻮد‬Yours copy ‫ ﻣﻲﺷﻮد و وﻗﺘﻲ‬assign ‫ ﻫﻢ‬Yours.Tom ،‫ ﻣﻲﺷﻮد‬Yours assign ‫ﻣﻲﺑﻴﻨﻴﺪ وﻗﺘﻲ‬ operator = ‫ و‬House copy constructor ‫ ﺣﺎﻻ اﮔﺮ ﺑﻪ ﻛﻼس‬.‫ ﻣﻲﺷﻮد‬copy ‫ ﻫﻢ‬Yours.Tom

:‫ ﻓﺮاﺧﻮاﻧﺪه ﻧﻤﻲﺷﻮد‬Cat ‫اﺿﺎﻓﻪ ﻛﻨﻴﻢ دﻳﮕﺮ ﭼﻴﺰي از‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat(){} // default constructor Cat(const Cat&) //copy constructor { cout<< "Cat copy constructor\n"; }

202

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ void operator = (const Cat&) { cout<< "Cat assigns\n"; } }; class House { public: Cat Tom; House(){} // default constructor House(const House&) //copy constructor { cout<< "House copy constructor\n"; } void operator = (const House&) { cout<< "House assigns\n"; } }; void f(House Mine){} // a function int main() { House Mine,Yours; Mine = Yours; f(Mine); getch(); }

Output: House assigns House copy constructor

‫ ﻛﺮدن )ﻳﻌﻨﻲ ﻣﺴﺎوي‬assign ‫ ﻛﺮدن )ﻳﻌﻨﻲ ﻣﻘﺪار اوﻟﻴﻪ دادن( ﺑﺎ‬initialize ‫ﺷﺎﻳﺪ ﺗﺎ ﺑﻪ ﺣﺎل ﺑﺎ ﺧﻮد ﻣﻲﮔﻔﺘﻴﺪ‬ copy ‫ ﻛﺮدن‬initialize ‫ وﻟﻲ‬.‫ را ﻓﺮا ﻣﻲﺧﻮاﻧﺪ‬operator = ‫ ﻛﺮدن‬assign .‫ﻗﺮار دادن( ﻓﺮﻗﻲ ﻧﺪارد‬ :‫ را ﻓﺮا ﻣﻲﺧﻮاﻧﺪ‬constructor #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat(){} // default constructor Cat(const Cat&) // copy constructor { cout<< "Cat copy constructor\n"; } void operator = (const Cat&) { cout<< "Cat assigns\n"; }

203

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ }; int main() { Cat Yours; Cat Mine = Yours; getch(); }

Output: Cat copy constructor

private constructor

.‫ ﺗﻌﺮﻳﻒ ﺷﻮﻧﺪ ﻧﻤﻲﺗﻮاﻧﻴﻢ ﻣﺘﻐﻴﺮي از ﻧﻮع آن ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‬private ‫ﻫﺎي ﻳﻚ ﻛﻼس‬constructor ‫اﮔﺮ ﻫﻤﻪي‬ :‫ﻣﺜﻼ ﺑﺮﻧﺎﻣﻪي زﻳﺮ اﺟﺮا ﻧﻤﻲﺷﻮد‬ #include <conio.h> #include <iostream> using namespace std; class Cat { private: Cat(){} // default constructor }; int main() { Cat Tom; getch(); }

Output: error

:‫اﻣﺎ ﺑﺎ اﻳﻦ ﻛﻼس ﻣﻲﺷﻮد ﻧﻮﺷﺖ‬ Cat* Tom;

:‫وﻟﻲ ﻧﻤﻲﺷﻮد ﻧﻮﺷﺖ‬ Cat* Tom = new Tom;

‫ ﺑﺎﻳﺪ ﻓﺮاﺧﻮاﻧﺪه‬constructor ‫ را ﺧﻮد ﻣﺎ ﺗﻌﺮﻳﻒ ﻛﺮده ﺑﺎﺷﻴﻢ )زﻳﺮا ﻣﻲداﻧﻴﺪ ﻛﻪ در ﻧﻬﺎﻳﺖ‬new ‫ﺣﺘﻲ اﮔﺮ‬ :‫ اﺳﺖ‬private ،constructor ‫ ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻫﻢ اﺟﺮا ﻧﻤﻲﺷﻮد زﻳﺮا‬.(‫ﺑﺸﻮد‬ #include <conio.h> #include <iostream>

204

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ using namespace std; class Cat { Cat(){} }; class House { public: Cat a; }; int main() { House MyHouse; getch(); }

Output: error

compiler ‫ ﻧﻤﻲﺗﻮاﻧﺪ ﻣﺘﻐﻴﺮش را ﺑﺴﺎزد و ﺑﺮاي ﻫﻤﻴﻦ‬House ،‫ اﺳﺖ‬Cat private ِ constructor ‫ﭼﻮن‬ .‫ﻧﻤﻲﺗﻮاﻧﺪ ﺑﺮﻧﺎﻣﻪ را اﺟﺮا ﻛﻨﺪ‬ ‫ ﺑﻪ ﺷﻜﻞ‬constructor ‫ ﻳﻚ‬compiler ‫ي ﺑﺮاي ﻛﻼس ﻧﻨﻮﻳﺴﻴﻢ ﺧﻮد‬constructor ‫اﮔﺮ ﻫﻴﭻ‬ Cat(){}

‫ وﻟﻲ اﮔﺮ ﻣﺎ ﻫﺮ ﺟﻮر‬.‫ ﻣﻲﮔﻮﻳﻨﺪ‬default constructor ‫ اﺳﺖ و ﺑﻪ آن‬public ‫در ﻧﻈﺮ ﻣﻲﮔﻴﺮد ﻛﻪ‬ ‫ در ﻧﻈﺮ ﻧﻤﻲﮔﻴﺮد و‬compiler ‫ي را ﺧﻮد‬constructor ‫ دﻳﮕﺮ ﭼﻨﻴﻦ‬،‫ي ﺑﻪ ﻛﻼس اﺿﺎﻓﻪ ﻛﻨﻴﻢ‬constructor ‫ﻫﺎي ﺧﻮد‬method ‫ ﻣﻲﺗﻮاﻧﻨﺪ در‬private ‫ﻫﺎي‬constructor .‫اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﺧﻮدﻣﺎن ﺑﺎﻳﺪ آن را اﺿﺎﻓﻪ ﻛﻨﻴﻢ‬ :‫ﻛﻼس اﺳﺘﻔﺎده ﺑﺸﻮﻧﺪ‬ #include <conio.h> #include <iostream> using namespace std; class Cat { Cat(int a) { age = a; } public: Cat() { *this = Cat(123); } int age; };

205

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ int main() { Cat Tom; cout<< Tom.age; getch(); }

Output: 123

‫ در ﺿﻤﻦ از‬.‫ را ﻓﺮا ﻣﻲﺧﻮاﻧﺪ‬private constructor ‫ ﻳﻚ‬default constructor ‫در اﻳﻦ ﻣﺜﺎل‬ .‫ ﺑﺮاي ﻛﻼس در ﻧﻈﺮ ﻣﻲﮔﻴﺮد اﺳﺘﻔﺎده ﻣﻲﻛﻨﺪ‬default ‫ ﺑﻪ ﻃﻮر‬compiler ‫ ﻛﻪ‬operator=

‫ﻫﺎ دﺳﺘﺮﺳﻲ ﻧﺪارﻧﺪ ﻧﻤﻲﺗﻮاﻧﻨﺪ آن را ﻓﺮا‬private ‫ ﺗﺎﺑﻊﻫﺎﻳﻲ ﻛﻪ ﺑﻪ‬،‫ ﺗﻌﺮﻳﻒ ﺷﻮد‬private ،destructor ‫اﮔﺮ‬ :‫ ﻣﺜﻼ ﺑﺮﻧﺎﻣﻪي زﻳﺮ اﺟﺮا ﻧﻤﻲﺷﻮد‬.‫ﺑﺨﻮاﻧﻨﺪ‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat() { cout<< "copy constructor\n"; } private: ~Cat() { cout<< "destructor"; } }; int main() { Cat Tom; _getch(); }

Output: Error

‫ ﻓﺮا ﺧﻮاﻧﺪه ﺑﺸﻮد در ﺣﺎﻟﻲ ﻛﻪ‬destructor ‫ ﺑﺎﻳﺪ‬main() ‫ﻋﻠﺖ اﺟﺮا ﻧﺸﺪن اﻳﻦ ﻛﻪ ﻣﻮﻗﻊ ﭘﺎﻳﺎن اﺟﺮاي‬ ‫ وﻟﻲ اﮔﺮ ﺑﻪ ﺟﺎي‬.‫ ﺣﻖ اﺳﺘﻔﺎده از آن را ﻧﺪارد‬main() ‫ اﺳﺖ و‬private ،destructor Cat Tom;

206

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ :‫ﺑﻨﻮﻳﺴﻴﻢ‬ Cat* pTom = new Cat;

:‫ﺑﺮﻧﺎﻣﻪ اﺟﺮا ﻣﻲﺷﻮد‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: Cat() { cout<< "copy constructor\n"; } private: ~Cat() { cout<< "destructor"; } }; int main() { Cat* pTom = new Cat; // delete pTom; // error _getch(); }

Output: copy constructor

‫ه‬member ‫ ار او دادن‬

‫ ﺷﻮﻧﺪ اﻣﺎ راه دﻳﮕﺮي‬initialize ‫ﮔﻔﺘﻢ ﻛﻪ ﻣﺘﻐﻴﺮﻫﺎﻳﻲ ﻛﻪ در ﻳﻚ ﻛﻼس ﺗﻌﺮﻳﻒ ﻣﻲﺷﻮﻧﺪ ﻧﺒﺎﻳﺪ ﺑﻪ ﺷﻜﻞ ﻋﺎدي‬ :‫ اﻳﻦ راه را در ﻣﺜﺎل زﻳﺮ ﻣﻲﺑﻴﻨﻴﺪ‬.‫ ﻛﺮدن آنﻫﺎ ﻫﺴﺖ‬initialize ‫ﺑﺮاي‬ #include <conio.h> #include <iostream> using namespace std; class Cat {

207

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ public: Cat(int a): age(1234) { cout<< "Cat constructor\n"; } int age; }; int main() { Cat Tom(8); cout<< Tom.age; getch(); }

Output: Cat constructor 1234

:‫ ﻧﻮﺷﺘﻪام‬،constructor ‫در اﻳﻦ ﺟﺎ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺑﻌﺪ از ﭘﺮاﻧﺘﺰ ﭘﺎﻳﺎﻧﻲ ِ ﻟﻴﺴﺖ ِ ﭘﺎراﻣﺘﺮﻫﺎي‬ : age(1234)

.‫ ﺷﻮد‬1234 initialize ‫ ﺑﺎ‬age ‫ ﻳﻌﻨﻲ ﻣﺘﻐﻴﺮ‬:age(1234) .‫ رﻓﺘﻪام‬constructor ‫و ﺑﻌﺪ ﺑﻪ ﺳﺮاغ ﺗﻌﺮﻳﻒ‬ ‫ اﻣﺎ اﻳﻦ ﻛﺎر‬age=1234 ‫ ﻗﺮار دﻫﻴﻢ‬constructor ‫ﺷﺎﻳﺪ ﺑﮕﻮﻳﻴﺪ ﻣﻲﺗﻮاﻧﺴﺘﻴﻢ ﺑﻪ ﺟﺎي اﻳﻦ ﻛﺎر در ﺗﻌﺮﻳﻒ‬ ‫ ﺑﻪ‬.‫ ﺷﻮﻧﺪ‬initialize ‫ﻫﺎ و ﺛﺎﺑﺖﻫﺎ ﺑﺎﻳﺪ ﺣﺘﻤﺎ‬reference .‫ اﺳﺖ‬assignment ‫ ﻧﻴﺴﺖ ﺑﻠﻜﻪ‬initialization ‫ ﺧﻴﻠﻲ‬assignment ‫ ﺑﺎ‬initialization ‫ﻋﻼوه در ﻣﻮرد ﻣﺘﻐﻴﺮﻫﺎﻳﻲ ﻛﻪ ﻧﻮﻋـﺸﺎن ﻳﻚ ﻛﻼس اﺳﺖ ﻣﻤﻜﻦ اﺳﺖ‬ :‫ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‬.‫ﻓﺮق ﻛﻨﺪ‬ #include <conio.h> #include <iostream> using namespace std; class mustache { public: mustache(int) { cout<< "int constructor\n"; } mustache(const mustache&) { cout<< "mustache copy constructor\n"; } void operator= (const mustache&) { cout<< "operator= \n"; } }; class Cat

208

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { const int Const; int& Ref; mustache itsMustache; public: Cat(int& a): age(1234), Const(456), Ref(a), itsMustache(789) /*where the action is*/ { cout<< "Cat constructor\n"; } int age; }; int main() { int a = 5555; Cat Tom(a); cout<< Tom.age; getch(); }

Output: int constructor Cat constructor 1234

‫ ﭼﻨﺪ‬.‫ﻫﺎﻳﻲ ﻛﻪ اﺣﺘﻤﺎل ﻓﺮاﺧﻮﻧﻲ آنﻫﺎ ﻫﺴﺖ ﺗﻌﺮﻳﻒ ﺷﺪه‬constructor ‫ﻫﺎ و‬method ‫ ﺑﺎ‬mustache ‫ﻛﻼس‬ ‫ دوم اﻳﻦ ﻛﻪ در‬.‫« ﺟﺪا ﻣﻲﻛﻨﻴﻢ‬,» ‫ آنﻫﺎ را ﺑﺎ‬،‫ﻧﻜﺘﻪ ﻣﻬﻢ ﻫﺴﺖ اول اﻳﻦ ﻛﻪ ﻣﻮﻗﻊ ﻣﻘﺪار اوﻟﻴﻪ دادن ﺑﻪ ﭼﻨﺪ ﻣﺘﻐﻴﺮ‬ Cat ‫ اﺳﺘﻔﺎده ﻛﺮد و ﺳﻮم اﻳﻦ ﻛﻪ ﻧﻤﻲﺷﻮد در ﻛﻼس‬constructor ‫ﻣﻘﺪار اوﻟﻴﻪ دادن ﻣﻲﺷﻮد از ﭘﺎراﻣﺘﺮﻫﺎي‬

‫ﺑﻪ ﺟﺎي‬ mustache itsMustache;

:‫ﻧﻮﺷﺖ‬ mustache itsMustache(789);

‫ اﺻﻼ‬mustache ‫ ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﻛﻼس‬.‫و ﺑﺎﻳﺪ ﺣﺘﻤﺎ ﭘﺎراﻣﺘﺮ آن را ﺑﻪ ﺷﻜﻠﻲ ﻛﻪ در ﻣﺜﺎل ﻫﺴﺖ ﺑﻪ آن داد‬ .‫ ﺑﺪون ﭘﺎراﻣﺘﺮ( ﻧﺪارد‬constructor ‫ )ﻳﻌﻨﻲ‬default constructor

209

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪method‬ه ‪inline‬‬

‫ﻣﻲداﻧﻴﺪ ﻛﻪ ﺗﺎﺑﻊﻫﺎي ﻣﻌﻤﻮﻟﻲ ﻣﻲﺗﻮاﻧﻨﺪ ‪ prototype‬داﺷﺘﻪ ﺑﺎﺷﻨﺪ اﻣﺎ آﻳﺎ ‪method‬ﻫﺎ ﻫﻢ ﻣﻲﺗﻮاﻧﻨﺪ ‪prototype‬‬ ‫داﺷﺘﻪ ﺑﺎﺷﻨﺪ؟ ﺑﻠﻪ وﻟﻲ‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫;)(‪void f‬‬ ‫)(‪void f‬‬ ‫{‬ ‫}‬ ‫;}‬

‫‪ error‬دارد‪ .‬ﺑﻪ ﺟﺎي آن ﺑﺎﻳﺪ ﻧﻮﺷﺖ‪:‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫;)(‪void f‬‬ ‫;}‬ ‫)(‪void A::f‬‬ ‫{‬ ‫}‬

‫ﻳﻌﻨﻲ ﺑﺎﻳﺪ ﺗﻌﺮﻳﻒ )(‪ f‬ﺑﻪ ﺧﺎرج از ﻓﻀﺎي ﻛﻼس ﻣﻨﺘﻘﻞ ﺷﻮد‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﻣﻌﻠﻮم ﺷﻮد اﻳﻦ ﺗﻌﺮﻳﻒ ﻣﺮﺑﻮط ﺑﻪ‬ ‫ﻛﻼس ‪ A‬اﺳﺖ ﺑﻌﺪ از ﻧﻮع ﺧﺮوﺟﻲ و ﻗﺒﻞ از اﺳﻢ ﺗﺎﺑﻊ ‪ A::‬اﺿﺎﻓﻪ ﺷﺪه‪ A::f .‬اﺳﻢ ﻛﺎﻣﻞ ﺗﺎﺑﻊ )(‪ f‬اﺳﺖ‪ .‬در‬ ‫ﻣﺜﺎل زﻳﺮ از اﺳﻢ ﻛﺎﻣﻞ اﺳﺘﻔﺎده ﺷﺪه‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫;)(‪void f‬‬ ‫;)‪void g(int = 5‬‬ ‫;}‬ ‫)(‪void A::f‬‬ ‫{‬ ‫;"‪cout<< "A::f called\n‬‬ ‫}‬ ‫)‪void A::g(int a‬‬ ‫{‬ ‫" << ‪cout<< a‬‬ ‫;"‪A::g called\n‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪A a‬‬ ‫;)(‪a.f‬‬ ‫;)(‪a.A::f‬‬

‫‪210‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ a.g(); _getch(); }

Output: A::f called A::f called 5 A::g called

‫ ﺑﺮاي‬default ‫ ﻣﻘﺪار‬.‫ ﻳﻚ ﺑﺎر ﺑﻪ ﻃﻮر ﻋﺎدي و ﻳﻚ ﺑﺎر ﺑﺎ اﺳﻢ ﻛﺎﻣﻞ‬.‫ را ﻓﺮاﺧﻮاﻧﺪهاﻳﻢ‬f() ‫ دو ﺑﺎر‬a ‫از ﻃﺮﻳﻖ‬ ‫ ﻫﻢ زﻣﺎن ﻧﺒﺎﻳﺪ ﻣﻘﺪار‬prototype ‫ اﻣﺎ ﺗﻌﺮﻳﻒ و‬.‫ در ﺗﻌﺮﻳﻒ ﻧﻮﺷﺖ‬prototype ‫ را ﻣﻲﺷﻮد ﺑﻪ ﺟﺎي‬g() ‫ﭘﺎراﻣﺘﺮ‬ .‫ داﺷﺘﻪ ﺑﺎﺷﻨﺪ‬default :‫ اﺳﺖ‬inline ‫ ﺗﻌﺮﻳﻒ ﻣﻲﻛﻨﻴﻢ ﻛﻪ‬method ‫در ﻣﺜﺎل زﻳﺮ ﻳﻚ‬ #include <conio.h> #include <iostream> using namespace std; class A { public: A(){} // default constructor A(const A&) // copy constructor { cout<< "A copy constructor\n"; } }; class B { public: void f(A a); }; inline void B::f(A a) { cout<< "B::f\n"; } int main() { B b; A a; b.f(a); _getch(); }

Output: A copy constructor B::f

211

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺑﺎ ﻧﻮﺷﺘﻦ ‪ inline‬ﻗﺒﻞ از ﺗﻌﺮﻳﻒ ‪ method‬ﺑﻪ ‪ compiler‬ﭘﻴﺸﻨﻬﺎد ﻣﻲﺷﻮد ﻛﻪ آن را ‪ inline‬ﺑﮕﻴﺮد‪ .‬ﻣﻲﺑﻴﻨﻴﺪ‬ ‫ﺑﺎ اﻳﻦ ﻛﻪ ‪ inline‬ﻧﻮﺷﺘﻪ ﺷﺪه ‪ copy constructor‬ﻓﺮاﺧﻮاﻧﺪه ﺷﺪه اﺳﺖ ﻛﻪ اﻟﺒﺘﻪ ﭼﻨﺪان ﻣﻄﻠﻮب ﻧﻴﺴﺖ )ﺣﺘﻲ‬ ‫اﮔﺮ ﺑﻪ ﺟﺎي ‪ inline‬در ‪compiler‬ﻫﺎي ‪ Microsoft‬از ‪ __forceinline‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ ﺑﺎز ﻫﻢ ‪copy‬‬ ‫‪ constructor‬ﻓﺮاﺧﻮاﻧﺪه ﻣﻲﺷﻮد(‪.‬‬ ‫اﮔﺮ ﺗﻌﺮﻳﻒ ‪ method‬را داﺧﻞ ﻛﻼس ﺑﻨﻮﻳﺴﻴﻢ ﺑﻪ ﻃﻮر ﺧﻮدﻛﺎر ‪ inline ،method‬ﺑﻪ ﺣﺴﺎب ﻣﻲآﻳﺪ‪ .‬ﻳﻌﻨﻲ‬ ‫ﺑﻪ ﺟﺎي‬ ‫‪class B‬‬ ‫{‬ ‫‪public:‬‬ ‫;)‪void f(A a‬‬ ‫;}‬ ‫)‪inline void B::f(A a‬‬ ‫{‬ ‫;"‪cout<< "B::f\n‬‬ ‫}‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫‪class B‬‬ ‫{‬ ‫‪public:‬‬ ‫)‪void f(A a‬‬ ‫{‬ ‫;"‪cout<< "B::f\n‬‬ ‫}‬ ‫;}‬

‫و اﻳﻦ ﻓﺮﻗﻲ ﺑﺎ ‪ inline‬ﺗﻌﺮﻳﻒ ﻛﺮدن )(‪ f‬ﻧﺪارد‪ .‬در اﻳﻦ ﺣﺎﻟﺖ ﻣﻲﮔﻮﻳﻴﻢ )(‪ f‬ﺑﻪ ﻃﻮر ﭘﻨﻬﺎن )ﻳﺎ )‪implicit‬‬ ‫‪ inline‬اﺳﺖ‪.‬‬

‫‪ %" ،typedef‬ه ‪ 8‬و ‪O‬س‬

‫ﻗﺒﻼ ﻧﺤﻮهي اﺳﺘﻔﺎدهي زﻳﺮ از ‪ typedef‬را ﺑﺎ ‪ struct‬ﮔﻔﺘﻪام‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪typedef class‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int a‬‬

‫‪212‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ } MyClass; int main() { MyClass a = {5}; cout<< a.a; _getch(); }

Output: 5

‫ داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﭼﻮن ﻫﻴﭻ اﺳﻤﻲ ﺑﺮاي ﺧﻮد ﻛﻼس اﻧﺘﺨﺎب ﻧﻜﺮدهاﻳﻢ و ﺑﺮاي‬constructor ‫اﻣﺎ در اﻳﻦ ﺟﺎ ﻧﻤﻲﺗﻮاﻧﻴﻢ‬ .‫ اﻧﺘﺨﺎب ﻛﻨﻴﻢ‬constructor ‫ﻫﻤﻴﻦ ﻧﻤﻲﺗﻮاﻧﻴﻢ اﺳﻤﻲ ﺑﺮاي‬ :‫ اﻳﻦ ﻣﺜﺎل را ﺑﺒﻴﻨﻴﺪ‬.‫آﻳﺎ ﻣﻲﺷﻮد از ﻧﻮع ﻳﻚ ﻛﻼس ﻣﺘﻐﻴﺮ ﻋﻤﻮﻣﻲ ﺗﻌﺮﻳﻒ ﻛﺮد؟ ﻣﺴﻠﻢ اﺳﺖ ﻛﻪ ﺑﻠﻪ‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: int age; }; Cat Tom; int main() { cout<< Tom.age; _getch(); }

Output: 0

:‫ﻫﻤﻴﻦ را ﻣﻲﺷﻮد ﺳﺎده ﺗﺮ ﻧﻮﺷﺖ‬ #include <conio.h> #include <iostream> using namespace std; class Cat { public: int age; } Tom; int main() { cout<< Tom.age;

213

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ _getch(); }

Output: 0

‫ ﺑﺎ داﻧﺴﺘﻦ اﻳﻦ‬.‫ )ﻳﻌﻨﻲ »;«( ﻣﻲﮔﺬارﻳﻢ‬semicolon ‫ﺣﺎﻻ دﻳﮕﺮ ﻣﻌﻠﻮم اﺳﺖ ﻛﻪ ﭼﺮا ﺑﻌﺪ از ﺗﻌﺮﻳﻒ ﻳﻚ ﻛﻼس‬ ‫ﻛﻪ ﻣﻲﺷﻮد ﻣﺘﻐﻴﺮ ﻋﻤﻮﻣﻲ ﺑﺎ ﻧﻮع ﻳﻚ ﻛﻼس داﺷﺖ ﻣﻤﻜﻦ اﺳﺖ وﺳﻮﺳﻪ ﺷﻮﻳﻢ ﻛﻪ ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﻢ ﻛﻪ اﺻﻼ‬ ‫ در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺗﺎﺑﻌﻲ ﻫﺴﺖ ﻛﻪ ﻳﻚ آراﻳﻪ‬.‫ ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﺟﻮاب اﻳﻦ وﺳﻮﺳﻪ اﺳﺖ‬.‫ ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ‬main() ‫ﻛﺎري ﺑﻪ‬ :‫را ﻣﺮﺗﺐ ﻣﻲﻛﻨﺪ‬ #include <conio.h> #include <iostream> using namespace std; void arrange(int input[],int output[]) { int x[5] = {0}; int i,j; for(i = 0; i < 5; i++) for (j = 0; j < 5; j++) { if(input[j] <= input[i]) x[i]++; if(i < j && input[j] == input[i]) x[i]--; } for(i = 0; i < 5; i++) output[ x[i] - 1 ] = input[i]; } class Main { public: Main() { int a[5] = {7,73,1,19,10}; int b[5],i; arrange(a,b); for (i=0; i < 5; i++) cout<< b[i] << endl; _getch(); } } Bailando; int main(){}

Output: 1

214

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪7‬‬ ‫‪10‬‬ ‫‪19‬‬ ‫‪73‬‬

‫آراﻳﻪي ‪ a‬ﺑﻪ ﺗﺎﺑﻊ ‪ arrange‬داده ﺷﺪه ﺗﺎ ﻣﺮﺗﺐ ﺷﻮد و ﻣﺮﺗﺐ ﺷﺪهي آن در آراﻳﻪي ‪ b‬ﻗﺮار ﺑﮕﻴﺮد‪ .‬ﺑﻌﺪ آراﻳﻪي‬ ‫‪ b‬ﭼﺎپ ﺷﺪه‪ .‬اﮔﺮ ﺑﻪ زﺣﻤﺖ ﻣﻲاﻓﺘﻴﺪ ﺧﻴﻠﻲ ﺑﻪ دﻧﺒﺎل ﻓﻬﻤﻴﺪن ﻧﺤﻮهي ﻛﺎر ﺗﺎﺑﻊ )(‪ arrange‬ﻧﺒﺎﺷﻴﺪ وﻟﻲ اﮔﺮ ﻣﻲ‪-‬‬ ‫ﺧﻮاﻫﻴﺪ ﺑﺪاﻧﻴﺪ )(‪ arrange‬ﭼﮕﻮﻧﻪ ﻛﺎر ﻣﻲﻛﻨﺪ ﺑﺎﻳﺪ ﺑﮕﻮﻳﻢ اﻳﻦ ﺗﺎﺑﻊ را ﺑﺎ ﺗﻮﺟﻪ ﺑﻪ ﺗﺎﺑﻊ وارون در رﻳﺎﺿﻴﺎت‬ ‫ﻃﺮاﺣﻲ ﻛﺮدهام‪ .‬ﺗﺎﺑﻊﻫﺎي ﺑﻬﺘﺮي ﻫﻢ ﻫﺴﺖ‪ .‬در ‪header file‬ﻫﺎي اﻏﻠﺐ ‪compiler‬ﻫﺎ ﻫﻢ اﻳﻦ ﺟﻮر ﺗﺎﺑﻊﻫﺎ ﭘﻴﺪا‬ ‫ﻣﻲﺷﻮﻧﺪ )ﺑﻪ دﻧﺒﺎل ‪ qsort‬ﺑﮕﺮدﻳﺪ(‪.‬‬ ‫ﺑﺎ دﻳﺪن اﻳﻦ ﻣﺜﺎل ﺑﻪ ﻳﺎد ‪ C#‬ﻧﻴﻔﺘﺎدﻳﺪ؟‬ ‫اﻟﺒﺘﻪ راه دﻳﮕﺮي ﻫﻢ ﻫﺴﺖ ﻛﻪ ﺗﺎﺑﻊ )(‪ main‬را دور ﺑﺰﻧﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int f‬‬ ‫{‬ ‫;"‪cout<< "hello‬‬ ‫;)(‪_getch‬‬ ‫;‪return 0‬‬ ‫}‬ ‫;)(‪int a = f‬‬ ‫}{)(‪int main‬‬

‫‪Output:‬‬ ‫‪hello‬‬

‫ا ‪static P‬‬

‫وﺟﻮد ‪ constructor‬ﺑﺎﻋـﺚ ﻣﻲﺷﻮد ﻛﻪ ﺑﺘﻮاﻧﻴﻢ ‪ compiler‬را رواﻧﺸﻨﺎﺳﻲ ﻛﻨﻴﻢ و آن را ﺑﻬﺘﺮ ﺑﺸﻨﺎﺳﻴﻢ‪ .‬در‬ ‫ﺑﺮﻧﺎﻣﻪ زﻳﺮ ﺑﺎ اﺳﺘﻔﺎده از ‪ constructor‬ﺗﺮﺗﻴﺐ اﻳﺠﺎد ﻣﺘﻐﻴﺮﻫﺎي ‪ static‬ﻣﺸﺨﺺ ﺷﺪه اﺳﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪215‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫;"‪A constructor\n‬‬

‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫)‪A(int w‬‬ ‫{‬ ‫" << ‪cout<< w‬‬ ‫}‬ ‫;}‬ ‫)(‪void f‬‬ ‫{‬ ‫;)‪static A y(3‬‬ ‫}‬ ‫;)‪A b(1‬‬ ‫;)‪static A a(2‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪f‬‬ ‫;)(‪f‬‬ ‫;)(‪getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1 A constructor‬‬ ‫‪2 A constructor‬‬ ‫‪3 A constructor‬‬ ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻣﺘﻐﻴﺮ ﻋﻤﻮﻣﻲ ‪ b‬اول و ﺑﻌﺪ ﻣﺘﻐﻴﺮ ‪ a ِ static‬ﺳﺎﺧﺘﻪ ﺷﺪه‪ .‬در ﺿﻤﻦ ﻣﺘﻐﻴﺮ ‪ static‬ﻣﻮﺟﻮد در ﺗﺎﺑﻊ )(‪f‬‬

‫ﻗﺒﻞ از ﻓﺮاﺧﻮاﻧﻲ ﺗﺎﺑﻊ اﺻﻼ ﺑﻪ وﺟﻮد ﻧﻴﺎﻣﺪه اﺳﺖ و ﺑﺎ ﻓﺮاﺧﻮاﻧﻲ ﻣﺠﺪد )(‪ f‬دوﺑﺎره اﻳﺠﺎد ﻧﻤﻲﺷﻮد‪ .‬ﺳﻮاﻟﻲ ﻛﻪ ﺑﻪ‬ ‫وﺟﻮد ﻣﻲآﻳﺪ اﻳﻦ اﺳﺖ ﻛﻪ ‪ static‬ﺑﻮدن ﻣﺘﻐﻴﺮ ﻋﻤﻮﻣﻲ )‪ (global‬ﭼﻪ ﻓﺮﻗﻲ ﺑﺎ ‪ static‬ﻧﺒﻮدن آن دارد؟ ﺑﺎﻳﺪ‬ ‫ﺑﮕﻮﻳﻢ ﻛﻪ ﺗﺎ زﻣﺎﻧﻲ ﻛﻪ ﺑﻪ ﺷﻜﻞ ﻛﻨﻮﻧﻲ در ﻳﻚ ﻓﺎﻳﻞ ﺑﺮﻧﺎﻣﻪ ﻣﻲﻧﻮﻳﺴﻴﻢ ﻧﻮﺷﺘﻦ ﻳﺎ ﻧﻨﻮﺷﺘﻦ آن ﺑﺮاي ﻣﺘﻐﻴﺮﻫﺎي‬ ‫ﻋﻤﻮﻣﻲ ﻓﺮﻗﻲ ﻧﺪارد‪ .‬در ﻓﺼﻞ ﭼﻬﺎرم ﺑﻴﺶ ﺗﺮ ﺗﻮﺿﻴﺢ ﻣﻲدﻫﻢ‪.‬‬ ‫درون ﻳﻚ ﻛﻼس ﻫﻢ‪ ،‬ﻣﻲﺷﻮد ﻣﺘﻐﻴﺮ ﻳﺎ ﺗﺎﺑﻊ ‪ static‬داﺷﺖ‪ .‬ﺗﺎﺑﻊﻫﺎي ‪ static‬در ﻳﻚ ﻛﻼس ﻓﻘﻂ از ﻣﺘﻐﻴﺮﻫﺎي‬ ‫‪ static‬آن ﻛﻼس ﻣﻲﺗﻮاﻧﻨﺪ اﺳﺘﻔﺎده ﻛﻨﻨﺪ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫;‪const unsigned PINK = 13865423‬‬ ‫‪class Pink‬‬ ‫{‬ ‫‪public:‬‬ ‫)(‪static void Run‬‬

‫‪216‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫{‬ ‫;"‪cout<< "Pink Running\n‬‬ ‫;‪color++‬‬ ‫}‬ ‫; ‪static int color‬‬ ‫;}‬ ‫;‪int Pink::color = PINK‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪Pink::Run‬‬ ‫;‪Pink Panther‬‬ ‫;)(‪Panther.Run‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪Pink Running‬‬ ‫‪Pink Running‬‬

‫ﭼﻴﺰﻫﺎي ﻣﻬﻢ در اﻳﻦ ﺑﺮﻧﺎﻣﻪ را در ﻟﻴﺴﺖ زﻳﺮ آوردهام‪:‬‬ ‫‪ (1‬ﺗﺎﺑﻊ ‪ Run() ِ static‬ﻣﺘﻐﻴﺮ ‪ color ِ static‬را ﻛﻪ ﺑﻌﺪ از آن ﻣﻌﺮﻓﻲ ﺷﺪه ﺗﻐﻴﻴﺮ ﻣﻲدﻫﺪ‪.‬‬ ‫‪ (2‬ﺑﻪ ﻣﺘﻐﻴﺮ ‪ static color‬ﺣﺘﻤﺎ ﺑﺎﻳﺪ ﻣﻘﺪار اوﻟﻴﻪ داده ﺑﺸﻮد و اﻳﻦ ﻛﺎر ﻓﻘﻂ ﺧﺎرج از ﻛﻼس اﻣﻜﺎن ﭘﺬﻳﺮ‬ ‫اﺳﺖ‪ .‬ﻣﺜﻼ ﻧﻤﻲﺷﻮد دادن ﻣﻘﺪار اوﻟﻴﻪ را داﺧﻞ ﻓﻀﺎي ﻛﻼس اﻧﺠﺎم داد ﻳﺎ از ‪ constructor‬ﺑﺮاي آن‬ ‫ﻛﻤﻚ ﮔﺮﻓﺖ‪.‬‬ ‫‪ (3‬ﺑﻪ ﺟﺎي‬ ‫;‪int Pink::color = PINK‬‬

‫ﻣﻲﺗﻮاﻧﻴﻢ !‪: .G1‬‬ ‫;)‪int Pink::color(PINK‬‬

‫‪ (4‬ﺑﺮاي ﻓﺮاﺧﻮاﻧﻲ ﻳﻚ ﺗﺎﺑﻊ ‪ static‬در ﻳﻚ ﻛﻼس ﻧﻴﺎزي ﺑﻪ داﺷﺘﻦ ﻳﻚ ‪ object‬از آن ﻛﻼس ﻧﻴﺴﺖ و‬ ‫اﮔﺮ ﺗﺎﺑﻊ ‪ static‬ﻣﺜﻞ ﻣﺜﺎل ﺑﺎﻻ ‪ public‬ﺑﺎﺷﺪ ﺑﺎ ﻧﻮﺷﺘﻦ اﺳﻢ ﻛﺎﻣﻠﺶ ﻣﻲﺷﻮد آن را ﻓﺮاﺧﻮاﻧﺪ‪.‬‬ ‫‪ (5‬از ﻳﻚ ‪ object‬ﻫﻢ ﻣﻲﺷﻮد ﺑﺮاي ﻓﺮاﺧﻮاﻧﻲ ﺗﺎﺑﻊ ‪ static‬ﻛﻤﻚ ﮔﺮﻓﺖ‪ .‬درﺳﺖ ﻣﺜﻞ ﻳﻚ ‪method‬‬ ‫ﻣﻌﻤﻮﻟﻲ‪.‬‬ ‫ﻣﺘﻐﻴﺮﻫﺎي ‪ static‬در اﺑﺘﺪاي ﺑﺮﻧﺎﻣﻪ ﻳﻚ ﺑﺎر ﺑﻪ وﺟﻮد ﻣﻲ آﻳﻨﺪ و ﺗﺎ ﭘﺎﻳﺎن ﺑﺮﻧﺎﻣﻪ از ﺑﻴﻦ ﻧﻤﻲروﻧﺪ‪ .‬ﺑﺮاي ﺗﺴﺖ اﻳﻦ‬ ‫ﻣﻄﻠﺐ‪ ،‬ﺑﮕﺬارﻳﺪ دوﺑﺎره ﺑﻪ ﺳﺮاغ رواﻧﺸﻨﺎﺳﻲ ‪ compiler‬ﺑﺮوﻳﻢ‪:‬‬ ‫>‪#include <conio.h‬‬

‫‪217‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <iostream> using namespace std; class Test { public: Test(int a) { cout<< "Test copy constructor\n"; } }; class Boy { static Test test; }; Test Boy::test(5); // initialization int main() { cout<< "hello\n"; Boy Hub, Charlie; _getch(); }

Output: Test copy constructor hello

:‫ راه دﻳﮕﺮ اﻳﻦ اﺳﺖ ﻛﻪ ﺑﻪ ﻃﻮر ﻃﺒﻴﻌﻲ ﺑﻨﻮﻳﺴﻴﻢ‬.‫ ﻗﺎﺑﻞ ﺗﻮﺟﻪ اﺳﺖ‬test ‫در اﻳﻦ ﻣﺜﺎل ﻧﺤﻮهي دادن ﻣﻘﺪار اوﻟﻴﻪ ﺑﻪ‬ Test Boy::test = 5;

‫ ﺗﻌﺮﻳﻒ ﻧﻤﻲﺷﺪ ﺑﺎز ﻫﻢ ﻫﻤﻴﻦ ﺧﺮوﺟﻲ را ﻣﻲداﺷﺘﻴﻢ ﻛﻪ از ﺳﺎﺧﺘﻪ ﺷﺪن ﻣﺘﻐﻴﺮ‬Boy ‫اﮔﺮ ﻫﻴﭻ ﻣﺘﻐﻴﺮي ﻫﻢ از ﻧﻮع‬ ‫ ﻓﻘﻂ ﻳﻚ ﺑﺎر‬test ‫ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬.‫( ﺣﻜﺎﻳﺖ دارد‬main() ‫ در اﺑﺘﺪاي ﺑﺮﻧﺎﻣﻪ )و ﻗﺒﻞ از ﻓﺮا ﺧﻮاﻧﻲ‬test ِ static .‫ دوﺑﺎره ﺳﺎﺧﺘﻪ ﻧﺸﺪه‬Charlie ‫ و‬Hub ‫ﺳﺎﺧﺘﻪ ﺷﺪه و ﺑﺎ اﻳﺠﺎد‬ :‫ ﺑﺎﺷﺪ ﻣﻲﺷﻮد ﺑﻪ آن در ﺧﻮد ﻛﻼس ﺑﻪ ﺷﻜﻞ ﻃﺒﻴﻌﻲ ﻣﻘﺪار اوﻟﻴﻪ داد‬static ،int ‫اﮔﺮ ﺛﺎﺑﺘﻲ از ﻧﻮع‬ #include <conio.h> #include <iostream> using namespace std; class A { public: const static int a = 235711; }; int main() { cout<< A::a;

218

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ _getch(); }

Output: 235711

‫ ﺧﻮﺑﻲ آنﻫﺎ اﻳﻦ اﺳﺖ ﻛﻪ ﺑﻴﻦ ﻫﻤﻪي‬.‫ ﺑﻪ ﭼﻪ درد ﻣﻲﺧﻮرﻧﺪ‬static ‫ﺷﺎﻳﺪ ﺑﺎ ﺧﻮدﺗﺎن ﻓﻜﺮ ﻛﺮده ﺑﺎﺷﻴﺪ ﻛﻪ ﻣﺘﻐﻴﺮﻫﺎي‬ ‫ اﺳﺘﻔﺎده ﺷﺪه‬static ‫ در ﻣﺜﺎل زﻳﺮ از ﻳﻚ ﻣﺘﻐﻴﺮ‬.‫ﻫﺎ(ي ﻳﻚ ﻛﻼس ﻣﺸﺘﺮك ﻫﺴﺘﻨﺪ‬object ‫ﻫﺎ )ﻳﻌﻨﻲ‬instance :‫ﻫﺎي ﻣﻮﺟﻮد از ﻳﻚ ﻛﻼس را ﻣﻲﺷﻤﺎرد‬object ‫اﺳﺖ ﻛﻪ ﺗﻌﺪاد‬ #include <conio.h> #include <iostream> using namespace std; class Class { public: static int number_of_Classes; Class() // constructor { cout<< "a new class constructed\n"; number_of_Classes++; } ~Class() // destructor { cout<< "a class destructed\n"; number_of_Classes--; } }; int Class::number_of_Classes = 0; int main() { Class avvale_alef; Class avvale_be; { // a block Class avvale_jim; } cout<< endl << "number of existing classes: " << Class::number_of_Classes; _getch(); }

Output: a new class constructed a new class constructed a new class constructed a class destructed number of existing classes: 2

219

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪template‬ه ‬

‫ﻛﻼسﻫﺎ و ﺗﺎﺑﻊﻫﺎ را ﻣﻲﺷﻮد ﺑﻪ ﺻﻮرت ‪ template‬ﻧﻮﺷﺖ‪ .‬اول ‪template‬ﻫﺎ را ﺑﺮاي ﺗﺎﺑﻊﻫﺎي ﻣﻌﻤﻮﻟﻲ ﻣﻌﺮﻓﻲ‬ ‫ﻣﻲﻛﻨﻢ‪ .‬ﻗﺒﻼ ﺗﺎﺑﻊ زﻳﺮ را ﺑﺮاي ﻣﺮﺗﺐ ﻛﺮد ﻳﻚ آراﻳﻪ از ‪ 5‬ﻋﺪد ﺑﺎ ﻧﻮع ‪ int‬ﻣﻌﺮﻓﻲ ﻛﺮدم‪:‬‬ ‫)][‪void arrange(int input[],int output‬‬ ‫{‬ ‫;}‪int x[5] = {0‬‬ ‫;‪int i,j‬‬ ‫)‪for(i = 0; i < 5; i++‬‬ ‫)‪for (j = 0; j < 5; j++‬‬ ‫{‬ ‫)]‪if(input[j] <= input[i‬‬ ‫;‪x[i]++‬‬ ‫)]‪if(i < j && input[j] == input[i‬‬ ‫;‪x[i]--‬‬ ‫}‬ ‫)‪for(i = 0; i < 5; i++‬‬ ‫;]‪output[ x[i] - 1 ] = input[i‬‬ ‫}‬

‫ﺣﺎل اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻫﻤﻴﻦ ﺗﺎﺑﻊ را ﻃﻮري ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﻢ ﻛﻪ آراﻳﻪاي از ‪ double‬ﻫﺎ را ﻣﺮﺗﺐ ﻛﻨﺪ‪ ،‬ﺑﺎﻳﺪ ﺗﺎﺑﻊ‬ ‫)(‪ arrange‬را ‪ overload‬ﻛﻨﻴﻢ و ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫)][‪void arrange(double input[],double output‬‬ ‫{‬ ‫;}‪int x[5] = {0‬‬ ‫;‪int i,j‬‬ ‫)‪for(i = 0; i < 5; i++‬‬ ‫)‪for (j = 0; j < 5; j++‬‬ ‫{‬ ‫)]‪if(input[j] <= input[i‬‬ ‫;‪x[i]++‬‬ ‫)]‪if(i < j && input[j] == input[i‬‬ ‫;‪x[i]--‬‬ ‫}‬ ‫)‪for(i = 0; i < 5; i++‬‬ ‫;]‪output[ x[i] - 1 ] = input[i‬‬ ‫}‬

‫‪ overload‬ﻛﺮدن اﻳﻦ ﺗﺎﺑﻊ ﺑﺮاي ‪ char‬و اﻧﻮاع دﻳﮕﺮي ﻛﻪ ﺧﻮد ﻣﺎ ﺑﻪ وﺟﻮد آوردهاﻳﻢ ﻳﺎ ﻫﻨﻮز ﺑﻪ وﺟﻮد ﻧﻴﺎورده‪-‬‬ ‫اﻳﻢ ﻛﺎر ﺳﺨﺘﻲ اﺳﺖ و ﺟﺎي زﻳﺎدي ﻣﻲﮔﻴﺮد و اﺣﺘﻤﺎل ﺧﻄﺎ ﻫﻨﮕﺎم ‪ overload‬ﻛﺮدن ﺑﺎﻻ ﻣﻲرود‪ .‬راﻫﻲ ﻛﻪ‬ ‫‪ C++‬ﭘﻴﺸﻨﻬﺎد ﻣﻲﻛﻨﺪ اﺳﺘﻔﺎده از ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ template‬اﺳﺖ‪ .‬ﻣﺜﺎل زﻳﺮ ﻧﺤﻮهي اﺳﺘﻔﺎده از آن را ﻧﺸﺎن‬ ‫ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬

‫‪220‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ using namespace std; template <typename Type> void arrange(Type input[],Type output[]) { int x[5] = {0}; int i,j; for(i = 0; i < 5; i++) for (j = 0; j < 5; j++) { if(input[j] <= input[i]) x[i]++; if(i < j && input[j] == input[i]) x[i]--; } for(i = 0; i < 5; i++) output[ x[i] - 1 ] = input[i]; } int main() { int a[5] = {7,73,1,19,10}; int b[5],i; arrange(a,b); for (i = 0; i < 5; i++) cout<< b[i] << endl; _getch(); }

Output: 1 7 10 19 73

‫ ﻣﻲﺗﻮﻧﺪ ﻳﻚ ﻣﻘﺪار ﺑﺮاي‬int ‫عﻫﺎ ﻫﺴﺘﻨﺪ ﻣﺜﻼ‬4i ‫ ﻳﻚ ﺟﻮر ﻣﺘﻐﻴﺮ اﺳﺖ ﻛﻪ ﻣﻘﺪارﻫﺎي آن‬Type ‫در اﻳﻦ ﻣﺜﺎل‬ ‫ را‬b ‫ و‬a ‫ ﻣﻲرﺳﺪ ﻧﻮع‬arrange(a,b); ‫ ﺑﺮﻧﺎﻣﻪ ﺑﻪ‬control ‫ وﻗﺘﻲ‬.‫ع اﺳﺖ‬4i ‫ ﻳﻚ‬int ‫ ﺑﺎﺷﺪ ﭼﻮن‬Type ‫ ﺑﻌﺪ از اﻳﻦ ﻛﻪ ﻧﻮع‬.‫ ﻣﺸﺨﺺ ﻣﻲﺷﻮد‬template ‫ در ﺗﻌﺮﻳﻒ‬Type ‫ﺗﺸﺨﻴﺺ ﻣﻲدﻫﺪ و ﺑﻪ اﻳﻦ ﺗﺮﺗﻴﺐ ﻣﺘﻐﻴﺮ‬ ‫ ﺑﺮاي اﻳﻦ ﻛﻪ ﻣﻮﺿﻮع‬.‫ ﺑﻪ ﻃﻮر ﻋﺎدي اﺟﺮا ﻣﻲﺷﻮد و آراﻳﻪ را ﻣﺮﺗﺐ ﻣﻲﻛﻨﺪ‬arrange() ‫ﺗﺸﺨﻴﺺ داده ﺷﺪ‬ :‫ﺗﺸﺨﻴﺺ ﻧﻮع ﺑﻬﺘﺮ ﻣﻌﻠﻮم ﺑﺸﻮد ﺑﻪ ﻣﺜﺎل ﺳﺎده ﺗﺮي ﻧﻴﺎز دارﻳﻢ‬ #include <conio.h> #include <iostream> using namespace std; template<typename T> void f(T x)

221

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { cout<< typeid(x).name() << endl; } int main() { f(2); f('a'); f(true); _getch(); }

Output: int char bool

.‫ ﺑﻪ راﺣﺘﻲ ﻧﻮع را ﺗﺸﺨﻴﺺ ﻣﻲدﻫﺪ‬compiler ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬ :

‫ ﻛﻢ ﺗﺮ ﺑﻪ زﺣﻤﺖ ﺑﻴﻔﺘﺪ‬compiler ‫ﻣﻲﺗﻮاﻧﻴﻢ ﺣﺘﻲ ﻧﻮع را ﻣﻮﻗﻊ ﻓﺮاﺧﻮاﻧﻲ ﺑﻪ ﻃﻮر واﺿﺢ ﺑﻴﺎن ﻛﻨﻴﻢ ﺗﺎ‬

#include <conio.h> #include <iostream> using namespace std; template<typename T> void f(T x) { cout<< typeid(x).name() << endl; } int main() { f<int>('a'); // where the action is _getch(); }

Output: int

‫ دﻳﮕﺮ‬compiler ‫ ﻗﺮار ﻣﻲﮔﻴﺮد و‬T ‫ ﺑﻪ ﻋﻨﻮان آرﮔﻮﻣﺎن در ﻣﺘﻐﻴﺮ‬int ،f ‫< ﺑﻌﺪ از‬int> ‫در اﻳﻦ ﺟﺎ ﺑﺎ ﻧﻮﺷﺘﻦ‬ .‫ ﻧﻤﻲرود‬T ‫ﺧﻮدش ﺑﻪ دﻧﺒﺎل ﺗﻌﻴﻴﻦ‬ :‫ واﻗﻌﺎ ﺧﻮدش ﻧﻤﻲﺗﻮاﻧﺪ ﻧﻮع را ﺗﺸﺨﻴﺺ دﻫﺪ و راﻫﻨﻤﺎﻳﻲ ﻻزم اﺳﺖ‬compiler ‫در ﺑﺮﺧﻲ ﻣﻮارد ﻫﻢ‬ #include <conio.h> #include <iostream> using namespace std; template<typename T> void f() {

222

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪T t‬‬ ‫;‪cout<< typeid(t).name() << endl‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(>‪f<int‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪int‬‬

‫در اﻳﻦ ﺟﺎ ‪ compiler‬ﻧﻤﻲﺗﻮاﻧﺪ ﺧﻮدش ﻧﻮع را ﺗﺸﺨﻴﺺ دﻫﺪ و ﻣﺎ ﺑﺎﻳﺪ آن را ﻣﺸﺨﺺ ﻛﻨﻴﻢ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ‪ T‬ﺑﺮاي‬ ‫ﻣﺎ ﻫﻨﮕﺎم ﻧﮕﺎه ﻛﺮدن ﺑﻪ ﻣﺘﻦ ﺑﺮﻧﺎﻣﻪ ﻣﺒﻬﻢ ﻧﺒﺎﺷﺪ ﻣﻲﺗﻮاﻧﻴﻢ در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﺟﺎي‬ ‫;‪T t‬‬

‫ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪typename T t‬‬

‫ﻳﻌﻨﻲ ﺑﻪ ﺟﺎي ‪ T‬ﻛﻪ ﻳﻚ ﻣﺘﻐﻴﺮ از ‪4i‬عﻫﺎﺳﺖ ﻣﻲﺷﻮد از ‪ typename T‬اﺳﺘﻔﺎده ﻛﺮد ﺗﺎ ﺗﺄﻛﻴﺪ ﺑﺸﻮد ﻛﻪ ‪ T‬ﻳﻚ‬ ‫ﻣﺘﻐﻴﺮ از ‪4i‬عﻫﺎﺳﺖ‪.‬‬ ‫‪template‬ﻫﺎ ﻣﻲﺗﻮاﻧﻨﺪ ﭘﺎراﻣﺘﺮﻫﺎي ﺑﻴﺸﺘﺮي داﺷﺘﻪ ﺑﺎﺷﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪template<int a, typename T, typename S‬‬ ‫)(‪void f‬‬ ‫{‬ ‫;‪cout<< a << endl‬‬ ‫;‪cout<< typeid(T).name() << endl‬‬ ‫;‪cout<< typeid(S).name() << endl‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(>‪f<2,char,int‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪2‬‬ ‫‪char‬‬ ‫‪int‬‬

‫اﻟﺒﺘﻪ ﭘﺎراﻣﺘﺮﻫﺎ ﻓﻘﻂ ﻣﻲﺗﻮاﻧﻨﺪ ‪ typename‬و ﻧﻮعﻫﺎي ﻃﺒﻴﻌﻲ )ﺑﻪ ﺟﺰ ‪ float‬و ‪ (void‬ﺑﺎﺷﻨﺪ و ﻧﻤﻲﺗﻮاﻧﻴﻢ ﻳﻚ‬ ‫ﭘﺎراﻣﺘﺮ از ﻧﻮع ﻳﻚ ﻛﻼس داﺷﺘﻪ ﺑﺎﺷﻴﻢ‪ .‬ﺑﻪ ﺟﺎي ‪ float‬ﻣﻲﺷﻮد از ‪ double‬اﺳﺘﻔﺎده ﻛﺮد‪.‬‬

‫‪223‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ )ﻛﺎري ﻛﻪ در ﮔﺬﺷﺘﻪ ﻗﺒﻞ از اﺿﺎﻓﻪ ﺷﺪن ﻛﻠﻤﻪي ﻛﻠﻴﺪي‬class ‫ ﻣﻲﺷﻮد ﻧﻮﺷﺖ‬typename ‫ﺑﻪ ﺟﺎي‬ :(‫ اﻧﺠﺎم ﻣﻲﺷﺪ‬C++ ‫ ﺑﻪ‬typename #include <conio.h> #include <iostream> using namespace std; class A{}; template<int a, class T, typename S> void f() { cout<< a << endl; cout<< typeid(typename T).name() << endl; cout<< typeid(S).name() << endl; } int main() { f<2,char,int>(); _getch(); }

Output: 2 char int

:‫ را ﻧﺸﺎن ﻣﻲدﻫﺪ‬class template ‫ ﻣﺜﺎل زﻳﺮ ﻳﻚ‬.‫ ﺑﺎﺷﻨﺪ‬template ‫ﻛﻼسﻫﺎ ﻫﻢ ﻣﻲﺗﻮاﻧﻨﺪ‬ #include <conio.h> #include <iostream> using namespace std; template<typename T, typename S, int a> class A { public: T f(typename S x) { cout<< x << endl; return static_cast<T>(x); } }; int main() { A<int,double,4> a; cout<< a.f(4.25); _getch(); }

Output: 4.25

224

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ 4 double ‫ را‬S ‫ و‬int ‫ را‬T ،main() ‫ در‬.‫ ﻫﻤﻪ ﭼﻴﺰ ﻣﺜﻞ ﺗﺎﺑﻊﻫﺎﺳﺖ‬.‫ﭼﻴﺰ ﻣﺒﻬﻤﻲ در ﻣﻮرد اﻳﻦ ﻣﺜﺎل وﺟﻮد ﻧﺪارد‬

.‫ اﺳﺘﻔﺎده ﺷﺪه‬int ‫ ﺑﻪ‬double ‫ از‬x ‫ ﺑﺮاي ﺗﺒﺪﻳﻞ ﻧﻮع‬static_cast ‫ از‬.‫ﮔﺮﻓﺘﻪام‬ .‫ داﺷﺘﻪ ﺑﺎﺷﻨﺪ‬default ‫ﻫﺎي ﺗﺎﺑﻊ ﻣﻲﺗﻮاﻧﻨﺪ ﻣﻘﺪار‬template ‫ﻫﺎي ﻛﻼس ﺑﺮ ﻋﻜﺲ‬template ‫ﭘﺎراﻣﺘﺮﻫﺎي‬ :‫ﻣﺜﻼ ﻣﺜﺎل ﻗﺒﻞ را ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻪ اﻳﻦ ﺻﻮرت ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﻢ‬ #include <conio.h> #include <iostream> using namespace std; template<typename T, typename S = double, int a = 4> class A { public: T f(typename S x) { cout<< x << endl; return static_cast<T>(x); } }; int main() { A<int> a; cout<< a.f(4.25); _getch(); }

Output: 4.25 4

:‫ﺑﻪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; template<class T> class A { public: void f(); }; void A<int>::f() { cout<< "int\n"; }

225

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪A<int> a‬‬ ‫;)(‪a.f‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪int‬‬

‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﭼﮕﻮﻧﻪ ﻳﻚ ﺗﺎﺑﻊ در ‪ class template‬را ﺑﻪ ﺻﻮرت ﻏﻴﺮ ‪ inline‬ﺗﻌﺮﻳﻒ ﻛﺮدهام‪ .‬اﻣﺎ‬ ‫اﻳﻦ ﺗﻌﺮﻳﻒ ﻓﻘﻂ ﺑﺮاي ﺣﺎﻟﺘﻲ اﺳﺖ ﻛﻪ ﭘﺎراﻣﺘﺮ ‪ T‬ﺑﺮاﺑﺮ ﺑﺎ ‪ int‬ﺑﺎﺷﺪ و اﮔﺮ در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﺟﺎي ;‪A<int> a‬‬

‫ﺑﻨﻮﻳﺴﻴﻢ ;‪ A<char> a‬ﺑﺮﻧﺎﻣﻪ اﺟﺮا ﻧﻤﻲﺷﻮد‪ .‬ﻳﻚ راه ﺣﻞ اﻳﻦ ﻣﺸﻜﻞ آن اﺳﺖ ﻛﻪ )(‪ f‬را ﺑﻪ ﻫﻤﻴﻦ ﺷﻜﻞ‬ ‫ﺑﺮاي ‪ char‬ﻫﻢ ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ اﻣﺎ راه ﺑﻬﺘﺮ آن اﺳﺖ ﻛﻪ آن را ﻣﺜﻞ ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﺑﻪ ﻃﻮر ﻛﻠﻲ ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪template<class T‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫;)(‪void f‬‬ ‫;}‬ ‫>‪template<class T‬‬ ‫)(‪void A<T>::f‬‬ ‫{‬ ‫;"‪cout<< "T\n‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪A<double> a‬‬ ‫;)(‪a.f‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪T‬‬

‫ﺳﻮاﻟﻲ ﻛﻪ اﻳﻦ ﺟﺎ ﭘﻴﺶ ﻣﻲآﻳﺪ اﻳﻦ اﺳﺖ ﻛﻪ در ﻣﺜﺎل ﻗﺒﻠﻲ اﮔﺮ ﻋﻼوه ﺑﺮ ﺗﻌﺮﻳﻒ ﻛﻠﻲ )(‪ ،f‬ﺗﻌﺮﻳﻒﻫﺎﻳﻲ وﻳﮋه‪،‬‬ ‫ﺑﺮاي ﻧﻮعﻫﺎي ﺧﺎص ﻫﻢ اﻧﺠﺎم ﺑﺪﻫﻴﻢ آن وﻗﺖ ﻛﺪام ﺗﻌﺮﻳﻒ اﻧﺘﺨﺎب ﻣﻲﺷﻮد؟ در ﻣﺜﺎل زﻳﺮ اﻳﻦ ﻛﺎر را اﻧﺠﺎم دادهام‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬

‫‪226‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪using namespace std‬‬ ‫>‪template<class T‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫;)(‪void f‬‬ ‫;}‬ ‫>‪template<class T‬‬ ‫)(‪void A<T>::f‬‬ ‫{‬ ‫;"‪cout<< "T\n‬‬ ‫}‬ ‫)(‪void A<int>::f‬‬ ‫{‬ ‫;"‪cout<< "int\n‬‬ ‫}‬ ‫)(‪void A<char>::f‬‬ ‫{‬ ‫;"‪cout<< "char\n‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪A<int> a‬‬ ‫;‪A<char> b‬‬ ‫;‪A<double> c‬‬ ‫;)(‪a.f‬‬ ‫;)(‪b.f‬‬ ‫;)(‪c.f‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪int‬‬ ‫‪char‬‬ ‫‪T‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺗﻌﺮﻳﻒ ﻧﺰدﻳﻚ ﺗﺮ ﭘﻴﺪا و اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪.‬‬ ‫ﻓﺮض ﻛﻨﻴﺪ ﻛﻼﺳﻲ ﺑﻪ اﻳﻦ ﺷﻜﻞ‬ ‫>‪template <typename T‬‬ ‫‪class A‬‬ ‫;}‪{...‬‬

‫دارﻳﻢ‪ .‬اﮔﺮ ‪4i n\ UUU‬ع ﺑﺎﺷﺪ ﻣﻲﺷﻮد ﺑﻪ ﭘﺎراﻣﺘﺮ ‪ T‬ﻣﻘﺪار ‪ UUU‬را داد و ﻧﻮﺷﺖ >‪ .A<UUU‬ﻣﺜﻼ ﭼﻮن ‪int‬‬

‫ﻳﻚ ﻧﻮع اﺳﺖ ﻣﻲﺷﻮد ﻧﻮﺷﺖ >‪ .A<int‬اﻣﺎ ﺧﻮد >‪ A<int‬ﻫﻢ ﻳﻚ ﻧﻮع اﺳﺖ ﭘﺲ ﺑﺎﻳﺪ ﺑﺸﻮد ﻧﻮﺷﺖ‬ ‫>>‪ .A<A<int‬در واﻗﻊ ﻣﻲﺷﻮد اﻳﻦ ﻛﺎر را ﻛﺮد وﻟﻲ ﺑﺮاي اﻳﻦ ﻛﻪ >> ‪ compiler‬در آﺧﺮ آن را ‪operator‬‬ ‫ﺑﻪ ﺣﺴﺎب ﻧﻴﺎورد ﺑﺎﻳﺪ ﻳﻚ ﻓﺎﺻﻠﻪ ﺧﺎﻟﻲ ﺑﻴﻦ > و > ﺑﮕﺬارﻳﻢ و ﺑﻨﻮﻳﺴﻴﻢ > >‪ .A<A<int‬اﻳﻦ ﻣﺜﺎل را ﺑﺒﻴﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬

‫‪227‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ using namespace std; template <typename T> class A { public: typename T a; }; int main() { A<A<int> > a; a.a.a = 2; cout<< a.a.a; _getch(); }

Output: 2

‫ ﭘﺲ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‬.‫ دارد‬A<int> ‫ ﺑﺎ ﻧﻮع‬a ‫ ﻣﺘﻐﻴﺮي ﺑﻪ ﻧﺎم‬A<A<int> > ‫ دارد و‬A<A<int> > ‫ ﻧﻮع‬a a.a.a ‫ ﭘﺲ ﻣﻲﺷﻮد ﻧﻮﺷﺖ‬.‫ دارد‬int ‫ ﺑﺎ ﻧﺎم‬a ‫ ﻫﻢ ﻋﻀﻮي ﺑﻪ ﻧﺎم‬A<int> ‫ اﻣﺎ‬.‫ دارد‬A<int> ‫ ﻛﻪ ﻧﻮع‬a.a

.‫ دارد‬int ‫ﻛﻪ ﻧﻮع‬ ‫ ﺑﻪ ﻣﺜﺎلﻫﺎي زﻳﺮ دﻗﺖ‬.‫ ﺗﻌﺮﻳﻒ ﻣﻲﺷﻮﻧﺪ ﻗﺪرت ﺧﻮﺑﻲ در ﺗﺸﺨﻴﺺ ﻧﻮع دارﻧﺪ‬template ‫ﺗﺎﺑﻊﻫﺎﻳﻲ ﻛﻪ ﺑﻪ ﺻﻮرت‬ :‫ﻛﻨﻴﺪ‬ #include <iostream> using namespace std; template <typename T> class A { public: typename T a; }; template<class T> void f(A<A<T> > x, A<T> y) { cout<< x.a.a << endl; cout<< y.a << endl; cout<< typeid(T).name(); } int main() { A<A<int> > a; a.a.a = 2; f(a,a.a); _getch(); }

228

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪Output:‬‬ ‫‪2‬‬ ‫‪2‬‬ ‫‪int‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ )(‪ f‬ﭘﺎراﻣﺘﺮ ‪ T‬را ﺗﺸﺨﻴﺺ داده و ﺑﻨﺎﺑﺮاﻳﻦ ﻣﻲﺗﻮاﻧﺴﺘﻴﻢ در ﺗﺎﺑﻊ ﻣﺜﻼ از *‪ T‬ﻫﻢ اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪.‬‬ ‫زﺑﺎن ‪ C++‬ﻳﺎ ‪compiler‬ﻫﺎي آن در ﻣﻮرد ‪template‬ﻫﺎ ﻛﻤﻲ ﺿﻌﻒ دارﻧﺪ‪ .‬ﺧﻴﻠﻲ از ﭼﻴﺰﻫﺎﻳﻲ ﻛﻪ در‬ ‫‪compiler‬ﻫﺎي ﻗﺪﻳﻤﻲ در ﻧﺤﻮهي ﻛﺎر ‪template‬ﻫﺎ ﺑﻮد اﻻن ﺗﻐﻴﻴﺮ ﻛﺮده وﻟﻲ ﻫﻨﻮز اﻳﺮادﻫﺎي زﻳﺎدي ﭘﻴﺪا ﻣﻲ‪-‬‬ ‫ﺷﻮد‪ .‬اﮔﺮ ﺑﺨﻮاﻫﻢ راﺣﺖ ﺗﺮ ﺑﮕﻮﻳﻢ ﺧﻴﻠﻲ روي ‪template‬ﻫﺎ ﻛﺎر ﻧﺸﺪه اﺳﺖ‪ .‬اﻟﺒﺘﻪ ﺑﺎز ﻫﻢ ﻣﺜﻞ ﻫﻤﻴﺸﻪ‬ ‫‪compiler‬ﻫﺎي ‪ Microsoft‬ﺑﻬﺘﺮ ﻋﻤﻞ ﻣﻲﻛﻨﻨﺪ )و ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﺑﺮﻧﺪه ﻣﻲﺷﻮﻧﺪ‬

‫ﺑﺎ اﻳﻦ ﺣﺎل ﻣﻦ ﻫﻤﻴﺸﻪ‬

‫‪ Borland‬را در ﺳﺎﺧﺖ ‪ compiler‬ﺑﻪ ‪ Microsoft‬ﺗﺮﺟﻴﺢ ﻣﻲدﻫﻢ(‪.‬‬ ‫ﻣﺜﺎل زﻳﺮ ﻧﻜﺘﻪاي ﺗﺎزه در ﻣﻮرد ﻧﻮع ﭘﺎراﻣﺘﺮﻫﺎي ﻳﻚ ‪ template‬دارد‪:‬‬ ‫>‪#include<conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪template <typename T, T x‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪typename T a‬‬ ‫)(‪void f‬‬ ‫{‬ ‫;‪cout<< x <<endl‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪A<int,3> a‬‬ ‫;)(‪a.f‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪3‬‬

‫ﭼﻴﺰ ﺟﺪﻳﺪ اﻳﻦ اﺳﺖ ﻛﻪ ﻧﻮع ﭘﺎراﻣﺘﺮ دوم ﻫﻤﺎن ﭘﺎراﻣﺘﺮ اول اﺳﺖ‪.‬‬ ‫ﻧﻜﺘﻪي ﻣﻬﻢ دﻳﮕﺮ اﻳﻦ اﺳﺖ ﻛﻪ آرﮔﻮﻣﺎنﻫﺎي ﻳﻚ ‪ template‬ﺑﺎﻳﺪ ﺛﺎﺑﺖ ﺑﺎﺷﻨﺪ‪ .‬ﻣﺜﻼ در ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ ﻧﻤﻲﺷﻮد‬ ‫ﺗﺎﺑﻊ )(‪ main‬را ﺑﻪ اﻳﻦ ﺻﻮرت ﺗﻐﻴﻴﺮ داد‪:‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int b = 8‬‬

‫‪229‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ A<int,b> a; a.f(); _getch(); }

:‫اﻣﺎ ﻣﻲﺷﻮد آن را ﺑﻪ اﻳﻦ ﺻﻮرت ﺗﻐﻴﻴﺮ داد‬ int main() { const int b = 3; A<int,b> a; a.f(); _getch(); }

:‫ اﺟﺮا ﻧﻤﻲﺷﻮد‬BDS 2006 ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ در‬ #include<conio.h> #include <iostream> using namespace std; template <typename T, T x, T* p> class A { public: typename T a; void f() { cout<< x << endl; } }; int main() { int* const b = 0; A<int,4,b> a; a.f(); _getch(); }

Output (Visual C++ 2005): 4

:‫ ﻛﺮد‬template ‫ ﺗﻨﻬﺎ را ﻫﻢ‬method ‫ﻣﻲﺷﻮد ﻳﻚ‬ #include<conio.h> #include <iostream> using namespace std; class A { public: template <typename T> void f(T x) {

230

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ cout<< x << endl; } }; int main() { A a; a.f<int>(5); a.f('a'); _getch(); }

Output: 5 a

‫ را ﺑﻪ ﺗﺸﺨﻴﺺ ﻧﻮع‬compiler ‫ ﮔﻔﺘﻪاﻳﻢ و ﺑﺎر دﻳﮕﺮ ﺧﻮد‬compiler ‫در اﻳﻦ ﺟﺎ ﻳﻚ ﺑﺎر ﻧﻮع را ﺧﻮد ﻣﺎ ﺑﻪ‬ .‫واداﺷﺘﻪاﻳﻢ‬ ‫ﭼﻨﺪ ﺑﺎر ﺑﮕﻮﻳﻢ‬

‫ را ﺑﻪ ﺧﺎرج از ﻛﻼس ﻣﻨﺘﻘﻞ ﻫﺴﺖ؟ )ﻣﻦ ﻛﻪ ﻧﺘﻮاﻧﺴﺘﻢ‬f() ‫اﻣﺎ آﻳﺎ ﻣﻲﺗﻮان ﺗﻌﺮﻳﻒ‬ .(

‫ از ﻣﻦ ﮔﻔﺘﻦ ﺑﻮد‬.‫ﻫﺎ اﻳﺮاد دارﻧﺪ‬template

:‫ ﻛﺮد؟ ﺑﻠﻪ ﺧﻴﻠﻲ ﺳﺎده‬template ،‫ ﺷﺪه‬template ‫ را در ﻳﻚ ﻛﻼس‬method ‫ﺣﺎل آﻳﺎ ﻣﻲﺷﻮد ﻳﻚ‬ #include<conio.h> #include <iostream> using namespace std; template <typename T> class A { public: template <typename S> void f(S x,T y) { cout<< x << " } };

" << y << endl;

int main() { A<double> a; a.f<int>(5,3.1415); a.f(6,9.99); _getch(); }

Output:

231

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪3.1415‬‬ ‫‪9.99‬‬

‫‪5‬‬ ‫‪6‬‬

‫اﻳﻦ ﻫﻢ ﻣﻘﺪار اواﻳﻪ دادن ﺑﻪ ﻣﺘﻐﻴﺮﻫﺎي ‪ static‬در ﻳﻚ ‪:template‬‬ ‫>‪#include<conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪template <typename T‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪static T a‬‬ ‫;}‬ ‫>‪template <typename T‬‬ ‫;‪T A<T>::a = 25‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪cout<< A<double>::a‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪25‬‬

‫ ‪friend‬‬

‫ﮔﻔﺘﻢ ﻛﻪ ﺑﻌﻀﻲ اﻋﻀﺎي ﻛﻼس ‪ private‬ﻫﺴﺘﻨﺪ و ﻓﻘﻂ ‪method‬ﻫﺎي آن ﻛﻼس ﺣﻖ اﺳﺘﻔﺎده از آنﻫﺎ را دارﻧﺪ‪.‬‬ ‫اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻳﻚ ﺗﺎﺑﻊ دﻳﮕﺮ ﻏﻴﺮ از ‪method‬ﻫﺎي ﻛﻼس ﺑﻪ ‪private‬ﻫﺎ )و در واﻗﻊ ﻛﻞ اﻋﻀﺎ( دﺳﺘﺮﺳﻲ داﺷﺘﻪ‬ ‫ﺑﺎﺷﺪ ﺑﺎﻳﺪ در ﻛﻼس اﻋﻼم ﻛﻨﻴﻢ ﻛﻪ ﻓﻼن ﺗﺎﺑﻊ اﺟﺎزهي اﻳﻦ ﻛﺎر را دارد‪ .‬ﺑﺮاي دادن اﻳﻦ اﺟﺎزه از ﻛﻠﻤﻪي ﻛﻠﻴﺪي‬ ‫‪ friend‬اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪ .‬ﺑﺎﻳﺪ ‪ ِ prototype‬ﺗﺎﺑﻊ ﻣﻮرد ﻧﻈﺮ ﻫﻤﺮاه ﺑﺎ ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ friend‬در ﺟﻠﻮي آن‪،‬‬ ‫در ﻓﻀﺎي ﻛﻼس ﻗﺮار داده ﺑﺸﻮد‪:‬‬ ‫>‪#include<conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬ ‫{‬ ‫‪private:‬‬ ‫;‪int x‬‬ ‫)(‪~A‬‬

‫‪232‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { cout<< "A destructor\n"; cout<< x << endl; cout<< y << endl; } public: int y; friend void f(); }; void f() { A a; a.x = 2; a.y = 3; } int main() { f(); _getch(); }

Output: A destructor 2 3

‫ در ﺿﻤﻦ‬.‫ را دارد‬A ‫ از‬object ‫ﻫﺎي ﻫﺮ‬private ‫ ﺣﻖ اﺳﺘﻔﺎده از‬f() ‫ﻣﻲﮔﻮﻳﺪ ﻛﻪ‬

friend void f();

(‫ ﺑﻮدن‬public ‫ ﻳﺎ‬private ‫ ﻣﺤﻞ آن ﻫﻢ )از ﻧﻈﺮ‬.‫ اﺳﺖ‬prototype ‫ﻣﺜﻞ ﻳﻚ ﺟﻮر‬

friend void f();

‫ ﻗﺮار ﮔﺮﻓﺘﻪ اﺳﺖ و اﻳﻦ ﻫﻴﭻ اﺷﻜﺎﻟﻲ ﺑﻪ وﺟﻮد‬private ‫ در ﻗﺴﻤﺖ‬destructor ‫ در اﻳﻦ ﻣﺜﺎل‬.‫ﻓﺮﻗﻲ ﻧﺪارد‬ ‫ ﻛﻪ‬x ‫ ﺑﻪ‬f() ‫ در اﻳﻦ ﻣﺜﺎل ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬.‫ اﺳﺖ‬friend ‫ ﻳﻚ‬f() ‫ ﺑﻪ آن ﻧﻴﺎز دارد و‬f() ‫ﻧﻴﺎورده ﭼﻮن ﻓﻘﻂ ﺗﺎﺑﻊ‬ :‫ ﻛﺮد‬friend ‫ از ﻳﻚ ﻛﻼس دﻳﮕﺮ را ﻫﻢ ﻣﻲﺷﻮد‬method ‫ ﻳﻚ‬.‫ اﺳﺖ دﺳﺘﺮﺳﻲ دارد‬private ‫ﻣﺘﻐﻴﺮي‬ #include<conio.h> #include <iostream> using namespace std; class B { public: void f(); }; class A { private: int x; ~A() { cout<< "A destructor\n"; cout<< x << endl; cout<< y << endl; }

233

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪public:‬‬ ‫;‪int y‬‬ ‫;)(‪friend void B::f‬‬ ‫;}‬ ‫)(‪void B::f‬‬ ‫{‬ ‫;‪A a‬‬ ‫;‪a.x = 2‬‬ ‫;‪a.y = 3‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪(new B) -> f‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪A destructor‬‬ ‫‪2‬‬ ‫‪3‬‬

‫ﺷﺎﻳﺪ ﺑﭙﺮﺳﻴﺪ ﭼﺮا ﺗﻌﺮﻳﻒ )(‪ f‬را در ﺧﺎرج از ﻛﻼس ‪ B‬و ﺑﻌﺪ از ﻛﻼس ‪ A‬اﻧﺠﺎم دادهام؟ ﻋﻠﺘﺶ اﻳﻦ اﺳﺖ ﻛﻪ در‬ ‫ﺗﻌﺮﻳﻒ )(‪ f‬از ‪ A‬اﺳﺘﻔﺎده ﺷﺪه و ﺑﺮاي ﻫﻤﻴﻦ ﺑﺎﻳﺪ ﺑﻌﺪ از ﻛﻼس ‪ A‬ﺗﻌﺮﻳﻒ ﺷﻮد‪ .‬ﭘﺲ ﭼﺮا ﻛﻼس ‪ B‬را ﺑﻪ ﺑﻌﺪ از ‪A‬‬

‫ﻣﻨﺘﻘﻞ ﻧﻜﺮدم؟ ﭼﻮن در ﻛﻼس ‪ A‬ﺑﻪ ‪ B‬اﺷﺎره ﺷﺪه و ﺑﺎﻳﺪ ﻗﺒﻼ ﻣﻌﺮﻓﻲ ﺷﺪه ﺑﺎﺷﺪ در ﺿﻤﻦ ﺧﻮد )(‪ f‬ﻫﻢ ﺑﺎﻳﺪ ﻗﺒﻼ‬ ‫ﻣﻌﺮﻓﻲ ﺷﺪه ﺑﺎﺷﺪ‪.‬‬ ‫ﻣﻲﺷﻮد ﻛﻞ ‪method‬ﻫﺎي ﻳﻚ ﻛﻼس دﻳﮕﺮ را ﻫﻢ ﺑﺎ ‪ friend‬اﻋﻼم ﻛﺮدن آن ﻛﻼس‪ friend ،‬ﻛﺮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫;"‪"A destructor\n‬‬ ‫;‪x << endl‬‬ ‫;‪y << endl‬‬

‫;‪B‬‬

‫‪class A‬‬ ‫{‬ ‫‪private:‬‬ ‫;‪int x‬‬ ‫)(‪~A‬‬ ‫{‬ ‫<<‪cout‬‬ ‫<<‪cout‬‬ ‫<<‪cout‬‬ ‫}‬ ‫‪public:‬‬ ‫;‪int y‬‬ ‫‪friend class‬‬ ‫;}‬ ‫‪class B‬‬

‫‪234‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { public: void B::f() { A a; a.x = 2; a.y = 3; } }; int main() { (new B) -> f(); _getch(); }

Output: A destructor 2 3

.‫ اﺳﺖ‬A ‫ ﺑﺮاي‬friend ‫ ﻳﻚ‬B ‫ اﺳﺘﻔﺎده ﻛﻨﻨﺪ ﭼﻮن ﻛﻼس‬A ‫ﻫﺎي‬private ‫ ﻣﻲﺗﻮاﻧﻨﺪ از‬B ‫ﻫﺎي‬method ‫ﻫﻤﻪي‬ :‫ ﻣﻲﺷﻮد اﻳﻦ ﻣﺜﺎل رو اﻳﻦ ﺟﻮري ﺗﻐﻴﻴﺮ داد‬Borland ‫ و‬Microsoft ‫ﻫﺎي‬compiler ‫در‬ #include <conio.h> #include <iostream> using namespace std; class B; // change class A { private: int x; ~A() { cout<< cout<< cout<< } public: int y; friend B; //

"A destructor\n"; x << endl; y << endl;

change

}; class B { public: void B::f() { A a; a.x = 2; a.y = 3; } };

235

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ int main() { (new B) -> f(); _getch(); }

Output: A destructor 2 3

‫در اﻳﻦ ﺟﺎ‬ class B;

:‫ ﻋﻤﻞ ﻣﻲﻛﻨﺪ ﺑﺮاي ﻫﻢ وﻗﺘﻲ ﻣﻲﻧﻮﻳﺴﻴﻢ‬B ‫ ﺑﺮاي ﻛﻼس‬prototype ‫ﻣﺜﻞ ﻳﻚ ﺟﻮر‬ friend B;

.‫ اﻳﻦ ﺷﻜﻞ را ﻧﻤﻲﭘﺬﻳﺮد‬dev C++ version 4.9.9.2 ‫ اﻟﺒﺘﻪ‬.‫ ﻳﻚ ﻛﻼس اﺳﺖ‬B ‫ ﻣﻲداﻧﺪ ﻛﻪ‬compiler :‫ ﻧﺸﺎن داده ﺷﺪه اﺳﺖ‬template ‫ ﻛﺮدن ﻳﻚ‬friend ‫در ﻣﺜﺎل ﺑﻌﺪ ﻧﺤﻮهي‬ #include <conio.h> #include <iostream> using namespace std; class A { private: int t; template<typename S> friend void f(S s); }; template <typename S> void f(S s) { A a; a.t = 5; cout<< s; } int main() { f<char>(97); _getch(); }

Output: a

236

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ در ﻣﻮرد‬BDS 2006 (update1) .‫ ﺑﺎﺷﺪ‬template ‫ ﻫﻢ ﻣﻲﺗﻮاﻧﺪ‬A ‫ ﺧﻮد ﻛﻼس‬Visual C++ 2005 ‫در‬ ‫ ﺑﻪ ﻫﻤﻴﻦ ﻋﻠﺖ‬.‫ ﻫﺴﺖ‬compiler ‫ اﻋﺘﺮاف ﺷﺪه ﻛﻪ اﺷﻜﺎﻟﻲ اﺳﺎﺳﻲ در‬error ‫ ﻣﻲدﻫﺪ و در ﭘﻴﺎم‬error ‫اﻳﻦ‬ :‫ اﺟﺮا ﻧﻤﻲﺷﻮد‬Borland ِ compiler ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ در‬ #include <conio.h> #include <iostream> using namespace std; template<typename T> class A { private: T t; template<typename S> friend void f(S s); }; template <typename S> void f(S s) { A<int> a; a.t = 5; cout<< s; } int main() { f<char>(97); _getch(); }

Output (Visual C++ 2005): a

‫ اﻳﺠﺎد ﺷﺪه اﻳﻦ ﺑﺮﻧﺎﻣﻪﻫﺎ ﻣﻤﻜﻦ‬template ‫ﺑﺮاي اﻃﻼع ﺷﻤﺎ ﻣﻲﮔﻮﻳﻢ ﻛﻪ ﺑﻪ ﻋﻠﺖ ﺗﻐﻴﻴﺮاﺗﻲ ﻛﻪ در ﻣﻮرد ﻛﺎرﺑﺮد‬ .‫ﻫﺎي ﻗﺪﻳﻤﻲ ﺗﺮ اﺟﺮا ﻧﺸﻮﻧﺪ‬compiler ‫اﺳﺖ در‬

member ‫ ع ? ان‬

‫ ﻫﻢ‬private ‫ اﻳﻦ ﻧﻮع ﻣﻲﺗﻮاﻧﺪ‬.‫ ﻣﻲﺷﻮد ﻳﻚ ﻧﻮع را در ﻓﻀﺎي ﻛﻼس ﺗﻌﺮﻳﻒ ﻛﺮد‬typedef ‫ﺑﺎ اﺳﺘﻔﺎده از‬ :‫ﺑﺎﺷﺪ‬ #include <conio.h>

237

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <iostream> using namespace std; class A { private: typedef int int1; public: typedef int int2; int1 f(int1 x,int2 y) { return x + y; } }; int main() { //A::int1 x = 2; // error int x = 2; A::int2 y = 3; A a; cout<< a.f(x,y); _getch(); }

Output: 5

.‫ ﻧﻤﻲﺷﻮد ﺑﻪ اﻳﻦ ﺷﻜﻞ اﺳﺘﻔﺎده ﻛﺮد‬A::int1 ‫ از‬.‫ اﺳﺖ‬main() ‫ در‬A::int2 ‫اوﻟﻴﻦ ﭼﻴﺰ ﻣﻬﻢ اﺳﺘﻔﺎده از‬ cout ،‫ اﺳﺖ‬int1 private ‫ اﺳﺖ و‬int1 ‫ از ﻧﻮع‬f() ‫دوﻣﻴﻦ ﭼﻴﺰ ﻣﻬﻢ اﻳﻦ اﺳﺖ ﻛﻪ ﺑﺎ اﻳﻦ ﻛﻪ ﺧﺮوﺟﻲ‬

.‫ را ﭼﺎپ ﻛﻨﺪ‬f() ‫ﺗﻮاﻧﺴﺘﻪ ﺧﺮوﺟﻲ‬ :‫در ﻳﻚ ﻛﻼس ﻣﻲﺷﻮد ﻧﻮع ﻛﻼﺳﻲ ﻫﻢ ﺗﻌﺮﻳﻒ ﻛﺮد‬ #include <conio.h> #include <iostream> using namespace std; class A { private: int a; class B { public: void f(); }; public: B b; A(){}// default constructor class C

238

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫{‬ ‫‪public:‬‬ ‫;‪int a‬‬ ‫;}‬ ‫;)‪B g(B‬‬ ‫;}‬ ‫)(‪void A::B::f‬‬ ‫{‬ ‫;"‪cout<< "A::B::f()\n‬‬ ‫‪// cout<< a; // error‬‬ ‫}‬ ‫‪#pragma argsused‬‬ ‫)‪A::B A::g(B c‬‬ ‫{‬ ‫;"‪cout<< "g called\n‬‬ ‫;‪return *new B‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫‪// A::B b; // error‬‬ ‫;}‪A::C c = {3‬‬ ‫;‪cout<< c.a << endl‬‬ ‫;‪A a‬‬ ‫;)‪a.g(a.b‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪3‬‬ ‫‪g called‬‬

‫اوﻻ ﺑﮕﻮﻳﻢ ﻛﻪ ‪default constructor‬ي ﻛﻪ ﻣﻲﺑﻴﻨﻴﺪ ﺑﺮاي اﻳﻦ اﺳﺖ ﻛﻪ ﺟﻠﻮي ﻳﻚ ‪ exception‬ﻧﺎﻣﻨﺎﺳﺐ در‬ ‫‪ Microsoft ِ compiler‬ﮔﺮﻓﺘﻪ ﺑﺸﻮد‪ .‬ﻫﻤﻪي ‪method‬ﻫﺎ در ﺧﺎرج از ﻣﺤﻴﻂ ﻛﻼﺳﺸﺎن ﺗﻌﺮﻳﻒ ﺷﺪهاﻧﺪ‪ .‬اول ﺑﻪ‬ ‫ﻧﺤﻮهي ﺗﻌﺮﻳﻒ ﺗﺎﺑﻊ )(‪ f‬در ﻛﻼس ‪ B‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪ .‬ﺑﻌﺪ ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ در )(‪ main‬ﻧﻤﻲﺷﻮد از ﻧﻮع ‪ B‬اﺳﺘﻔﺎده‬ ‫ﻛﺮد ﭼﻮن ‪ private‬اﺳﺖ‪ .‬ﺑﺮاي ﻫﻤﻴﻦ ﻣﺠﺒﻮر ﺑﻮدم ﺑﺮاي اﻣﺘﺤﺎن ﺗﺎﺑﻊ )(‪ g‬ﻣﺘﻐﻴﺮ ‪ b‬را ﻛﻪ ﻧﻮع ‪ B‬دارد در ﺧﻮد‬ ‫ﻛﻼس ‪ A‬ﺑﺴﺎزم ﺗﺎ ﺑﻪ ﻋﻨﻮان آرﮔﻮﻣﺎن )(‪ g‬اﺳﺘﻔﺎده ﺑﺸﻮد‪ .‬ﺑﻪ ﺗﻌﺮﻳﻒ )(‪ g‬ﻧﮕﺎه ﻛﻨﻴﺪ‪ .‬ﻧﻮع ﺧﺮوﺟﻲ را ﺑﺎ اﺳﻢ‬ ‫ﻛﺎﻣﻞ )‪ (A::B‬ﻣﺸﺨﺺ ﻛﺮدهام اﻣﺎ ﻧﻮع ﭘﺎراﻣﺘﺮ را ﺑﺎ اﺳﻢ ﻏﻴﺮ ﻛﺎﻣﻞ )‪ (B‬ﻣﺸﺨﺺ ﻛﺮدهام‪ .‬ﺑﻪ ﺗﻌﺮﻳﻒ )(‪ f‬ﻧﮕﺎه‬ ‫ﻛﻨﻴﺪ ﺑﺨﺸﻲ ﻛﻪ ‪ comment out‬ﺷﺪه ﻳﻚ ﺧﻄﺎ ﺑﻪ وﺟﻮد ﻣﻲآورد ﭼﻮن ﻛﻼس ‪ B‬ﻧﻤﻲﺗﻮاﻧﺪ از اﻋﻀﺎي ‪ A‬اﺳﺘﻔﺎده‬ ‫ﻛﻨﺪ )ﻛﻪ اﻳﻦ ﻣﺤﺪودﻳﺖ ﭼﻨﺪان ﺟﺎﻟﺐ ﻧﻴﺴﺖ ﻳﻌﻨﻲ ﻣﻦ ﻓﻜﺮ ﻣﻲﻛﻨﻢ اﮔﺮ اﺳﺘﻔﺎده از ﻣﺘﻐﻴﺮﻫﺎي ‪ A‬ﻣﻤﻜﻦ ﺑﻮد اﻧﻌﻄﺎف‬ ‫ﭘﺬﻳﺮي زﺑﺎن ﺑﻴﺶ ﺗﺮ ﻣﻲﺷﺪ ﮔﺮﭼﻪ ﻣﺸﻜﻼﺗﻲ ﻫﻢ ﺑﻪ وﺟﻮد ﻣﻲآﻣﺪ(‪ .‬در ﻛﻼس ‪ C‬ﻣﻲﺗﻮاﻧﺴﺘﻴﻢ ﻧﻮع ‪ a‬را ﺑﻪ ﺟﺎي‬ ‫‪ B ،int‬ﺑﮕﻴﺮﻳﻢ‪.‬‬

‫‪239‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪method‬ه ‪const‬‬

‫اﮔﺮ ﻳﻚ ‪ method‬را ‪ const‬ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‪ ،‬دﻳﮕﺮ ﻧﻤﻲﺗﻮاﻧﺪ ﻣﺘﻐﻴﺮﻫﺎي ﻛﻼس ﺧﻮدش را ﺗﻐﻴﻴﺮ دﻫﺪ‪ .‬ﺑﻪ ﻣﺜﺎل زﻳﺮ‬ ‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪ .‬در اﻳﻦ ﻣﺜﺎل ﻧﺤﻮهي ‪ const‬ﻛﺮدن ﻳﻚ ‪ method‬و ﻫﻢ ﭼﻨﻴﻦ ﺟﺎﻳﻲ ﻛﻪ ‪ const‬ﺑﻮدن ﺑﺎﻋـﺚ اﻳﺠﺎد‬ ‫‪ error‬ﻣﻲﺷﻮد ﻣﺸﺨﺺ ﺷﺪه‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫;‪int univ‬‬ ‫‪class A‬‬ ‫{‬ ‫;‪int a‬‬ ‫‪public:‬‬ ‫‪void f(int aParam) const‬‬ ‫{‬ ‫;"‪cout<< "A::f()\n‬‬ ‫‪// a = aParam; error‬‬ ‫;‪cout<< aParam‬‬ ‫;‪aParam = 10‬‬ ‫;‪univ = 10‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪A a‬‬ ‫;)‪a.f(10022008‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫)(‪A::f‬‬ ‫‪10022008‬‬

‫در اﻳﻦ ﻣﺜﺎل ‪ f() const‬اﺳﺖ و ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﻧﻤﻲﺗﻮاﻧﺪ ﻣﻘﺪار ‪ a‬را ﻋﻮض ﻛﻨﺪ ﭼﻮن ‪ a‬از اﻋﻀﺎي ﻛﻼس اﺳﺖ‪.‬‬ ‫وﻟﻲ ﻫﻤﺎن ﻃﻮر ﻛﻪ ﻣﻲﺑﻴﻨﻴﺪ ﻣﻲﺗﻮاﻧﺪ ﭘﺎراﻣﺘﺮ ﺧﻮدش ﻳﺎ ﻣﺘﻐﻴﺮﻫﺎي ﻋﻤﻮﻣﻲ را ﺗﻐﻴﻴﺮ ﺑﺪﻫﺪ‪.‬‬ ‫اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻳﻚ ‪ const ِ method‬را در ﺧﺎرج از ﻛﻼس ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ ﺑﺎﻳﺪ ‪ const‬را ﻫﻢ در‬ ‫‪ prototype‬و ﻫﻢ در ﺗﻌﺮﻳﻒ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬

‫‪240‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ void f(int a) const; }; void A::f(int a) const { cout<< a; } int main() { A a; int d(5);// i.e.: int d = 5 a.f(d); _getch(); }

Output: 5

.‫ ﺗﻌﺮﻳﻒ ﻣﻲﻛﻨﺪ‬5 ‫ را ﺑﺎ ﻣﻘﺪار اوﻟﻴﻪي‬d ‫ ﻣﺘﻐﻴﺮ‬int d(5) ‫در اﻳﻦ ﻣﺜﺎل‬ :‫ﺣﺎﻻ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; class A { public: void f(int a) const { cout<< "First f()\n"; } void f(int a) { cout<< "Second f()\n"; } }; int main() { A a; int variable = 1387; const int constant = 2009; a.f(variable); // second f() a.f(constant); // second f() _getch(); }

Output: Second f() Second f()

241

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ دو ﺗﺎ ﺗﺎﺑﻊ ﺑﺎ اﺳﻢ و ﭘﺎراﻣﺘﺮﻫﺎي ﻳﻜﺴﺎن دارﻳﻢ‪ .‬ﻓﻘﻂ ﻳﻜﻲ ‪ const‬اﺳﺖ و آن ﻳﻜﻲ ﻧﻴﺴﺖ‪ .‬در ﺗﺎﺑﻊ‬ ‫)(‪ ،main‬ﻣﺘﻐﻴﺮ ‪ variable‬و ﺛﺎﺑﺖ ‪ constant‬ﻣﻌﺮﻓﻲ ﺷﺪهاﻧﺪ‪ .‬اﻳﻦ ﻣﺘﻐﻴﺮ و ﺛﺎﺑﺖ را ﺑﻪ ﻋﻨﻮان آرﮔﻮﻣﺎن‬ ‫)(‪ f‬ﺑﻪ ﻛﺎر ﺑﺮدهام‪ .‬در ﻫﺮ دو ﻣﻮرد )(‪ f‬دوم ﻓﺮاﺧﻮاﻧﺪه ﺷﺪه‪ .‬اﻣﺎ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﺑﺎ اﻳﻦ ﺟﻮر ﻓﺮاﺧﻮاﻧﻲ ﻫﺮ دو ﺗﺎﺑﻊ‬ ‫)(‪ f‬ﺧﻮاﻧﺪه ﺑﺸﻮﻧﺪ ﻛﺎﻓﻲ اﺳﺖ ﺟﻠﻮي ﭘﺎراﻣﺘﺮ )(‪ f‬دوم & ﺑﮕﺬارﻳﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫‪void f(int a) const‬‬ ‫{‬ ‫;"‪cout<< "First f()\n‬‬ ‫}‬ ‫‪void f(int& a) // change‬‬ ‫{‬ ‫;"‪cout<< "Second f()\n‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪A a‬‬ ‫‪int‬‬ ‫;‪variable = 1387‬‬ ‫;‪const int constant = 2009‬‬ ‫)(‪a.f(variable); // second f‬‬ ‫)(‪a.f(constant); // first f‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫)(‪Second f‬‬ ‫)(‪First f‬‬

‫ﺷﺎﻳﺪ ﺑﮕﻮﻳﻴﺪ اﺻﻼ ﻧﻴﺎزي ﺑﻪ ‪ const‬ﺑﻮدن )(‪ f‬اول ﻧﻴﺴﺖ اﻣﺎ اﮔﺮ آن را ﺣﺬف ﻛﻨﻴﺪ ‪ compiler‬ﺑﺮاي‬ ‫;)‪!6 3/ a.f(d‬ا‪ f() /‬ﻣﻨﺎﺳﺐ را ﺗﺸﺨﻴﺺ ﺑﺪﻫﺪ‪.‬‬

‫‪inheritance‬‬

‫در اﻃﺮاف ﻣﺎ ﺳﺎﻋـﺖﻫﺎي زﻳﺎدي ﭘﻴﺪا ﻣﻲﺷﻮد ﻛﻪ زﻣﺎن را ﺑﻪ ﻣﺎ ﻧﺸﺎن ﻣﻲدﻫﻨﺪ‪ .‬ﺳﺎﻋﺘﻲ ﻛﻪ ﺑﻪ دﺳﺘﻤﺎن ﻣﻲﺑﻨﺪﻳﻢ‬ ‫ﺳﺎﻋـﺖ ﻣﭽﻲ اﺳﺖ‪ .‬ﺳﺎﻋﺖ ﻣﭽﻲ ﻳﻚ ﺟﻮر ﺳﺎﻋﺖ اﺳﺖ‪ .‬از ﻃﺮﻓﻲ ﺳﺎﻋﺖ دﻳﻮاري ﻳﺎ ﺷﻤﺎﻃﻪاي )ﻫﻤﺎن ‪alarm‬‬

‫‪242‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ -‫ ﺷﺒﻴﻪ ﺳﺎزي ﻛﻨﻴﻢ ﻣﻲ‬،‫ ﺣﺎﻻ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ اﻳﻦ ﺳﺎﻋﺖﻫﺎ را در ﺑﺮﻧﺎﻣﻪ‬.‫( ﻫﻢ ﻧﻮﻋﻲ ﺳﺎﻋـﺖ اﺳﺖ‬

‫ ﺧﻮدﻣﺎن‬clock

‫ )ﻳﻌﻨﻲ ﻳﻚ ﺳﺎﻋﺖ ﻛﻠﻲ ﻛﻪ ﻣﻲﺗﻮاﻧﺪ ﻫﺮ ﺟﻮر ﺳﺎﻋﺘﻲ ﺑﺎﺷﺪ( درﺳﺖ ﻛﻨﻴﻢ و ﻣﺜﻼ‬Clock ‫ﺗﻮاﻧﻴﻢ ﻛﻼﺳﻲ ﺑﻪ اﺳﻢ‬ :‫ اﻳﻦ ﻣﺜﺎل را ﺑﺒﻴﻨﻴﺪ‬.‫ اﻳﺠﺎد ﻛﻨﻴﻢ‬Clock ‫ را ﺑﺎ اﺿﺎﻓﻪ ﻛﺮدن ﭼﻴﺰﻫﺎﻳﻲ ﺑﻪ‬Alarm_Clock ‫ﻛﻼس‬ #include <conio.h> #include <iostream> using namespace std; class Clock { public: int second_hand; int minute_hand; int hour_hand; }; class AlarmClock: public Clock { public: bool bell; }; class GrandfatherClock { double pendulum; }; int main() { AlarmClock myAlarmClock ; GrandfatherClock yourClock; myAlarmClock.second_hand = 5; cout<< myAlarmClock.second_hand; getch(); }

Output: 5

‫در واﻗﻊ‬ class AlarmClock: public Clock { public: bool bell; };

‫ﻣﻌﺎدل اﺳﺖ ﺑﺎ‬ class AlarmClock { public: int second_hand;

243

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪int minute_hand‬‬ ‫;‪int hour_hand‬‬ ‫‪public:‬‬ ‫;‪bool bell‬‬ ‫;}‬

‫ﺑﺎ ﺗﻮﺟﻪ ﺑﻪ اﻳﻦ ﻫﻤﻪ ﭼﻴﺰ در ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ روﺷﻦ اﺳﺖ و ﻧﻴﺎزي ﺑﻪ ﺗﻮﺿﻴﺢ ﻧﺪارد‪ .‬وﻗﺘﻲ ﻣﻲﻧﻮﻳﺴﻴﻢ‪:‬‬ ‫‪class AlarmClock: public Clock‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪bool bell‬‬ ‫;}‬

‫ﻣﻲﮔﻮﻳﻴﻢ ﻛﻼس ‪ AlarmClock‬از ﻛﻼس ‪) Clock‬ﺑﻪ ﻃﻮر ‪ public) derive‬ﺷﺪه و ﻣﺘﻐﻴﺮﻫﺎي‬ ‫‪ minute_hand ،second_hand‬و ‪ hour_hand‬را از ‪ Clock‬را ﺑﻪ ارث ﺑﺮده )ﻳﺎ ‪ inherit‬ﻛﺮده‬ ‫اﺳﺖ(‪ .‬ﺑﻪ ‪ Clock‬ﻳﻚ ‪ - base‬ﻛﻼس ﺑﺮاي ‪ AlarmClock‬ﻣﻲﮔﻮﻳﻴﻢ‪.‬‬ ‫ﻳﻚ ﻛﻼس اﻋﻀﺎي ‪ private‬ﻛﻼس دﻳﮕﺮ را ﺑﻪ ارث ﻧﻤﻲﺑﺮد ﻳﻌﻨﻲ اﮔﺮ‬ ‫‪class A‬‬ ‫{‬ ‫‪private:‬‬ ‫;‪char a‬‬ ‫;}‬

‫ﻧﻤﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫‪class B : public A‬‬ ‫{‬ ‫)(‪void f‬‬ ‫{‬ ‫;'‪a = 'a‬‬ ‫}‬ ‫;}‬

‫ﭼﻮن ‪ A‬ﺑﻪ ﻛﻼسﻫﺎي ‪ derive‬ﺷﺪه ﺣﻖ اﺳﺘﻔﺎده از ‪private‬ﻫﺎي ﺧﻮدش را ﻧﻤﻲدﻫﺪ‪ .‬وﻟﻲ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻣﺘﻐﻴﺮي‬ ‫در ‪ A‬ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ ﻛﻪ ﻫﻢ ‪ private‬ﺑﺎﺷﺪ و ﻫﻢ ﺑﻪ ارث ﺑﺮده ﺷﻮد ﺑﺎﻳﺪ ﭼﻪ ﺑﻜﻨﻴﻢ؟‬ ‫ﺑﻪ ﻛﻠﻤﺎت ﻛﻠﻴﺪي ‪ public‬و ‪) access specifier ،private‬ﺑﺨﻮاﻧﻴﺪ »اك ﺳﺲ اس ﭘﻪ ﺳﻲ ﻓﺎﻳﺮ «‬

‫(‬

‫ﻣﻲﮔﻮﻳﻨﺪ‪ .‬ﻋﻼوه ﺑﺮ ‪ public‬و ‪ private‬ﻳﻚ ‪ ِ access specifier‬دﻳﮕﺮ ﻫﻢ ﻫﺴﺖ و آن ‪protected‬‬

‫اﺳﺖ‪ protected .‬ﻫﻤﺎن ﭼﻴﺰي اﺳﺖ ﻛﻪ ﺑﻪ دﻧﺒﺎﻟﺶ ﻫﺴﺘﻴﻢ‪ .‬اﻳﻦ ‪ access specifier‬در واﻗﻊ ﻫﻤﺎن‬ ‫‪ private‬اﺳﺖ ﻛﻪ اﺟﺎزهي ‪)inheritance‬ﻳﻌﻨﻲ ﺑﻪ ارث ﺑﺮدن( را ﻫﻢ ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬

‫‪244‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫{‬ ‫‪private:‬‬ ‫;‪int a‬‬ ‫;‪int b‬‬ ‫‪protected:‬‬ ‫;‪char ch‬‬ ‫;}‬ ‫‪class B : public A‬‬ ‫{‬ ‫)(‪void f‬‬ ‫{‬ ‫;'‪ch = 'a‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫‪cout<< sizeof(A) << endl; // output: 12‬‬ ‫‪cout<< sizeof(B) << endl; // output: 12‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪12‬‬ ‫‪12‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ‪ ch‬در )(‪ f‬ﻗﺎﺑﻞ دﺳﺘﺮﺳﻲ اﺳﺖ‪ .‬ﺑﻪ ﺧﺮوﺟﻲ ﻛﻪ اﻧﺪازهي )‪ (size‬ﻛﻼسﻫﺎي ‪ A‬و ‪ B‬را ﻧﺸﺎن ﻣﻲدﻫﺪ‪،‬‬ ‫ﻧﮕﺎه ﻛﻨﻴﺪ‪ .‬اﻧﺪازهي ﻛﻼس ‪ A‬ﺑﺮاﺑﺮ ﺑﺎ ‪ 12‬اﺳﺖ‪ .‬ﺷﺎﻳﺪ ﺑﭙﺮﺳﻴﺪ ﻛﻪ ﭼﺮا اﻳﻦ ﻃﻮر اﺳﺖ وﻗﺘﻲ ‪ A‬ﻓﻘﻂ دو _‪int Z‬‬

‫ﭼﻬﺎر ﺑﺎﻳﺘﻲ و \‪ char n‬ﻳﻚ ﺑﺎﻳﺘﻲ دارد ﻛﻪ روي ﻫﻢ ‪ 9‬ﺑﺎﻳﺖ ﻫﺴﺘﻨﺪ؟ ﻋﻠﺖ اﻳﻦ اﺳﺖ ﻛﻪ اﻧﺪازهي ﻳﻚ ﻛﻼس‬ ‫ﻣﻀﺮﺑﻲ از ﺑﺰرگ ﺗﺮﻳﻦ اﻧﺪازهي ﻣﺘﻐﻴﺮﻫﺎي ﻃﺒﻴﻌﻲ آن اﺳﺖ )اﮔﺮ ﻣﺘﻐﻴﺮي از ﻧﻮع ﻛﻼس دﻳﮕﺮي ﻫﻢ ﺑﺎﺷﺪ ﺑﺎﻳﺪ ﺑﻴﻦ‬ ‫ﻣﺘﻐﻴﺮﻫﺎي ﻃﺒﻴﻌﻲ آن ﻛﻼس ﻫﻢ ﮔﺸﺖ و ﺑﺰرگ ﺗﺮﻳﻦ اﻧﺪازه را ﭘﻴﺪا ﻛﺮد(‪ .‬ﻣﻨﻈﻮر از ﻣﺘﻐﻴﺮ ﻃﺒﻴﻌﻲ‪ ،‬ﻣﺘﻐﻴﺮي از ﻧﻮع‪-‬‬ ‫ﻫﺎي اوﻟﻴﻪ )ﻣﺜﻞ ‪ float ،double ،int‬و‪ (...‬اﺳﺖ‪ .‬اﻧﺪازهي ﻛﻼس ‪ B‬ﻫﻢ ﺑﺎ اﻧﺪازهي ﻛﻼس ‪ A‬ﺑﺮاﺑﺮ اﺳﺖ اﮔﺮ‬ ‫ﭼﻪ ﺑﻪ ﻳﻜﻲ از ﻣﺘﻐﻴﺮﻫﺎي ‪ A‬دﺳﺘﺮﺳﻲ ﻧﺪارد‪.‬‬ ‫ﺑﻪ ﺗﺮﺗﻴﺐ آزادي دﺳﺘﺮﺳﻲ ﻣﻲﺷﻮد ﻧﻮﺷﺖ ‪ .private < protected < public‬ﻳﻚ ﻛﻼس ﻋﻼوه ﺑﺮ‬ ‫‪ public‬ﻣﻲﺗﻮاﻧﺪ ﺑﻪ ﻃﻮر ‪ private‬ﻳﺎ ‪ protected‬ﻫﻢ ‪ derive‬ﺑﺸﻮد‪.‬‬ ‫ﺗﺎ اﻳﻦ ﺟﺎ ﻣﻲداﻧﻴﻢ وﻗﺘﻲ ﻛﻼس ‪ B‬از ﻛﻼس ‪) A‬ﺑﻪ ﻃﻮر ‪ public) derive‬ﻣﻲﺷﻮد ﻫﻤﻪي اﻋﻀﺎي ﻏﻴﺮ ‪ِ private‬‬ ‫‪ A‬ﺑﻪ ‪ B‬اﺿﺎﻓﻪ ﻣﻲﺷﻮﻧﺪ‪ .‬ﺣﺎﻻ اﮔﺮ ﻛﻼس ‪ B‬از ﻛﻼس ‪ A‬ﺑﻪ ﺻﻮرت ‪ derive ،private‬ﺷﻮد‪ ،‬اﻋﻀﺎي ‪private‬‬ ‫ِ ‪ A‬ﺑﻪ ‪ B‬اﺿﺎﻓﻪ ﻧﻤﻲﺷﻮﻧﺪ و ﺑﻘﻴﻪي اﻋﻀﺎي ‪ A‬ﺑﻪ ﻣﺤﺪودهي ‪ private‬در ‪ B‬اﺿﺎﻓﻪ ﻣﻲﺷﻮﻧﺪ‪:‬‬ ‫>‪#include <conio.h‬‬

‫‪245‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <iostream> using namespace std; class A { private: int a; protected: int b; public: int c; }; class B: private A { public: void f() { //a = 1; // error b = 2; c = 3; } }; class C: private B { public: void g() { //a = 1; // error //b = 2; // error //c = 3; // error } }; int main() { B b; //b.a = 1; // error //b.b = 2; // error //b.c = 3; // error b.f(); _getch(); }

Output: empty A ‫ دﺳﺘﺮﺳﻲ ﻧﺪارد ﭼﻮن در ﻛﻼس‬a ‫ ﺑﻪ‬B::f() .‫ دارﻧﺪ‬error ،‫ ﺷﺪه‬comment out ‫ﺑﺨﺶﻫﺎﻳﻲ ﻛﻪ‬

‫ ﺑﻪ ﻃﻮر‬B ‫ ﻫﺴﺘﻨﺪ ) ﭼﻮن‬c) private ‫ و‬b ‫ ) ﻳﻌﻨﻲ‬B ‫ ﻫﻤﻪي ﻣﺘﻐﻴﺮﻫﺎي‬.‫ اﺳﺖ و ﺑﻪ ارث ﺑﺮده ﻧﻤﻲﺷﻮد‬private ،B ‫ ﻛﻪ از‬C ‫ ﺑﻪ ﻫﻤﻴﻦ ﻋﻠﺖ ﻛﻼس‬.(‫ي ﻧﺪارد‬public ‫ ﻳﺎ‬protected ‫ ﺷﺪه و ﺧﻮدش ﻣﺘﻐﻴﺮ‬derive ،private -‫ ﺑﺮاي اﻳﻦ ﻛﻪ ﺑﻬﺘﺮ اﻳﻦ ﻣﺜﺎل را درك ﻛﻨﻴﺪ ﻣﻲﺗﻮاﻧﻢ ﺑﮕﻮﻳﻢ ﻛﻼس‬.‫ ﻋﻤﻼ ﻫﻴﭻ ﻣﺘﻐﻴﺮي ﻧﺪارد‬،‫ ﺷﺪه اﺳﺖ‬derive :‫ ﻋﻤﻼ ﺑﻪ اﻳﻦ ﺷﻜﻞ ﻫﺴﺘﻨﺪ‬C ‫ و‬B ‫ﻫﺎي‬ class B

246

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { private: int b; int c; public: void f() { //a = 1; // error b = 2; c = 3; } }; class C { private: void f() { //a b = c = } public: void g() { //a //b //c } };

= 1; // error 2; 3;

= 1; // error = 2; // error = 3; // error

.‫ اﺿﺎﻓﻪ ﺷﺪهاﻧﺪ‬private ‫ ﺑﻪ ﺑﺨﺶ‬A ‫ اﺿﺎﻓﻪ ﻧﺸﺪهاﻧﺪ ﺑﻘﻴﻪي اﻋﻀﺎي‬B ‫ ﺑﻪ‬A ‫ در‬private ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ اﻋﻀﺎي‬ -‫ اﺿﺎﻓﻪ ﻧﻤﻲ‬B ‫ ﺑﻪ‬A ِ private ‫ اﻋﻀﺎي‬،‫ ﺑﺸﻮد‬derive ،protected ‫ ﺑﻪ ﺻﻮرت‬A ‫ از ﻛﻼس‬B ‫اﮔﺮ ﻛﻼس‬ :‫ اﺿﺎﻓﻪ ﻣﻲﺷﻮﻧﺪ‬B ‫ در‬protected ‫ ﺑﻪ ﻣﺤﺪودهي‬A ‫ﺷﻮﻧﺪ و ﺑﻘﻴﻪي اﻋﻀﺎي‬ #include <conio.h> #include <iostream> using namespace std; class A { private: int a; protected: int b; public: int c; }; class B: protected A { public: void f() { //a = 1; //error

247

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ b = 2; c = 3; } }; class C: protected B { public: void f() { // a = 1; //error b = 2; c = 3; } }; int main() { B b; //b.a = 1; //error //b.b = 2; //error //b.c = 3; //error b.f(); _getch(); }

Output: empty

:‫ در ﻋﻤﻞ ﺑﻪ اﻳﻦ ﺷﻜﻞ اﺳﺖ‬B ‫در اﻳﻦ ﻣﺜﺎل ﻛﻼس‬ class B: protected A { protected: int b; int c; public: void f() { //a = 1; //error b = 2; c = 3; } };

.‫ اﺿﺎﻓﻪ ﻧﻤﻲﺷﻮﻧﺪ‬B ‫ ﺑﻪ‬A ِ private ‫ اﻋﻀﺎي‬،‫ ﺷﻮد‬derive ،public ‫ ﺑﻪ ﺻﻮرت‬A ‫ از ﻛﻼس‬B ‫اﮔﺮ ﻛﻼس‬ ‫ ﻫﻢ ﺑﻪ‬A ِ public ‫ اﺿﺎﻓﻪ ﻣﻲﺷﻮﻧﺪ و اﻋﻀﺎي‬B ِ protected ‫ ﺑﻪ ﻣﺤﺪودهي‬،A ِ protected ‫اﻋﻀﺎي‬ :‫ اﺿﺎﻓﻪ ﻣﻲﺷﻮﻧﺪ‬B ِ public ‫ﻣﺤﺪودهي‬ #include <conio.h> #include <iostream> using namespace std; class A { private:

248

www.pupuol.com


â€Ťď­˜ď­˜ďť? ﺎďş&#x; ﺊďş?ﺸﺎ ďť­ ﺪﺭﺳ‏ int a; protected: int b; public: int c; }; class B: public A { public: void f() { //a = 1; //error b = 2; c = 3; } }; class C: public B { public: void f() { //a = 1; //error b = 2; c = 3; } }; int main() { B b; //b.a = 1; //error //b.b = 2; //error b.c = 3; b.f(); _getch(); }

Output: empty

:‍ ďť‹ ďş‘ ا ﺡďťœďťž اﺳﺖ‏B ‍س‏S ‍ ل‏F 01‍دع ا‏ class B: public A { protected: int b; public: int c; void f() { //a = 1; //error b = 2; c = 3; } };

249

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ :‫ ﺑﺸﻮد‬derive ‫ﻳﻚ ﻛﻼس ﻣﻲﺗﻮاﻧﺪ از ﭼﻨﺪ ﻛﻼس‬ #include <conio.h> #include <iostream> using namespace std; class A { private: int a; protected: int b; public: int c; }; class B { private: int d; protected: int e; public: int f; }; class C: public B, protected A { void g() { //a = 4; //error b = 4; } }; int main() { cout<< sizeof(C) << " = " << sizeof(A) << " + " << sizeof(B); C c; c.f = 4; _getch(); }

Output: 24 = 12 + 12

‫ ﺑﺎ ﺗﻮﺟﻪ ﺑﻪ اﻳﻦ ﻛﻪ در‬.‫ ﺷﺪه‬derive ،protected ‫ ﺑﻪ ﻃﻮر‬A ‫ و از‬public ‫ ﺑﻪ ﻃﻮر‬B ‫ از‬C ‫در اﻳﻦ ﺟﺎ ﻛﻼس‬ ‫ ﻫﻤﻪي‬C .‫ اﺳﺖ‬B ‫ و‬A ‫ ﺑﺮاﺑﺮ ﺑﺎ ﻣﺠﻤﻮع اﻧﺪازهي ﻛﻼسﻫﺎي‬C ‫ اﻧﺪازهي‬،‫ ﻣﺴﺘﻘﻴﻤﺎ ﻫﻴﭻ ﻣﺘﻐﻴﺮي ﺗﻌﺮﻳﻒ ﻧﺸﺪه‬C ‫ﺧﻮد‬ .‫ را در اﺧﺘﻴﺎر دارد‬B ‫ و‬A ‫ ﻛﻼسﻫﺎي‬private ‫ﻣﺘﻐﻴﺮﻫﺎي ﻏﻴﺮ‬ :‫ﻛﻼسﻫﺎي ﻣﺜﺎل ﻗـﺒﻞ را ﺑﺎ ﻧﻤﻮدار زﻳﺮ ﻧﺸﺎن ﻣﻲدﻫﻢ‬

250

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫ ﺑﻪ اﻳﻦ‬.‫ اﺳﺖ‬private ‫ و رﻧﮓ ﻗﺮﻣﺰ ﺑﻪ ﻣﻌﻨﻲ‬protected ‫ رﻧﮓ ﻧﺎرﻧﺠﻲ ﺑﻪ ﻣﻌﻨﻲ‬،public ‫رﻧﮓ آﺑﻲ ﺑﻪ ﻣﻌﻨﻲ‬ .‫ )ﺑﺨﻮاﻧﻴﺪ »ﻫﻲ ﻳﺮ آر ﻛﻲ«( ﻣﻲﮔﻮﻳﻴﻢ‬hierarchy ‫ﺟﻮر ﻧﻤﻮدارﻫﺎ‬ -‫ ﻫﻢ ﻓﺮاﺧﻮاﻧﺪه ﻣﻲ‬B ‫ و‬A ‫ﻫﺎي‬constructor ،‫ ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‬C ‫ از ﻧﻮع‬object ‫ ﺑﺎﻻ وﻗﺘﻲ ﻳﻚ‬hierarchy ‫ﺑﺎ‬ :‫ اﻣﺎ ﺑﺎ ﭼﻪ ﺗﺮﺗﻴﺒﻲ؟ ﺑﻪ ﻣﺜﺎل زﻳﺮ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‬.‫ﺷﻮﻧﺪ‬ #include <conio.h> #include <iostream> using namespace std; class A { public: A() { cout<< } ~A() { cout<< } }; class B { public: B() { cout<< } ~B() { cout<< } }; class C: public B, { public: C() {

"A constructor\n";

"A destructor\n";

"B constructor\n";

"B destructor\n"; protected A

251

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ cout<< "C constructor\n"; } ~C() { cout<< "C destructor\n"; } }; int main() { {

// a block C c;

} _getch(); }

Output: B constructor A constructor C constructor C destructor A destructor B destructor

.‫ ﻓﺮاﺧﻮاﻧﺪه ﺷﺪهاﻧﺪ‬A ‫ و‬B ‫ﻫﺎي‬constructor ‫ ﺑﺎ ﻫﻤﻴﻦ ﺗﺮﺗﻴﺐ‬.‫ ﺷﺪه‬A derive ‫ و ﺑﻌﺪ از‬B ‫ ﺑﻪ ﺗﺮﺗﻴﺐ اول از‬C ‫ﻫﺎ دﻗﻴﻘﺎ ﻋﻜﺲ ﻓﺮاﺧﻮاﻧﻲ‬destructor ‫ ﻣﻲﺑﻴﻨﻴﺪ ﺗﺮﺗﻴﺐ ﻓﺮاﺧﻮاﻧﻲ‬.‫ ﻓﺮاﺧﻮاﻧﺪه ﺷﺪه‬constructor C ‫ﺑﻌﺪ‬ .‫ﻫﺎﺳﺖ‬constructor ‫ ﭘﺎراﻣﺘﺮدار داﺷﺘﻪ ﺑﺎﺷﺪ ﭼﮕﻮﻧﻪ ﺑﺎﻳﺪ آن را ﻓﺮا ﺧﻮاﻧﺪ؟ ﺑﺮاي اﻳﻦ ﻛﺎر ﺑﺎﻳﺪ‬B constructor ‫ ﻳﺎ‬A ‫ﺣﺎﻻ اﮔﺮ‬ :‫ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‬.‫ اﻳﺠﺎد ﺷﻮد‬C ‫ ﺑﺮاي دادن ﭘﺎراﻣﺘﺮﻫﺎ در ﻛﻼس‬،‫ ﻣﻨﺎﺳﺐ‬constructor #include <conio.h> #include <iostream> using namespace std; class A { public: A(int a, int b) { cout<< "A constructor:\n"; cout<< a << endl; // output: 1387 cout<< b << "\n\n"; // output: 12 } }; class B { public: B(int twelve) { cout<< "B constructor:\n"; cout<< twelve << "\n\n"; // output: 12

252

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ } }; class C: public B, public A { public: int x; C(int a, int b, int c): A(a,b), B(12), x(21) { cout<< "C constructor:\n"; cout<< c << "\n\n"; // output: 2 } }; int main() { C c(1387,12,2); cout<< "x equals: " << c.x; // output: x equals 21 _getch(); }

Output: B constructor: 12 A constructor: 1387 12 C constructor: 2 x equals: 21

- base ‫ ﻛﻼسﻫﺎﺳﺖ )در اﻳﻦ ﻣﺜﺎل‬- base ‫ ﻣﻨﺎﺳﺐ ﻧﻮﻋﻲ ﻣﻘﺪار اوﻟﻴﻪ دادن ﺑﻪ‬constructor ‫ ﻓﺮاﺧﻮاﻧﺪن‬،‫ﭘﺲ‬ ‫ را ﻫﻢ ﻣﻲﺷﻮد ﺑﻪ ﻫﻤﻴﻦ ﺷﻴﻮه ﻓﺮاﺧﻮاﻧﺪ اﻣﺎ ﻓﺮا ﺧﻮاﻧﺪن آن ﻻزم‬default constructor .(‫ ﻫﺴﺘﻨﺪ‬B ‫ و‬A ‫ﻛﻼسﻫﺎ‬ ‫ )در ﺻﻮرت ﻋﺪم ﻓﺮاﺧﻮاﻧﻲ‬default constructor ‫ﻧﻴﺴﺖ ﭼﻮن ﻫﻤﺎن ﻃﻮر در ﻣﺜﺎلﻫﺎي ﻗﺒﻠﻲ دﻳﺪﻳﺪ ﻛﻪ‬ .‫ﻫﺎي دﻳﮕﺮ( ﺧﻮد ﺑﻪ ﺧﻮد ﻓﺮاﺧﻮاﻧﺪه ﻣﻲﺷﻮد‬constructor ‫اﮔﺮ در‬

253

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫ي ﻣﻮﺟﻮد در‬a ‫ ﺑﻪ‬b.a ‫ ﺑﺎﺷﺪ آن وﻗﺖ‬B ‫ ﺑﺎ ﻧﻮع‬object ‫ ﻳﻚ‬b ‫ داﺷﺘﻪ ﺑﺎﺷﻨﺪ و‬a ‫ ﻫﺮ ﻛﺪام ﻋﻀﻮي ﺑﺎ اﺳﻢ‬B ‫ و‬A :‫ ﺑﺎﻳﺪ از اﺳﻢ ﻛﺎﻣﻞ اﺳﺘﻔﺎده ﻛﻨﻴﻢ‬A ‫ي ﻣﻮﺟﻮد در‬a ‫ ﺑﺮاي دﺳﺘﺮﺳﻲ ﺑﻪ‬.‫ اﺷﺎره دارد‬B #include <conio.h> #include <iostream> using namespace std; class A { public: int a; A():a(0) {} }; class B: public A { public: int a; }; int main() { B b; b.a = 123456; cout<< b.A::a << endl; cout<< b.B::a; _getch(); }

Output: 0 123456

‫در ﺣﻘﻴﻘﺖ در‬

254

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫وﻗﺘﻲ ‪ B‬از اﺳﻤﻲ اﺳﺘﻔﺎده ﻛﻨﺪ‪ ،‬ﻫﻤﻪي اﻋﻀﺎي ‪ A‬ﺑﺎ آن اﺳﻢ )در ‪object‬ﻫﺎي ‪ B) hide‬ﻣﻲﺷﻮﻧﺪ )ﻳﻌﻨﻲ ﭘﻨﻬﺎن ﻣﻲ‪-‬‬ ‫ﺷﻮﻧﺪ(‪ .‬ﻣﺜﻼ اﮔﺮ ‪ int n\ B‬ﺑﺎ اﺳﻢ ‪ w‬داﺷﺘﻪ ﺑﺎﺷﺪ ﻫﻤﻪي ﻣﺘﻐﻴﺮﻫﺎ و ﺗﺎﺑﻊﻫﺎي ‪ A‬ﺑﺎ ﻧﺎم ‪ hide ،w‬ﻣﻲﺷﻮﻧﺪ‪ .‬ﺑﺮاي‬ ‫دﺳﺘﺮﺳﻲ ﺑﻪ اﻋﻀﺎي ‪ hide‬ﺷﺪه ﺑﺎﻳﺪ ﺣﺘﻤﺎ از اﺳﻢ ﻛﺎﻣﻞ آنﻫﺎ اﺳﺘﻔﺎده ﻛﺮد‪ .‬اﻳﻦ ﻣﺜﺎل را ﺑﺒﻴﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫)‪void w(int‬‬ ‫{‬ ‫;"‪cout<< "A::w()\n‬‬ ‫}‬ ‫;}‬ ‫‪class B: public A‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int w‬‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪B b‬‬ ‫‪// b.w(31415); // error‬‬ ‫;‪b.w = 5‬‬ ‫;)‪b.A::w(31415‬‬ ‫;‪cout<< b.B::w‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫)(‪A::w‬‬ ‫‪5‬‬

‫‪255‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪method‬ه ‪virtual‬‬

‫اﻳﻦ ‪ hierarchy‬را در ﻧﻈﺮ ﺑﮕﻴﺮﻳﺪ‬

‫ﺣﺎﻓﻈﻪاي ﻛﻪ ﺑﻪ ﻫﺮ ‪ object‬ﺑﺎ ﻧﻮع ‪ B‬داده ﻣﻲﺷﻮد ﺑﻪ اﻳﻦ ﺻﻮرت اﺳﺖ‪:‬‬

‫‪point‬‬

‫‪B‬‬

‫‪A‬‬

‫ﭘﺲ ﻫﺮ ‪pointer‬ي ﻛﻪ ﺑﻪ اول ﺣﺎﻓﻈﻪي ﻳﻚ ‪ object‬ﺑﺎ ﻧﻮع ‪ B‬اﺷﺎره دارد‪ ،‬ﺑﻪ اول ﺣﺎﻓﻈﻪي ﻳﻚ ‪ object‬ﺑﺎ ﻧﻮع‬ ‫‪ A‬ﻫﻢ اﺷﺎره دارد‪ .‬ﺑﻪ زﺑﺎن ﺳﺎده ﻫﺮ ‪ pointer‬ﺑﻪ \‪B pointer n‬ي ﺑﻪ \‪ A n‬اﺳﺖ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int a‬‬ ‫)(‪void f‬‬ ‫{‬ ‫;"‪cout<< "A::f()\n‬‬ ‫}‬ ‫;}‬ ‫‪class B: public A‬‬

‫‪256‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { public: int a; void f() { cout<< "B::f()\n"; } }; int main() { B b; b.A::a = 1; b.B::a = 2; A* pA = &b; B* pB = &b; pA -> f(); pB -> f(); cout<< pA -> a << endl; cout<< pB -> a; _getch(); }

Output: A::f() B::f() 1 2

‫ ذﺧﻴﺮه‬B ‫ ﺑﻪ‬pointer ‫ و در ﻳﻚ‬A ‫ ﺑﻪ‬pointer ‫ ﺗﻌﺮﻳﻒ ﺷﺪه و آدرس آن در ﻳﻚ‬B ‫در اﻳﻦ ﺟﺎ ﻣﺘﻐﻴﺮي از ﻧﻮع‬ ‫ و‬A ‫ اﻋﻀﺎي‬A ‫ ﺑﻪ‬pointer ‫ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬.‫ ﻓﺮاﺧﻮاﻧﺪه ﺷﺪه‬f() ‫ و ﺗﺎﺑﻊ‬a ‫ﻫﺎ ﻣﺘﻐﻴﺮ‬pointer ‫ ﺑﻪ وﺳﻴﻠﻪي اﻳﻦ‬.‫ﺷﺪه‬ :‫ﻫﺎ ﻫﻢ درﺳﺖ اﺳﺖ‬reference ‫ ﻫﻤﻴﻦ در ﻣﻮرد‬.‫ را ﻓﺮا ﻣﻲﺧﻮاﻧﺪ‬B ‫ اﻋﻀﺎي‬B ‫ ﺑﻪ‬pointer #include <conio.h> #include <iostream> using namespace std; class A { public: int a; void f() { cout<< "A::f()\n"; } }; class B: public A { public: int a; void f()

257

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { cout<< "B::f()\n"; } }; int main() { B b; b.A::a = 1; b.B::a = 2; A& rA = b; B& rB = b; rA.f(); rB.f(); cout<< rA.a << endl; cout<< rB.a; _getch(); }

Output: A::f() B::f() 1 2

.‫ اﺳﺖ‬B ‫ از ﻧﻮع‬b ‫ اﺳﺖ و‬A ‫ي ﺑﻪ‬rA reference ‫ در ﺣﺎﻟﻲ ﻛﻪ‬A& rA = b; ‫ﭼﻴﺰ ﻣﻬﻢ اﻳﻦ اﺳﺖ ﻛﻪ ﻧﻮﺷﺘﻢ‬ ‫ ﺑﻪ‬rA.f() ‫ و‬pA->f() ‫ اﻣﻜﺎﻧﻲ را در اﺧﺘﻴﺎر ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻣﻲﮔﺬارد ﻛﻪ ﺑﺎﻋﺚ ﻣﻲﺷﻮد در دو ﻣﺜﺎل ﺑﺎﻻ‬C++ ( «‫ ل‬-ِ ‫ ر ﭼﻮ و‬-ِ ‫ )ﺑﺨﻮاﻧﻴﺪ »و‬virtual ‫ را‬A ‫ اﮔﺮ ﺗﺎﺑﻊ ﻣﻮﺟﻮد در‬.‫ را ﻓﺮاﺑﺨﻮاﻧﻨﺪ‬B::f() ،A::f() ‫ﺟﺎي‬ :‫ دوﺑﺎره اﺟﺮا ﻣﻲﻛﻨﻢ‬f() ‫ ﻛﺮدن‬virtual ‫ دو ﻣﺜﺎل ﺑﺎﻻ را ﺑﺎ‬.‫ﻛﻨﻴﻢ اﻳﻦ اﺗﻔﺎق ﻣﻲاﻓﺘﺪ‬ #include <conio.h> #include <iostream> using namespace std; class A { public: int a; virtual void f() { cout<< "A::f()\n"; } }; class B: public A { public: int a; void f() {

258

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ cout<< "B::f()\n"; } }; int main() { B b; b.A::a = 1; b.B::a = 2; A* pA = &b; B* pB = &b; pA -> f(); pB -> f(); cout<< pA -> a << endl; cout<< pB -> a; _getch(); }

Output: B::f() B::f() 1 2

‫ ﺑﻪ‬pointer ‫ وﻗﺘﻲ ﻳﻚ‬.‫ ﺷﺪه‬virtual ‫ اﻳﻦ ﺗﺎﺑﻊ‬A ‫ در‬f() ‫ ﺟﻠﻮي ﺗﺎﺑﻊ‬virtual ‫ﺑﺎ ﻧﻮﺷﺘﻦ ﻛﻠﻤﻪي ﻛﻠﻴﺪي‬ ‫ ﻫﻤﻴﻦ‬.‫ را ﻓﺮا ﺧﻮاﻧﺪ‬B ‫ ﻣﻮﺟﻮد در‬f() ‫ ﺑﺎ آن ﻣﻲﺷﻮد‬،‫ ﻣﻲﺷﻮد‬cast ،A ‫ ﺑﻪ‬pointer ‫ ﺑﻪ ﻳﻚ‬B ‫ از‬object ‫ﻳﻚ‬ :‫ﻫﺎ ﻣﻲاﻓﺘﺪ‬reference ‫اﺗﻔﺎق در ﻣﻮرد‬ #include <conio.h> #include <iostream> using namespace std; class A { public: int a; virtual void f(); }; void A::f() { cout<< "A::f()\n"; } class B: public A { public: int a; void f() { cout<< "B::f()\n"; } };

259

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ int main() { B b; b.A::a = 1; b.B::a = 2; A& rA = b; B& rB = b; rA.f(); rB.f(); cout<< rA.a << endl; cout<< rB.a; _getch(); }

Output: B::f() B::f() 1 2

‫ ﺗﻨﻬﺎ در‬virtual ‫ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻛﻠﻤﻪي ﻛﻠﻴﺪي‬.‫ ﺗﻌﺮﻳﻒ ﺷﺪه‬A ‫ در ﺧﺎرج ار ﻛﻼس‬virtual f() ‫ﺗﺎﺑﻊ‬ .‫ وﺟﻮد دارد‬prototype

‫ رو ﺑﻪ رو اﮔﺮ در‬hierarchy ‫ ﻣﺜﻼ در‬.‫ ﺑﻮدن ﺑﻪ ارث ﻣﻲرﺳﺪ‬virtual ‫ اﻳﻦ ﺗﺎﺑﻊ ﺑﺮاي‬،‫ ﺗﻌﺮﻳﻒ ﺷﺪه ﺑﺎﺷﺪ‬virtual ‫ ﺑﻪ ﺻﻮرت‬f() ‫ ﺗﺎﺑﻊ‬A ‫ ﺑﻪ ﻣﺜﺎل ﺑﻌﺪي‬.‫ ﺑﻪ ﺣﺴﺎب ﻣﻲآﻳﺪ‬virtual ‫ ﻫﻢ‬C ‫ﻫﺎي ﺑﺎ ﻧﻮع‬object :‫ﻧﮕﺎه ﻛﻨﻴﺪ‬

#include <conio.h> #include <iostream> using namespace std; class A

260

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { public: virtual void f() { cout<< "A::f()\n"; } }; class B: public A { public: void f() { cout<< "B::f()\n"; } }; class C: public B { public: void f() { cout<< "C::f()\n"; } }; int main() { C c; A& rA = c; B& rB = c; C& rC = c; rA.f(); rB.f(); rC.f(); _getch(); }

Output: C::f() C::f() C::f()

:‫ ﺧﺮوﺟﻲ ﺑﻪ ﺻﻮرت زﻳﺮ ﺗﻐﻴﻴﺮ ﻣﻲﻛﻨﺪ‬،‫ ﻛﻨﻴﻢ‬virtual ‫ را‬B::f() ،A::f()‫ ﻛﺮدن‬virtual ‫ﺣﺎل اﮔﺮ ﺑﻪ ﺟﺎي‬ A::f() C::f() C::f()

:‫ ﻧﺪاﺷﺘﻪ ﺑﺎﺷﺪ ﺧﺮوﺟﻲ ﺗﻐﻴﻴﺮ ﻧﻤﻲﻛﻨﺪ‬f() ‫ )ﻣﺴﺘﻘﻴﻤﺎ( ﺗﺎﺑﻊ‬B ‫ ﺑﺎﺷﺪ و ﻛﻼس‬A::f() virtual ‫وﻟﻲ اﮔﺮ‬ #include <conio.h> #include <iostream>

261

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫)(‪virtual void f‬‬ ‫{‬ ‫;"‪cout<< "A::f()\n‬‬ ‫}‬ ‫;}‬ ‫‪class B: public A‬‬ ‫;}{‬ ‫‪class C: public B‬‬ ‫{‬ ‫‪public:‬‬ ‫)(‪void f‬‬ ‫{‬ ‫;"‪cout<< "C::f()\n‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪C c‬‬ ‫;‪A& rA = c‬‬ ‫;‪B& rB = c‬‬ ‫;‪C& rC = c‬‬ ‫;)(‪rA.f‬‬ ‫;)(‪rB.f‬‬ ‫;)(‪rC.f‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫)(‪C::f‬‬ ‫)(‪C::f‬‬ ‫)(‪C::f‬‬

‫اﻟﺒﺘﻪ ﺑﺎ )(‪ A::f() ،rA.A::f‬ﺧﻮاﻧﺪه ﻣﻲﺷﻮد و ‪ virtual‬ﺑﻮدن وﻗﺘﻲ ﻣﺆﺛﺮ اﺳﺖ ﻛﻪ اﺳﻢ ﻛﺎﻣﻞ ﺑﻴﺎن ﻧﺸﻮد‪.‬‬ ‫ﮔﻔﺘﻪ ﻣﻲﺷﻮد ﻛﻪ ‪compiler‬ﻫﺎ ﺑﺮاي اﻳﺠﺎد ﻳﻚ ﺗﺎﺑﻊ ِ ‪ ،virtual‬ﻳﻚ ‪) v-table‬ﻳﺎ ‪virtual function‬‬ ‫‪ (table‬اﻳﺠﺎد ﻣﻲﻛﻨﻨﺪ ﺗﺎ ﺗﺎﺑﻊﻫﺎي ‪ virtual‬درﺳﺖ ﻓﺮا ﺧﻮاﻧﺪه ﺷﻮﻧﺪ‪ .‬اﻳﺠﺎد ﻫﻤﭽﻴﻦ ‪table‬ي ﻫﺰﻳﻨﻪي ﺣﺎﻓﻈﻪاي‬ ‫دارد وﻟﻲ ﺑﻪ ﻣﺤﺾ اﻳﺠﺎد آن ﺑﻴﺶ ﺗﺮ ﻫﺰﻳﻨﻪ اﻧﺠﺎم ﺷﺪه و ‪ virtual‬ﻛﺮدن ﺑﻘﻴﻪي ‪method‬ﻫﺎي ﻛﻼس ﻫﺰﻳﻨﻪي‬ ‫ﺑﺴﻴﺎر ﻛﻢ ﺗﺮي دارد‪ .‬ﻛﻼﺳﻲ ﻛﻪ ﺑﺮاي آن ‪ v-table‬وﺟﻮد دارد )ﻳﻌﻨﻲ ﺗﺎﺑﻊ ‪ virtual‬دارد( ‪polymorphic‬‬

‫‪262‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ﻛﻼسﻫﺎ ﻫﻢ ﺑﻪ ارث رﺳﻴﺪه ﺑﺎﺷﺪ ﺑﺎز ﻫﻢ ﻣﻲﮔﻮﻳﻴﻢ‬- base ‫ ﻣﻮرد ﻧﻈﺮ از‬virtual ‫ ﺣﺘﻲ اﮔﺮ ﺗﺎﺑﻊ‬.‫ﻧﺎﻣﻴﺪه ﻣﻲﺷﻮد‬ .‫ اﺳﺖ‬polymorphic ‫ﻛﻼس‬

virtual destructor

:‫ رو ﺑﻪ رو اﮔﺮ ﺑﻨﻮﻳﺴﻴﻢ‬hierarchy ‫ﺑﺎ‬ A* pA = new B; delete pA;

‫ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻋﻼوه‬.‫ ﻓﺮاﺧﻮاﻧﺪه ﻣﻲﺷﻮد‬A ‫ ِ ﻛﻼس‬destructor ‫ﺗﻨﻬﺎ‬ ‫ ﻫﻢ ﻓﺮاﺧﻮاﻧﺪه‬B ‫ ِ ﻛﻼس‬A destructor ‫ ِ ﻛﻼس‬destructor ‫ﺑﺮ‬ ‫ ﺑﺮﻧﺎﻣﻪي زﻳﺮ اﻳﻦ را‬.‫ ﻛﻨﻴﻢ‬virtual ‫ را‬A ِ destructor ‫ ﺑﺎﻳﺪ‬،‫ﺷﻮد‬ :‫ﻧﺸﺎن ﻣﻲدﻫﺪ‬

#include <conio.h> #include <iostream> using namespace std; class A { public: A() { cout<< "A constructor\n"; } virtual ~A() { cout<< "A destructor\n"; } }; class B: public A { public: B() {

263

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ cout<< "B constructor\n"; } ~B() { cout<< "B destructor\n"; } }; class C: public B { public: C() { cout<< "C constructor\n"; } ~C() { cout<< "C destructor\n"; } }; int main() { A* c = new C; delete c; _getch(); }

Output: A constructor B constructor C constructor C destructor B destructor A destructor

:‫ را از اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺣﺬف ﻛﻨﻴﻢ ﺧﺮوﺟﻲ ﺑﻪ اﻳﻦ ﺻﻮرت اﺳﺖ‬virtual ‫اﮔﺮ ﻛﻠﻤﻪي‬ A B C A

constructor constructor constructor destructor

.‫ ﺷﻮد‬virtual ‫ ﻫﻢ‬destructor ‫ اﻳﺠﺎد ﺷﺪ ﺑﻬﺘﺮ اﺳﺖ‬v-table ‫ﮔﻔﺘﻪ ﻣﻲﺷﻮد وﻗﺘﻲ ﻳﻚ‬ :‫ دارد‬error ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ‬ #include <conio.h> #include <iostream> using namespace std;

264

www.pupuol.com


тАлянШя╗оянШя╗оя╗Э я╗гя║оя║Яя╗К я║йя║Ня╗зя║╕яоХя║Оя╗й я╗н я╗гя║кя║ня║│я╗ктАм class A { private: virtual ~A() { cout<< "A destructor\n"; _getch(); } }; class B: public A {}; int main() { new B; _getch(); }

Output: error

:тАл я║Ся║Оя╗│я║к я║гя║к╪зя╗Чя╗Ю я╗│я╗Ья╗▓ ╪з╪▓ ╪зя╗│я╗ж ╪п┘И я╗Ыя║О╪▒ ╪▒╪з я╗Ыя║о╪птАмerror тАля║Ся║о╪з┘К я║Ся║о я╗Гя║о┘Б я║╖я║к┘ЖтАм .public тАл~ ╪п╪▒ я╗гя║дя║к┘И╪п┘З┘КтАмA() тАл( я╗Чя║о╪з╪▒ ╪п╪з╪п┘ЖтАм1 .virtual тАл( я║гя║м┘Б я╗Ыя╗ая╗дя╗к┘КтАм2

dynamic_cast

.тАл я║гя║оя╗Ыя║Ц я╗Ыя║о╪птАмhierarchy Q1 тАл =!╪п ╪п╪▒тАмdynamic_cast тАл ╪з╪▓тАм%тАл( ╪птАм84тАл ╪зтАм :тАл ╪▒┘И я║Ся╗к ╪▒┘И я╗зяоХя║О┘З я╗Ыя╗ия╗┤я║ктАмhierarchy тАля║Ся╗ктАм :тАл╪зяоФя║о я║Ся╗ия╗оя╗│я║┤я╗┤я╗втАм A* pA = new N;

тАл я╗Ыя╗ия╗┤я╗в╪ЯтАмX* cast тАл ╪▒╪з я║Ся╗ктАмpA тАля║Ся╗Мя║к ян╝я╗к я║Яя╗о╪▒┘К я║Ся║Оя╗│я║ктАм :тАл╪п╪▒ ┘И╪зя╗Чя╗К я╗Ыя║Оя╗Уя╗▓ ╪зя║│я║Ц я║Ся╗ия╗оя╗│я║┤я╗┤я╗втАм X* pX = (X*) pA;

265

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫راه رﺳﻤﻲ ﺗﺮ آن اﺳﺘﻔﺎده از ‪ static_cast‬اﺳﺖ ﻛﻪ ﻗﺒﻼ ﻣﻌﺮﻓﻲ ﻛﺮده ﺑﻮدم‪.‬‬ ‫ﺣﺎﻻ اﮔﺮ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪B* pB = new B‬‬

‫ﻣﻌﻠﻮم اﺳﺖ ﻛﻪ ‪ pB‬را ﻧﺒﺎﻳﺪ ﺑﻪ ‪ X* cast‬ﻛﺮد وﻟﻲ اﮔﺮ اﻳﻦ ﻛﺎر را ﺑﻜﻨﻴﻢ‪ compiler ،‬اﻳﺮادي ﻧﻤﻲﮔﻴﺮد و ﺗﻨﻬﺎ‬ ‫ﻛﺎري ﻛﻪ ﻣﻲﻛﻨﺪ اﻳﻦ اﺳﺖ ﻛﻪ ﻃﻮل ﺣﺎﻓﻈﻪاي را ﻛﻪ ‪ pointer‬ﺑﻪ آن اﺷﺎره ﻣﻲﻛﻨﺪ ﺗﻐﻴﻴﺮ ﻣﻲدﻫﺪ‪ .‬ﺑﺮاي روﺷﻦ‬ ‫ﺷﺪن ﻣﻄﻠﺐ ﻓﻜﺮ ﻛﻨﻴﺪ ﻛﻪ ‪ B‬ﺣﺎﻓﻈﻪي ﺑﺴﻴﺎر ﻛﻢ ﺗﺮي ﻧﺴﺒﺖ ﺑﻪ ‪ X‬ﻣﻲﮔﻴﺮد‪ .‬در اﻳﻦ ﺻﻮرت ‪ cast‬ﻛﺮدن ‪ pB‬ﺑﻪ‬ ‫‪pointer‬ي ﺑﻪ ‪ X‬ﺑﺎﻋـﺚ ﻣﻲﺷﻮد ‪ pB‬ﺑﻪ ﺑﺨﺶﻫﺎﻳﻲ ازﺣﺎﻓﻈﻪ اﺷﺎره داﺷﺘﻪ ﺑﺎﺷﺪ ﻛﻪ اﺻﻼ ﺗﺨﺼﻴﺺ داده ﻧﺸﺪهاﻧﺪ‪.‬‬ ‫اﺟﺮاي ﻣﺜﺎل زﻳﺮ ﻛﻪ ‪ hierarchy‬ﺑﺎﻻ را دارد‪ ،‬در ‪ BDS 2006‬ﻳﻚ ‪ exception‬اﻳﺠﺎد ﻣﻲﻛﻨﺪ‪ .‬در ‪Visual‬‬ ‫‪ C++ 2005‬ﻇﺎﻫﺮا ﺑﺪون ﺧﻄﺎ اﺟﺮا ﻣﻲﺷﻮد )ﻫﻤﻮاره در اﻳﻦ ﻧﻮﺷﺘﻪ ﺗﻨﻈﻴﻤﺎت ‪ default‬در ﻧﻈﺮ ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد‬ ‫ﻣﮕﺮ آن ﻛﻪ ﮔﻔﺘﻪ ﺷﻮد(‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬ ‫;}{‬ ‫‪class B: public A‬‬ ‫;}{‬ ‫‪class X‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int x‬‬ ‫;‪int y‬‬ ‫;‪int z‬‬ ‫;‪int u‬‬ ‫;‪int v‬‬ ‫;}‬ ‫‪class Y: public X‬‬ ‫;}{‬ ‫‪class N: public B, public Y‬‬ ‫;}{‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪B* pB = new B‬‬ ‫;‪X* pX = (X*) pB‬‬ ‫‪cout<< sizeof(B) << endl; // output: 8 , 1‬‬ ‫‪cout<< sizeof(X) << endl; // output: 20‬‬ ‫;‪cout<< pX‬‬

‫‪266‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪pX -> v = 8‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪8‬‬ ‫‪20‬‬ ‫‪904358‬‬

‫‪Output (Visual C++ 2005):‬‬ ‫‪1‬‬ ‫‪20‬‬ ‫‪00365D98‬‬ ‫وﻟﻲ اﮔﺮ از ‪ static_cast‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ ،‬ﻫﻴﭻ ﻳﻚ از دو ‪ compiler‬ﺑﺎﻻ اﺟﺎزهي ‪ cast‬ﻛﺮدن از *‪ B‬ﺑﻪ *‪X‬‬

‫را ﻧﻤﻲدﻫﻨﺪ‪ .‬ﻳﻌﻨﻲ‬ ‫;)‪X* pX = static_cast<X*>(pB‬‬

‫ﺧﻄﺎ دارد‪ .‬ﺑﻪ ﺟﺎي آن ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;)‪N* pN = static_cast<N*>(pB‬‬ ‫;)‪X* pX = static_cast<X*>(pN‬‬

‫ﺑﻪ ﻫﺮ ﺣﺎل اﻳﻦ ﭼﻨﺪان ﻣﻄﻠﻮب ﻧﻴﺴﺖ‪ .‬ﭼﺮا ‪ compiler‬ﺑﺎﻳﺪ ‪ cast‬ﻛﻨﺪ در ﺣﺎﻟﻲ ﻛﻪ اﻳﻦ ‪ cast‬ﻛﺮدن ﻣﻤﻜﻦ اﺳﺖ‬ ‫ﻣﻮﺟﺐ اﻳﺠﺎد ‪ run-time error‬ﺑﺸﻮد؟ )‪error ،run-time error‬ي اﺳﺖ ﻛﻪ ﻫﻨﮕﺎم اﺟﺮاي ﺑﺮﻧﺎﻣﻪ )و ﻧﻪ‬ ‫ﻫﻨﮕﺎم ‪ compile‬ﻳﺎ ‪ link‬ﺷﺪن( ﺑﻪ وﺟﻮد ﻣﻲآﻳﺪ(‪.‬‬ ‫ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ dynamic_cast‬ﻣﺸﻜﻞ را ﺣﻞ‬ ‫ﻣﻲﻛﻨﺪ‪ .‬ﻗﺒﻞ از اﻳﻦ ﻛﻪ ﭼﻴﺰي در ﻣﻮرد‬ ‫‪ dynamic_cast‬ﺑﮕﻮﻳﻢ ﺑﺎﻳﺪ ‪ upcast‬و‬ ‫‪ downcast‬را ﻣﻌﺮﻓﻲ ﻛﻨﻢ‪ .‬ﻓﺮض ﻛﻨﻴﺪ ﻳﻚ‬ ‫‪ hierarchy‬ﻣﺜﻞ اﻳﻦ دارﻳﻢ‪:‬‬

‫‪267‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫ در واﻗﻊ‬.‫ اﻧﺠﺎم ﺷﺪه‬upcast ‫ ﻣﻲﮔﻮﻳﻴﻢ ﻳﻚ‬،‫ ﺷﻮد‬X* cast ‫ ﺑﻪ‬Y* ‫ ﺷﻮد ﻳﺎ ﻳﻚ‬A* cast ‫ ﺑﻪ‬B* ‫ ﻳﺎ‬N* ‫اﮔﺮ ﻳﻚ‬ hierarchy ‫ ﭘﺎﻳﻴﻦ آﻣﺪن از‬.(‫ )از راه ﺧﻄﻮط و ﺑﺪون ﭘﺎﻳﻴﻦ آﻣﺪن‬hierarchy ‫ ﻛﺮدن ﻳﻌﻨﻲ ﺑﺎﻻ رﻓﺘﻦ از‬upcast cross-cast ‫ ﺣﺮﻛﺖ ﻛﺮدن از ﻣﺴﻴﺮﻫﺎي ﻋﺠﻴﺐ و ﻏﺮﻳﺐ ﺗﺮ را ﻫﻢ ﻣﻲﺗﻮاﻧﻴﻢ‬.‫ ﮔﻔﺘﻪ ﻣﻲﺷﻮد‬downcast ‫ﻫﻢ‬ .‫ﺑﻨﺎﻣﻴﻢ‬ ‫ ﻓﻘﻂ‬،dynamic_cast ‫ اﺳﺖ وﻟﻲ ﺑﺎ‬static_cast ‫ درﺳﺖ ﻣﺜﻞ‬dynamic_cast ‫روش اﺳﺘﻔﺎده از‬ ‫ ﻛﺮدن ﭼﻴﺰ ﺧﺎص و‬upcast ‫ ﺑﺮاي‬.‫ﻫﺎي ﻛﻼس اﻣﻜﺎن ﭘﺬﻳﺮ اﺳﺖ‬reference ‫ ﻛﻼسﻫﺎ ﻳﺎ‬pointer ‫ﺗﺒﺪﻳﻞﻫﺎي‬ :‫ﻣﻬﻤﻲ ﺑﺮاي ﮔﻔﺘﻦ ﻧﻴﺴﺖ‬ #include <conio.h> #include <iostream> using namespace std; class A {}; class B: public A {}; int main() { B* pB = new B; A* pA = dynamic_cast<A*>(pB); _getch(); }

Output: empty

‫ ﺑﺎﺷﺪ ﻳﻌﻨﻲ ﺣﺪاﻗﻞ ﻳﻚ‬polymorphic ‫ ﺑﺎﻳﺪ ﻛﻼس‬dynamic_cast ‫ ﻛﺮدن ﺑﺎ‬downcast ‫ﺑﺮاي‬ :(‫ ﺑﺎﺷﺪ‬virtual ،destructor ‫ ﻛﻼس ﻣﻨﺎﺳﺐ ﻣﻮﺟﻮد ﺑﺎﺷﺪ )ﻳﺎ‬- base ‫ در ﻳﻚ‬virtual method #include <conio.h> #include <iostream> using namespace std; class A { virtual void f(){}; };

268

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ class B: public A {}; int main() { A* pA = new B; B* pB = dynamic_cast<B*>(pA); cout<< pB; _getch(); }

Output (BDS 2006): 904358 Output (Visual C++ 2005): 00365FB8

‫ اﮔﺮ اﻳﻦ ﻃﻮر‬.‫ ﻛﻨﺪ‬B* cast ‫ ﻣﻲﺗﻮاﻧﺪ آن را ﺑﻪ‬dynamic_cast ،‫ اﺷﺎره دارد‬B ‫ در ﻋﻤﻞ ﺑﻪ ﻳﻚ‬pA ‫ﭼﻮن‬ :‫ ﺗﺸﺨﻴﺺ ﻣﻲداد و ﺻﻔﺮ ﺑﺮﻣﻲﮔﺮداﻧﺪ‬dynamic_cast ‫ﻧﺒﻮد‬ #include <conio.h> #include <iostream> using namespace std; class A { virtual void f(){}; }; class B: public A {}; int main() { A* pA = new A; B* pB = dynamic_cast<B*>(pA); cout<< pB; _getch(); }

Output (BDS 2006): 0 Output (Visual C++ 2005): 00000000

‫ اﻳﻦ ﺑﺮﺗﺮي‬.‫ ﺧﺮوﺟﻲ ﺻﻔﺮ ﻧﻴﺴﺖ‬،‫ ﺑﻨﻮﻳﺴﻴﺪ‬static_cast ،dynamic_cast ‫اﮔﺮ در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﺟﺎي‬ ‫ در ﺣﻴﻦ‬dynamic_cast ‫ ﺑﻪ اﻳﻦ ﻣﻌﻨﻲ اﺳﺖ ﻛﻪ‬dynamic .‫ﻫﺎي دﻳﮕﺮ‬cast ‫ اﺳﺖ ﺑﺮ‬dynamic_cast

269

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫اﺟﺮاي ﺑﺮﻧﺎﻣﻪ )‪ (run-time‬ﺗﺸﺨﻴﺺ ﻣﻲدﻫﺪ ﻛﻪ آﻳﺎ ﺣﺎﻓﻈﻪي ﻻزم وﺟﻮد دارد ﻳﺎ ﻧﻪ و اﮔﺮ ﺣﺎﻓﻈﻪي ﻻزم‬ ‫ﺗﺨﺼﻴﺺ داده ﻧﺸﺪه ﺑﺎﺷﺪ ﺻﻔﺮ ﺑﺮ ﻣﻲﮔﺮداﻧﺪ‪ static_cast .‬ﺣﻴﻦ اﺟﺮاي ﺑﺮﻧﺎﻣﻪ ﺣﺎﻓﻈﻪ را ﭼﻚ ﻧﻤﻲﻛﻨﺪ و ﺑﻪ‬ ‫ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ اﻋﺘﻤﺎد ﻣﻲﻛﻨﺪ‪ .‬ﻣﺜﺎل زﻳﺮ اﻫﻤﻴﺖ ‪ run-time‬ﺑﻮدن را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬ ‫{‬ ‫;}{)(‪virtual void f‬‬ ‫;}‬ ‫‪class B: public A‬‬ ‫;}{‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪A* pA‬‬ ‫;‪int decide‬‬ ‫;‪cin>> decide‬‬ ‫)‪if(decide == 1‬‬ ‫;‪pA = new B‬‬ ‫‪else‬‬ ‫;‪pA = new A‬‬ ‫;)‪B* pB = dynamic_cast<B*>(pA‬‬ ‫;‪cout<< pB‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪1‬‬ ‫‪9245fc‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫‪2‬‬ ‫‪00000000‬‬

‫در اﻳﻦ ﻣﺜﺎل ﺣﻴﻦ ‪ compile‬و ﻗﺒﻞ از اﺟﺮا ﻧﻤﻲﺷﻮد ﺗﺸﺨﻴﺺ داد ﻛﻪ آﻳﺎ ‪ pA‬ﺣﺎﻓﻈﻪي ﻻزم ﺑﺮاي ‪ cast‬ﺷﺪن ﺑﻪ‬ ‫*‪ B‬را دارد ﻳﺎ ﻧﻪ‪ .‬اﻣﺎ ‪ dynamic_cast‬در ﺣﻴﻦ اﺟﺮا آن را ﺗﺸﺨﻴﺺ ﻣﻲدﻫﺪ و ﺑﺮاي ﻫﻤﻴﻦ ‪ dynamic‬اﺳﺖ‬ ‫ﻧﻪ ‪ static. dynamic‬ﻳﻌﻨﻲ »ﭘﻮﻳﺎ« و ‪ static‬ﻳﻌﻨﻲ »اﻳﺴﺘﺎ« )‬

‫(‪ .‬در اﻳﻦ ﻣﺜﺎل ﺑﻪ ﺟﺎي‬ ‫;)‪B* pB = dynamic_cast<B*>(pA‬‬ ‫;‪cout<< pB‬‬

‫ﻣﻲﺗﻮاﻧﺴﺘﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;)‪void* pV = dynamic_cast<void*>(pA‬‬

‫‪270‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ cout<< pV;

‫ي ﺑﻪ ﻛﻞ ﺣﺎﻓﻈﻪي ﺗﺨﺼﻴﺺ داده ﺷﺪه داﺷﺘﻴﻢ در ﺿﻤﻦ ﺑﻌﺪ از‬pointer ‫در اﻳﻦ ﺣﺎﻟﺖ ﺻﻔﺮ ﺑﺮﮔﺮداﻧﺪه ﻧﻤﻲﺷﺪ و‬ ‫آن ﻧﻮﺷﺘﻦ‬ dynamic_cast<B*>(pV);

.‫ ﺑﻪ ﻧﻮع ﻛﻼﺳﻲ ﻧﻴﺴﺖ‬pV pointer ‫ﺧﻄﺎ دارد ﭼﻮن‬ :‫ﻫﺎ ﻫﻢ ﻣﻲﺷﻮد ﺑﻪ ﻛﺎر ﺑﺮد‬reference ‫ را ﺑﺮاي‬dynamic_cast #include <conio.h> #include <iostream> using namespace std; class A { public: virtual void f(){}; }; class B: public A { public: void f() { cout<< "f() in B\n"; } }; int main() { A& rA = *new B; B& rB = dynamic_cast<B&>(rA); rA.f(); rB.f(); _getch(); }

Output: f() in B f() in B

:‫ ﻧﮕﺎه ﻛﻨﻴﺪ‬hierarchy ‫ﺑﻪ اﻳﻦ‬

271

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫در اﻳﻦ ‪ hierarchy‬اﺷﻜﺎﻟﻲ وﺟﻮد ﻧﺪارد‪ E .‬ﺑﻪ ﻃﻮر ﻏﻴﺮ ﻣﺴﺘﻘﻴﻢ دو ﺑﺎر از ﻛﻼس ‪ A derive‬ﺷﺪه و دو ﻛﭙﻲ از ‪A‬‬

‫را در ﺧﻮد دارد‪.‬‬ ‫ﻓﺮض ﻛﻨﻴﺪ ‪pointer‬ي ﺑﺎ ﻧﻮع *‪ D‬ﺑﻪ ﺣﺎﻓﻈﻪاي ﺑﻪ اﻧﺪازهي ‪ E‬دارﻳﻢ و ﻣﻲﺧﻮاﻫﻴﻢ اﻳﻦ ‪ pointer‬را ﺑﻪ ‪A* cast‬‬

‫ﻛﻨﻴﻢ ﻛﻪ ‪A‬ي ﺳﻤﺖ ﭼﭗ ﻣﻮرد ﻧﻈﺮ اﺳﺖ‪ .‬ﺑﺎ ‪ static_cast‬اﻳﻦ ﻛﺎر را ﻧﻤﻲﺷﻮد ﻣﺴﺘﻘﻴﻤﺎ اﻧﺠﺎم داد‪ .‬ﺑﺎﻳﺪ اﻳﻦ‬ ‫ﻛﺎر در دو ﻣﺮﺣﻠﻪ اﻧﺠﺎم ﺷﻮد‪ .‬اول ﺑﺎ ‪ static_cast‬از ‪ hierarchy‬ﭘﺎﻳﻴﻦ ﻣﻲآﻳﻴﻢ و ﺑﻌﺪ در ﺟﻬﺖ ﻣﻨﺎﺳﺐ ﺑﺎﻻ‬ ‫ﻣﻲروﻳﻢ‪ .‬در ﻣﺜﺎل زﻳﺮ ﻫﻤﻴﻦ ﻛﺎر را ﺑﺎ ‪ dynamic_cast‬اﻧﺠﺎم دادهام‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int a‬‬ ‫}{)‪A(int aParam): a(aParam‬‬ ‫;}‬ ‫‪class B: public A‬‬ ‫{‬ ‫‪public:‬‬ ‫;}{)‪B(): A(1000‬‬ ‫;}‬

‫‪272‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ class C: public A { public: C(): A(2000){}; }; class D { public: virtual ~D(){} }; class E: public B, public C, public D { public: E(): B(),C(),D() {} }; int main() { D* pD = new E; E* pE = dynamic_cast<E*>(pD); B* pB = dynamic_cast<B*>(pE); A* pA = dynamic_cast<A*>(pB); cout<< pA -> a; _getch(); }

Output: 1000

.‫ ﻛﺮدهام‬E downcast ‫ ﺑﻪ‬D ‫ از‬dynamic_cast ‫ اول ﺑﺎ‬.‫ي ﻛﻼسﻫﺎي اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‬hierarchy ‫ﺑﻪ‬ ‫ را‬virtual ‫ اﻳﻦ ﻋﻀﻮ‬.‫ داﺷﺘﻪ ﺑﺎﺷﺪ‬virtual ‫ ﺑﺎﺷﺪ ﻳﻌﻨﻲ ﻋﻀﻮ‬D polymorphic ‫ﺑﺮاي اﻳﻦ ﻛﺎر ﻻزم اﺳﺖ‬ ‫ ﺑﻌﺪ‬.‫ ﻧﺒﻮد‬D ‫ ﺑﻮدن‬polymorphic ‫ ﻧﻴﺎزي ﺑﻪ‬،‫ اﺳﺘﻔﺎده ﻣﻲﻛﺮدم‬static_cast ‫ اﮔﺮ از‬.‫ ﮔﺮﻓﺘﻪام‬destructor ‫ ﺳﻤﺖ ﭼﭗ‬A ‫ اﻣﺎ ﺑﺎﻳﺪ ﻣﻄﻤﺌﻦ ﺷﺪ ﻛﻪ واﻗﻌﺎ ﺑﻪ‬.‫ ﺳﻤﺖ ﭼﭗ رﺳﻴﺪهام‬A ‫ ﻛﺮدهام و در ﻧﻬﺎﻳﺖ ﺑﻪ‬B upcast ‫ ﺑﻪ‬E ‫از‬ ‫ ﺑﺮاي‬A::a ‫ و‬1000 ‫ ﺳﻤﺖ ﭼﭗ ﻣﻘﺪار‬A ‫ ﺑﺮاي‬A::a ‫ﻫﺎ را ﺑﺮرﺳﻲ ﻛﻨﻴﺪ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬constructor .‫رﻓﺘﻪام‬ .‫ ﺳﻤﺖ ﭼﭗ رﺳﻴﺪهام‬A ‫ اﺳﺖ ﭘﺲ واﻗﻌﺎ ﺑﻪ‬1000 ‫ دارد و ﺧﺮوﺟﻲ‬2000 ‫ ﺳﻤﺖ راﺳﺖ ﻣﻘﺪار‬A ‫اﮔﺮ ﺑﻪ ﺟﺎي‬ E* pE = dynamic_cast<E*>(pD); B* pB = dynamic_cast<B*>(pE); A* pA = dynamic_cast<A*>(pB);

:‫ﻣﻲﻧﻮﺷﺘﻢ‬ A* pA = dynamic_cast<A*>(pD);

273

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺑﺮﻧﺎﻣﻪ اﺟﺮا ﻣﻲﺷﺪ وﻟﻲ ﻳﻚ ‪ exception‬ﻫﻢ ‪ raise‬ﻣﻲﺷﺪ ﭼﻮن ﻣﻌﻠﻮم ﻧﺸﺪه ﻛﻪ ﻣﻨﻈﻮر ﻛﺪام ‪ A‬اﺳﺖ‪ .‬ﻳﻌﻨﻲ ﺑﺮﻧﺎﻣﻪ‬ ‫‪ compile-time error‬ﻧﻤﻲداﺷﺖ اﻣﺎ ﻳﻚ ‪ run-time error‬ﻣﻲداﺷﺖ‪ .‬اﮔﺮ از ‪ static_cast‬اﺳﺘﻔﺎده‬ ‫ﻣﻲﻛﺮدم ‪ compile-time error‬اﻳﺠﺎد ﻣﻲﺷﺪ‪ .‬اﮔﺮ در اﻳﻦ ﻣﺜﺎل ‪ destructor‬را ‪ private‬ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‬ ‫ﺑﺮﻧﺎﻣﻪ اﺟﺮا ﻧﻤﻲﺷﻮد‪.‬‬

‫‪virtual inheritance‬‬

‫ﺑﻪ اﻳﻦ ‪ hierarchy‬ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬

‫ﻫﺮ ‪ object‬ﺑﺎ ﻧﻮع ‪ N‬دو ﻛﭙﻲ از ‪ A‬دارد‪ .‬ﺑﺮاي دﺳﺘﺮﺳﻲ ﺑﻪ اﻋﻀﺎي ﻫﺮ ﻳﻚ از اﻳﻦ دو ‪ A‬ﺑﺎﻳﺪ از ﻣﺴﻴﺮ ﻣﻨﺎﺳﺐ‬ ‫اﺳﺘﻔﺎده ﻛﺮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int a‬‬ ‫;}‬ ‫‪class B: public A‬‬ ‫;}{‬ ‫‪class C: public A‬‬ ‫;}{‬

‫‪274‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪class N: public B, public C‬‬ ‫;}{‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪N n‬‬ ‫‪// n.a = 1; // error‬‬ ‫‪// n.A::a = 1; // error‬‬ ‫;‪n.B::a = 1111‬‬ ‫;‪n.C::a = 2222‬‬ ‫;‪cout<< n.B::a << endl‬‬ ‫;‪cout<< n.C::a << endl‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1111‬‬ ‫‪2222‬‬

‫اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﺗﻨﻬﺎ ﻳﻚ ﻛﭙﻲ از ‪ A‬درﺳﺖ ﺷﻮد ﺑﺎﻳﺪ از ‪ virtual inheritance‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ .‬در اﻳﻦ ﺻﻮرت ﻳﻚ‬ ‫‪ hierarchy‬ﻣﺜﻞ ﺷﻜﻞ زﻳﺮ ﺧﻮاﻫﻴﻢ داﺷﺖ‪:‬‬

‫ﺑﺮاي اﻳﻦ ﻛﺎر ﻛﺎﻓﻲ اﺳﺖ ﺷﺎﺧﻪﻫﺎﻳﻲ ﻛﻪ ﻣﻲﺧﻮاﻫﻴﻢ ﺑﻪ ﻳﻚ ‪ A‬ﻣﺸﺘﺮك ﻣﺘﺼﻞ ﺑﺎﺷﻨﺪ‪ virtual ،‬ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‪.‬‬ ‫ﺑﻪ اﻳﻦ ‪ hierarchy‬ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫‪275‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

:‫ ﻗﺎﺑﻞ ﺗﻌﺮﻳﻒ ﻫﺴﺘﻨﺪ‬hierarchy ‫ ﻛﻼسﻫﺎﻳﻲ ﺑﺎ اﻳﻦ‬Borland ‫ﻫﺎي‬compiler ‫در‬ #include <conio.h> #include <iostream> using namespace std; class A { public: int a; A() { cout<< "A constructor\n"; } ~A() { cout<< "A destructor\n"; } }; class B: virtual public A { public: B() { cout<< "B constructor\n"; } ~B() { cout<< "B destructor\n"; } };

276

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ class C: virtual public A { public: C() { cout<< "C constructor\n"; } ~C() { cout<< "C destructor\n"; } }; class D: public A { public: D() { cout<< "D constructor\n"; } ~D() { cout<< "D destructor\n"; } }; class E: public B,virtual public A, public C, public D { public: E() { cout<< "E constructor\n"; } ~E() { cout<< "E destructor\n"; } }; int main() { { E e; } _getch(); }

Output (BDS 2006): A constructor B constructor C constructor A constructor D constructor

277

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪constructor‬‬ ‫‪destructor‬‬ ‫‪destructor‬‬ ‫‪destructor‬‬ ‫‪destructor‬‬ ‫‪destructor‬‬ ‫‪destructor‬‬

‫‪E‬‬ ‫‪E‬‬ ‫‪D‬‬ ‫‪A‬‬ ‫‪C‬‬ ‫‪B‬‬ ‫‪A‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺗﻨﻬﺎ دو ‪ A‬ﺳﺎﺧﺘﻪ ﺷﺪه اﺳﺖ‪ .‬ﺑﻌﺪ از اﻳﻦ ﻛﻪ اوﻟﻴﻦ ‪ A‬ﺳﺎﺧﺘﻪ ﺷﺪ‪ B ،‬ﺳﺎﺧﺘﻪ ﻣﻲﺷﻮد و ﺑﺪون اﻳﻦ ﻛﻪ ‪A‬‬

‫دﻳﮕﺮي ﺳﺎﺧﺘﻪ ﺷﻮد‪ C ،‬ﺳﺎﺧﺘﻪ ﻣﻲﺷﻮد‪ .‬ﺑﻌﺪ ‪ A‬دوم ﺳﺎﺧﺘﻪ ﻣﻲﺷﻮد و ﺑﻌﺪ از آن ‪ D‬ﺑﺎ اﺳﺘﻔﺎده از اﻳﻦ ‪ A‬دوم ﺳﺎﺧﺘﻪ‬ ‫ﻣﻲﺷﻮد‪ .‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻓﻘﻂ ﺷﺎﺧﻪﻫﺎي ‪ A ،virtual‬ﻣﺸﺘﺮك دارﻧﺪ‪destructor .‬ﻫﺎ ﺑﺎ ﺗﺮﺗﻴﺐ ﻋﻜﺲ‬ ‫‪constructor‬ﻫﺎ ﻓﺮاﺧﻮاﻧﺪه ﻣﻲﺷﻮﻧﺪ‪.‬‬ ‫‪ Microsoft Visual C++ 2005‬از ‪ hierarchy‬اﻳﻦ ﻣﺜﺎل اﻳﺮاد ﻣﻲﮔﻴﺮد و ﻣﻲﮔﻮﻳﺪ ﻛﻪ ‪ E‬ﻧﺒﺎﻳﺪ ﺑﻪ ﻃﻮر‬ ‫ﻣﺴﺘﻘﻴﻢ از ‪ A derive‬ﺷﻮد )ﭼﻪ ‪ virtual‬و ﭼﻪ ﻏﻴﺮ ‪ .(virtual‬در ﻣﻮرد ﻏﻴﺮ ‪ virtual‬ﻣﻲﺷﻮد ﺗﺎ ﺣﺪي ﺑﻪ آن‬ ‫ﺣﻖ داد ﭼﻮن دﺳﺘﺮﺳﻲ ﺑﻪ ‪ A::a‬ﻛﻪ ‪ base class‬ﻣﺴﺘﻘﻴﻢ اﺳﺖ وﺟﻮد ﻧﺪارد )در واﻗﻊ ﻧﻤﻲﺷﻮد ﺑﻪ ‪compiler‬‬ ‫ﻓﻬﻤﺎﻧﺪ ﻛﻪ ﻣﻨﻈﻮر ﻣﺎ ﻛﺪام ‪ A‬اﺳﺖ(‪.‬‬

‫ﺑﻴﺎﻳﻴﺪ ﺑﺮﻧﺎﻣﻪاي ﺑﺮاي ‪ hierarchy‬ﺳﺎدهي زﻳﺮ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬

‫>‪#include <conio.h‬‬

‫‪278‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <iostream> using namespace std; class A { public: int a; A() { cout<< "A constructor\n"; } ~A() { cout<< "A destructor\n"; } }; class B: virtual public A { public: B() { cout<< "B constructor\n"; } ~B() { cout<< "B destructor\n"; } }; class C: virtual public A { public: C() { cout<< "C constructor\n"; } ~C() { cout<< "C destructor\n"; } }; class D: public B,public C { public: D() { cout<< "D constructor\n"; } ~D() { cout<< "D destructor\n"; } }; int main()

279

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { { D e; cout<< endl; e.a = 2; cout<< e.B::a cout<< e.C::a cout<< e.A::a cout<< e.a cout<< endl;

<< << << <<

endl; endl; endl; endl;

} _getch(); }

Output: A constructor B constructor C constructor D constructor 2 2 2 2 D C B A

destructor destructor destructor destructor

abstract ‫سه‬O

‫ اﺳﺖ( ﻛﻼﺳﻲ اﺳﺖ ﻛﻪ ﺗﺎﺑﻊ‬Abstract Data Type ‫ )ﻛﻪ ﻣﺨﻔﻒ‬ADT ‫( ﻳﺎ‬abstract) ‫ﻳﻚ ﻧﻮع اﻧﺘﺰاﻋﻲ‬ method ‫ ﻛﺮدن ﻳﻚ‬pure ‫ ﺑﺮاي‬.‫ ﻣﻲﮔﻮﻳﻴﻢ‬abstract ‫ ﺑﻪ ﭼﻨﻴﻦ ﻛﻼﺳﻲ ﻛﻼس‬.‫ داﺷﺘﻪ ﺑﺎﺷﺪ‬pure virtual ‫ در‬."=0" ‫ آن در ﻛﻼس ﻧﻮﺷﺖ‬prototype ‫ﺑﺎﻳﺪ اوﻻ ﺗﻌﺮﻳﻒ آن را ﺑﻪ ﺧﺎرج از ﻛﻼس ﺑﺮد و ﺛﺎﻧﻴﺎ ﺟﻠﻮي‬ :‫ اﺳﺖ‬f() pure virtual ‫ﻛﻼس زﻳﺮ‬ class A { public:

280

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪int a‬‬ ‫;‪virtual void f() = 0‬‬ ‫)(‪A‬‬ ‫{‬ ‫;"‪cout<< "A constructor\n‬‬ ‫}‬ ‫)(‪~A‬‬ ‫{‬ ‫;"‪cout<< "A destructor\n‬‬ ‫}‬ ‫;}‬ ‫)(‪void A::f‬‬ ‫{‬ ‫;"‪cout<<"f()\n‬‬ ‫}‬

‫در اﻳﻦ ﺣﺎﻟﺖ ﻛﻼس ‪ abstract‬اﺳﺖ و ‪ f() pure‬اﺳﺖ‪ .‬ﺗﻨﻬﺎ ‪method‬ﻫﺎي ‪virtual‬؛ ﻣﻲﺗﻮاﻧﻨﺪ ‪pure‬‬ ‫ﺑﺎﺷﻨﺪ‪ .‬ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ‪ pure virtual‬ﺑﺎ ‪ pure‬ﺧﺎﻟﻲ ﻓﺮﻗﻲ ﻧﺪارد‪method .‬ﻫﺎي ‪ pure‬ﻧﻴﺎزي ﺑﻪ ﺗﻌﺮﻳﻒ‬ ‫ﻧﺪارﻧﺪ وﻟﻲ اﮔﺮ ﺑﺮاي آنﻫﺎ ﺗﻌﺮﻳﻒ ﻗﺮار ﺑﺪﻫﻴﻢ در ‪ BDS 2006‬ﺑﺎﻳﺪ ﺧﺎرج از ﻛﻼس ﺑﺎﺷﺪ‪ .‬در ‪Visual C++‬‬ ‫‪ 2005‬ﺗﻌﺮﻳﻒ را ﻣﻲﺷﻮد ﺑﻪ ﺻﻮرت ﻋﺎدي در ﺧﻮد ﻛﻼس ﻫﻢ اﻧﺠﺎم داد‪:‬‬ ‫‪class A‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int a‬‬ ‫‪virtual void f() = 0‬‬ ‫{‬ ‫;"‪cout<<"f()\n‬‬ ‫}‬ ‫;}‬

‫ﻫﻴﭻ ‪object‬ي ﻧﻤﻲﺷﻮد از ﻧﻮع ﻳﻚ ﻛﻼس ِ ‪ abstract‬ﺗﻌﺮﻳﻒ ﻛﺮد‪ .‬ﻳﻌﻨﻲ ﺑﺎ ﻛﻼس ‪ A‬ﻛﻪ ‪ abstract‬اﺳﺖ‬ ‫ﻧﻤﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;‪A a‬‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;‪A* p‬‬

‫وﻟﻲ ﻧﻤﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;‪A* p = new A‬‬

‫ﭼﻮن ﻫﻴﭻ ‪instance‬ي از ﻳﻚ ﻛﻼس ‪ abstract‬ﻧﻤﻲﺷﻮد داﺷﺖ )‪ instance‬ﻳﻌﻨﻲ ‪ .(object‬ﻛﻼسﻫﺎي‬ ‫‪ abstract‬ﺗﻨﻬﺎ ﺑﻪ درد ‪ base class‬ﺑﻮدن ﻣﻲﺧﻮرﻧﺪ‪ .‬ﻳﻌﻨﻲ ﻓﻘﻂ ﺑﻪ اﻳﻦ درد ﻣﻲﺧﻮرﻧﺪ ﻛﻪ ﻛﻼسﻫﺎي دﻳﮕﺮي از‬ ‫آنﻫﺎ ‪ derive‬ﺷﻮﻧﺪ‪ .‬اﮔﺮ ﻛﻼسﻫﺎي ‪ derive‬ﺷﺪه ﻫﻤﻪي ﺗﺎﺑﻊﻫﺎي ‪ pure‬را دوﺑﺎره ﺗﻌﺮﻳﻒ ﻧﻜﻨﻨﺪ‪ ،‬ﺧﻮد ِ ﺗﺎﺑﻊﻫﺎي‬ ‫‪ pure‬را ﺑﻪ ارث ﻣﻲﺑﺮﻧﺪ و در ﻧﺘﻴﺠﻪ ﺧﻮدﺷﺎن ﻫﻢ ‪ abstract‬ﻣﻲﺷﻮﻧﺪ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬

‫‪281‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <conio.h> #include <iostream> using namespace std; class A { public: int a; virtual void f() = 0; virtual void g() = 0; }; void A::f() { cout<<"f()\n"; } class B: public A { public: void g() { cout<<"g() is defined\n"; } }; class C: public B { public: void f() { A::f(); cout<< "f() is redefined\n"; } }; int main() { C c; c.f(); c.g(); //c.A::g(); // error _getch(); }

Output: f() f() is redefined g() is defined

282

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ را‬g() ،B .‫ داده ﻧﺸﺪه‬g() ‫ ﻫﻴﭻ ﺗﻌﺮﻳﻔﻲ ﺑﺮاي‬A ‫ در‬.‫ ﻫﺴﺘﻨﺪ‬abstract ‫ ﻫﺮ دو‬B‫ و‬A ‫در اﻳﻦ ﻣﺜﺎل ﻛﻼسﻫﺎي‬ ‫ ﻫﻢ‬f() ،C ‫ در ﻛﻼس‬.‫ را ﺗﻌﺮﻳﻒ ﻧﻜﺮده‬f() ِ pure ‫ اﺳﺖ ﭼﻮن ﻫﻨﻮز ﺗﺎﺑﻊ‬abstract ‫ﺗﻌﺮﻳﻒ ﻛﺮده ﺑﺎ اﻳﻦ ﺣﺎل‬ .‫ ﻧﻴﺴﺖ‬abstract ‫ دﻳﮕﺮ‬C .‫ در اﻳﻦ ﺗﻌﺮﻳﻒ ﺑﻪ ﻛﺎر ﺑﺮده ﺷﺪه‬A ‫ در‬f() ‫ ﺗﻌﺮﻳﻒ ﻗﺒﻠﻲ‬.‫ﺗﻌﺮﻳﻒ ﺷﺪه‬ ‫ ﺑﻪ ﻣﺜﺎل زﻳﺮ ﺗﻮﺟﻪ‬.‫ ﺑﻪ ﻋﻨﻮان ﻳﻚ ﻗﺎﻟﺐ ﺑﺮاي ﺗﻌﺮﻳﻒ ﻛﻼسﻫﺎي دﻳﮕﺮ ﺑﻪ ﻛﺎر ﻣﻲروﻧﺪ‬abstract ‫ﻛﻼسﻫﺎي‬ Truck ،(‫ )ﻣﺎﺷﻴﻦ‬Car ‫ )وﺳﻴﻠﻪي ﻧﻘﻠﻴﻪ( را ﺑﻪ ﻋﻨﻮان ﻳﻚ ﻗﺎﻟﺐ دارد و ﻛﻼسﻫﺎي‬Vehicle ‫ﻛﻨﻴﺪ ﻛﻪ‬ GetFuel() ِ pure ‫ ﺗﺎﺑﻊ‬Vehicle ‫ ﻛﻼس‬.‫ ﺷﺪهاﻧﺪ‬derive ‫ )ﻫﻮاﭘﻴﻤﺎ( از آن‬airplane ‫)ﻛﺎﻣﻴﻮن( و‬

:‫)ﺳﻮﺧﺖ ﮔﺮﻓﺘﻦ( را در ﺧﻮدش دارد‬ #include <conio.h> #include <iostream> using namespace std; class Vehicle { public: virtual void GetFuel() = 0; }; class Car: public Vehicle { public: void GetFuel() { cout<< "Get gasoline\n"; } }; class Truck: public Vehicle { public: void GetFuel() { cout<< "Get diesel\n"; } }; class Airplane { public: void GetFuel() { cout<<"Get fuel\n"; } }; int main() { Car Speedy; Airplane Jimbo;

283

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ Speedy.GetFuel(); Jimbo.GetFuel(); _getch(); }

Output: Get gasoline Get fuel

.‫ ﻣﻲﺷﻮد‬abstract ‫ ﺷﻮد ﻛﻼس ﺣﺎوي آن ﺗﺎﺑﻊ‬pure ،‫در ﻧﻬﺎﻳﺖ ﻣﻲﮔﻮﻳﻢ ﻛﻪ ﺣﺘﻲ اﮔﺮ ﻳﻚ ﺗﺎﺑﻊ‬

compiler > ? ‫سه در‬O ‫ د از‬."#‫ا‬

C++ ‫ و زﺑﺎن‬compiler ‫ ﻣﻲﺷﻮد ﺷﻨﺎﺧﺖ ﺑﻬﺘﺮي از‬destructor ‫ﻫﺎ و‬constructor ،‫ﺑﺎ اﺳﺘﻔﺎده از ﻛﻼس‬ .‫ در اﻳﻦ ﺟﺎ ﭼﻨﺪ ﺗﺎ ﻣﺜﺎل ﻣﻲآورم‬.(‫ﭘﻴﺪا ﻛﺮد )ﻳﻌﻨﻲ ﻣﻲﺷﻮد آنﻫﺎ را رواﻧﺸﻨﺎﺳﻲ ﻛﺮد‬ :‫ﺑﻪ اﻳﻦ ﻣﺜﺎل ﺗﻮﺟﻪ ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; class A { public: A() { cout<< "an A is constructed\n"; } ~A() { cout<< "an A is destroyed\n"; } }; int main() { { A a[3][2]; } _getch(); }

Output: an A is constructed an A is constructed

284

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ an an an an an an an an an an

A A A A A A A A A A

is is is is is is is is is is

constructed constructed constructed constructed destroyed destroyed destroyed destroyed destroyed destroyed

.‫ ﻓﺮاﺧﻮاﻧﺪه ﺷﺪه‬constructor (‫ﻫﺎي ﻣﻮﺟﻮد در آراﻳﻪ‬int ‫ ﺑﺎر )ﺑﻪ ﺗﻌﺪاد‬6 ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬ :‫ ﻣﺜﺎل زﻳﺮ ﻗﺎﺑﻞ ﺗﻮﺟﻪ اﺳﺖ‬throw ‫ و‬catch ،try ‫در ﻣﻮرد ﻛﻠﻤﻪﻫﺎي ﻛﻠﻴﺪي‬ #include <conio.h> #include <iostream> using namespace std; class A { public: A() { cout<< "an A is constructed\n"; } ~A() { cout<< "an A is destroyed\n"; } A(const A& a) { cout<< "A copy constructor\n"; } }; void f() { A a; throw a; } int main() { try { f(); } catch(A& a) { } _getch(); }

285

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ Output (BDS 2006): an A is constructed A copy constructor A copy constructor an A is destroyed an A is destroyed an A is destroyed Output (Visual C++ 2005) : an A is constructed A copy constructor an A is destroyed an A is destroyed

...‫ و‬constructor ‫ﻫﺎ ﻓﻘﻂ ﻣﺜﻞ ﻳﻚ اﺳﻢ ِ ﺟﺎﻳﮕﺰﻳﻦ ﻋﻤﻞ ﻣﻲﻛﻨﻨﺪ و‬reference ‫ﺑﺮﻧﺎﻣﻪي ﺑﻌﺪي ﻧﺸﺎن ﻣﻲدﻫﺪ‬ :‫را ﻓﺮا ﻧﻤﻲﺧﻮاﻧﻨﺪ‬ #include <conio.h> #include <iostream> using namespace std; class A { public: A() { cout<< "an A is constructed\n"; } ~A() { cout<< "an A is destroyed\n"; } A(const A& a) { cout<< "A copy constructor\n"; } void operator = (A a) { cout<< "operator =\n"; } }; int main() { { A a; A& b = a; } _getch(); }

286

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ Output: an A is constructed an A is destroyed

.‫ اﺳﺖ‬a ‫ اﺳﻢ دﻳﮕﺮي ﺑﺮاي‬b ‫ ﻫﻴﭻ ﭼﻴﺰ را ﻓﺮا ﻧﺨﻮاﻧﺪه و اﻧﮕﺎر‬b ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺗﻌﺮﻳﻒ‬

‫ه‬union

‫ ﻳﻚ ﻛﻼس اﺳﺖ ﺑﺎ اﻳﻦ ﻓﺮق ﻛﻪ ﺣﺎﻓﻈﻪي ﻫﻤﻪي ﻣﺘﻐﻴﺮﻫﺎي آن در ﻳﻚ ﺟﺎ ﻗﺮار دارد و از ﻳﻚ ﺟﺎ‬union ‫ﻳﻚ‬ :‫ﺷﺮوع ﻣﻲﺷﻮد‬ #include <conio.h> #include <iostream> using namespace std; union A { int a; char ch; void f() { cout<< "f()"; } A():a(0),ch(0) { cout<< "constructor\n"; } }; int main() { A a; a.ch = 97; cout<< a.a << endl; a.f(); _getch(); }

Output: constructor 97 f()

287

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ union‬در اﻳﻦ ﻣﺜﺎل درﺳﺖ ﻣﺜﻞ ﻳﻚ ‪ struct‬ﻋﻤﻞ ﻣﻲﻛﻨﺪ ﺑﺎ اﻳﻦ ﻓﺮق ﻛﻪ ‪ A::ch‬از ﻫﻤﺎن ﺣﺎﻓﻈﻪاي اﺳﺘﻔﺎده‬ ‫ﻣﻲﻛﻨﺪ ﻛﻪ ‪ A::a‬اﺳﺘﻔﺎده ﻣﻲﻛﻨﺪ‪ .‬ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ وﻗﺘﻲ ﻣﻘﺪار ‪ 97‬ﺑﻪ ‪ ch‬داده ﺷﺪه‪ a ،‬ﻫﻢ ﻫﻤﻴﻦ ﻣﻘﺪار را ﮔﺮﻓﺘﻪ‬ ‫اﺳﺖ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﺛﺎﺑﺖ ﺷﻮد ﻣﻜﺎن ﺣﺎﻓﻈﻪ ﻳﻜﻲ اﺳﺖ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪class Cat‬‬ ‫{‬ ‫;‪int a‬‬ ‫;‪int b‬‬ ‫;}‬ ‫‪union A‬‬ ‫{‬ ‫;‪Cat Tom‬‬ ‫;‪int a‬‬ ‫;‪char ch‬‬ ‫;}‬

‫;‪endl‬‬ ‫;‪endl‬‬ ‫;‪endl‬‬ ‫;‪endl‬‬ ‫;‪endl‬‬

‫<<‬ ‫<<‬ ‫<<‬ ‫<<‬ ‫<<‬

‫)(‪int main‬‬ ‫{‬ ‫;‪A a‬‬ ‫‪cout<< (int) &a.Tom‬‬ ‫‪cout<< (int) &a.a‬‬ ‫‪cout<< (int) &a.ch‬‬ ‫)‪cout<< sizeof(A‬‬ ‫)(‪cout<< typeid(A).name‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪1245060‬‬ ‫‪1245060‬‬ ‫‪1245060‬‬ ‫‪8‬‬ ‫‪A‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫‪1245020‬‬ ‫‪1245020‬‬ ‫‪1245020‬‬ ‫‪8‬‬ ‫‪union A‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻣﻜﺎن ﺣﺎﻓﻈﻪي ﻫﺮ ﺳﻪ ﻣﺘﻐﻴﺮ ‪ union‬در اﻳﻦ ﻣﺜﺎل ﻳﻜﻲ اﺳﺖ‪ .‬اﻧﺪازهي ‪ union‬ﺑﺮاﺑﺮ ﺑﺎ اﻧﺪازهي‬ ‫ﺑﺰرگ ﺗﺮﻳﻦ ﻣﺘﻐﻴﺮ آن اﺳﺖ‪.‬‬

‫‪288‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻓﺮق دﻳﮕﺮ ‪ union‬ﺑﺎ ‪ struct‬اﻳﻦ اﺳﺖ ﻛﻪ ﻧﻤﻲﺷﻮد از آن ‪ union‬دﻳﮕﺮي را ‪ derive‬ﻛﺮد ﻳﻌﻨﻲ ﻧﻤﻲﺗﻮاﻧﺪ‬ ‫‪ - base‬ﻛﻼس ﺑﺎﺷﺪ‪.‬‬ ‫ﻣﺜﺎل زﻳﺮ ﻛﺎرﺑﺮد ﺟﺎﻟﺒﻲ از ﻳﻚ ‪ union‬را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫;‪a1‬‬ ‫;‪a2‬‬ ‫;‪a3‬‬ ‫;‪a4‬‬

‫‪union A‬‬ ‫{‬ ‫‪public:‬‬ ‫;‪int a‬‬ ‫‪struct‬‬ ‫{‬ ‫‪char‬‬ ‫‪char‬‬ ‫‪char‬‬ ‫‪char‬‬ ‫;}‬ ‫;}‬

‫)(‪int main‬‬ ‫{‬ ‫;}‪A a = {44 + 22*256 + 11*256*256‬‬ ‫;‪int x‬‬ ‫;‪x = (unsigned char)a.a1‬‬ ‫‪cout << x << endl; // first byte‬‬ ‫;‪x = (unsigned char)a.a2‬‬ ‫;‪cout << x‬‬ ‫‪// second byte‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪44‬‬ ‫‪22‬‬

‫در اﻳﻦ ﻣﺜﺎل ﻳﻚ ‪ union‬دارﻳﻢ ﻛﻪ ﺑﻪ وﺳﻴﻠﻪي آن \‪ int n‬ﻳﻌﻨﻲ ‪ A::a‬را ﺑﻪ ﭼﻬﺎر ﺑﺎﻳﺖ ﺷﻜﺴﺘﻪاﻳﻢ‪ .‬در‬ ‫)(‪ main‬ﺑﻪ اﻳﻦ ‪ int‬ﻣﻘﺪاري دادهام و دو ﺑﺎﻳﺖ اول آن را ﭼﺎپ ﻛﺮدهام‪ .‬ﻧﻜﺘﻪي ﻗﺎﺑﻞ ﺗﻮﺟﻪ در اﻳﻦ ﻣﺜﺎل اﻳﻦ‬ ‫اﺳﺖ ﻛﻪ ‪ struct‬ﺗﻌﺮﻳﻒ ﺷﺪه در ‪ union‬ﻫﻴﭻ اﺳﻤﻲ ﻧﺪارد و ﻫﻴﭻ ﻣﺘﻐﻴﺮي ﻫﻢ از ﻧﻮع آن وﺟﻮد ﻧﺪارد‪ .‬اﻋﻀﺎي‬ ‫آن در واﻗﻊ اﻋﻀﺎي ‪ A‬ﺑﻪ ﺣﺴﺎب ﻣﻲآﻳﻨﺪ ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﻧﻮﺷﺘﻴﻢ ‪ .a.a1‬اﻟﺒﺘﻪ ﺣﺎﻓﻈﻪي ‪ a1‬و ﻣﺜﻼ ‪ a2‬ﻳﻜﻲ ﻧﻴﺴﺖ‪.‬‬ ‫اﮔﺮ‬ ‫‪union A‬‬ ‫{‬ ‫;‪int a‬‬

‫‪289‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ int b; };

:‫ﻧﻤﻲﺷﻮد ﻧﻮﺷﺖ‬ A u = {1,2};

:‫ ﻳﻚ ﻣﺘﻐﻴﺮ ﺑﻴﺶ ﺗﺮ ﻧﺪارد‬A ‫ﭼﻮن ﻋﻤﻼ‬ #include <conio.h> #include <iostream> using namespace std; union A { int a; int b; char ch; }; int main() { A u = {97}; cout<< u.a << endl; cout<< u.b << endl; cout<< u.ch; _getch(); }

Output 97 97 a

‫ي‬union ‫ ﺑﻪ ﭼﻨﻴﻦ‬.‫ اﻳﺠﺎد ﭼﻨﺪ ﻣﺘﻐﻴﺮ ﺑﺎ ﻳﻚ ﻣﻜﺎن ﺣﺎﻓﻈﻪ اﺳﺖ‬union ‫ﻳﻜﻲ دﻳﮕﺮ از ﻛﺎرﺑﺮدﻫﺎي‬ :‫ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‬.‫ ﻳﻌﻨﻲ »ﺑﻲ اﺳﻢ« ﻣﻲﮔﻮﻳﻨﺪ‬anonymous #include <conio.h> #include <iostream> using namespace std; int main() { union { int a; int b; }; a = 1387; cout<< b;

290

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1387‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ‪ a‬و ‪ b‬در ﻳﻚ ﻣﻜﺎن از ﺣﺎﻓﻈﻪ ﻗﺮار دارﻧﺪ‪.‬‬ ‫‪union‬ﻫﺎي ‪ anonymous‬ﻧﻤﻲﺗﻮاﻧﻨﺪ ﺗﺎﺑﻊ ﻳﺎ ﻋﻀﻮ ﻏﻴﺮ ‪ public‬داﺷﺘﻪ ﺑﺎﺷﻨﺪ‪.‬‬

‫@? ' ‬

‫‪ (1‬ﻛﻼس زﻳﺮ ﺷﺮوﻋﻲ ﺑﺮ ﻳﻚ ﻛﻼس ﻛﺎﻣﻞ ﺑﺮاي رﺷﺘﻪﻫﺎﺳﺖ‪:‬‬ ‫‪class String‬‬ ‫{‬ ‫;‪char* c‬‬ ‫‪public:‬‬ ‫)‪String(char* normal_string‬‬ ‫{‬ ‫;)‪int len = StringLength(normal_string‬‬ ‫;]‪c = new char [len + 1‬‬ ‫)‪for(unsigned i = 0; i <= len; i++‬‬ ‫;]‪c[i] = normal_string[i‬‬ ‫}‬ ‫)(‪~String‬‬ ‫{‬ ‫;‪delete [] c‬‬ ‫}‬ ‫)‪void Print(void‬‬ ‫{‬ ‫;‪cout<< c << endl‬‬ ‫}‬ ‫;}‬

‫آن را ﺑﺎ اﺿﺎﻓﻪ ﻛﺮدن ‪ operator+‬ﺑﺮاي ﺗﺮﻛﻴﺐ رﺷﺘﻪﻫﺎ و ][‪ operator‬ﺑﺮاي دﺳﺘﺮﺳﻲ ﺑﻪ ‪i‬اﻣﻴﻦ‬ ‫ﻛﺎراﻛﺘﺮ ﻛﺎﻣﻞ ﺗﺮ ﻛﻨﻴﺪ‪ .‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ اﻳﻦ ﻛﻼس ﺣﺎﻓﻈﻪ را از ‪ heap‬ﻣﻲﮔﻴﺮد وﻟﻲ ﺑﻪ ﺧﺎﻃﺮ وﺟﻮد‬ ‫‪ destructor‬ﻣﻨﺎﺳﺐ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻧﻴﺎزي ﻧﺪارد ﻣﺪام ﻣﺮاﻗﺐ ][‪ delete‬ﻛﺮدن ﺣﺎﻓﻈﻪ ﺑﺎﺷﺪ‪ .‬ﺑﻬﺘﺮ اﺳﺖ‬ ‫اﻳﻦ ﻛﻼس را ﺗﺎ آن ﺟﺎ ﻛﻪ ﻣﻤﻜﻦ اﺳﺖ ﻛﺎﻣﻞ ﻛﻨﻴﺪ و در ‪ header file‬ﻣﺨﺼﻮص ﺧﻮدﺗﺎن ﻗﺮار ﺑﺪﻫﻴﺪ‪.‬‬ ‫‪ (2‬ﺑﺮﻧﺎﻣﻪي زﻳﺮ را ﺑﺒﻴﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬

‫‪291‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ using namespace std; class Data { public: char a[80][25]; int current_x; int current_y; void Reset() { current_x = 0; current_y = 0; for(int i = 0; i < 80; i++) for(int j= 0; j < 25; j++) a[i][j] = 0; } Data() { Reset(); } void Add(char ch) { a[current_x][current_y] = ch; if(current_x < 79) current_x++; else { current_x = 0; current_y ++; } } }; class Screen: public Data { public: Screen() {} void Clear() { system("CLS"); } void PaintWindow() { Clear(); for(int j = 0; j < 25; j++) for(int i = 0; i < 80; i++) { bool b = (i == 79) && (j == 24); if(!b) cout<< a[i][j]; }

292

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫}‬ ‫)‪Screen& operator << (char right_side‬‬ ‫{‬ ‫;)‪Add(right_side‬‬ ‫;)(‪PaintWindow‬‬ ‫;‪return *this‬‬ ‫}‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪Screen cout1, cout2‬‬ ‫;'‪cout1 << 'a' << 'b‬‬ ‫;'‪cout2 << 'x' << 'y‬‬ ‫;'‪cout1 << 'c' << 'd‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫ ‪S‬س ‪ Screen‬ﻳﻚ ﺻﻔﺤﻪي ﻧﻤﺎﻳﺶ را در ﺧﻮدش ﺟﺎي ﻣﻲدﻫﺪ‪ .‬ﺑﺎ ‪ Screen‬ﻣﻲﺗﻮاﻧﻴﺪ ﭼﻨﺪ ﺻﻔﺤﻪي‬ ‫ﻧﻤﺎﻳﺶ در ﺣﺎﻓﻈﻪ داﺷﺘﻪ ﺑﺎﺷﻴﺪ‪ .‬دﺳﺘﻮر‬ ‫;)"‪system("CLS‬‬

‫ﺻﻔﺤﻪي ﻧﻤﺎﻳﺶ را ﭘﺎك ﻣﻲﻛﻨﺪ‪ .‬در ﻓﺼﻞ ﺑﻌﺪ درﺑﺎرهي آن ﺑﻴﺶ ﺗﺮ ﻣﻲﮔﻮﻳﻢ‪.‬‬ ‫اﻟﻒ( ﻛﻼس ‪ Screen‬را ﻃﻮري ﺗﻐﻴﻴﺮ دﻫﻴﺪ ﻛﻪ ﺑﺎ ‪ cout1‬و ‪ cout2‬ﺑﺘﻮاﻧﻴﻢ رﺷﺘﻪﻫﺎ را ﻫﻢ ﭼﺎپ‬ ‫ﻛﻨﻴﻢ‪.‬‬ ‫ب( ﻛﺎري ﻛﻨﻴﺪ ﻛﻪ ﭼﺎپ ﺑﺎ ‪ cout1‬و ‪ cout2‬ﺳﺮﻳﻊ ﺗﺮ ﺷﻮد‪.‬‬ ‫راﻫﻨﻤﺎﻳﻲ‪ :‬وﻗﺘﻲ ]‪ a[i][j‬ﻣﻘﺪار ﺻﻔﺮ دارد ﻻزم ﻧﻴﺴﺖ ﭼﺎپ ﺷﻮد‪.‬‬ ‫ج( ﺗﺎﺑﻌﻲ ﺑﻪ ﻧﺎم )(‪ gotoxy‬ﺑﻪ ﺑﺮﻧﺎﻣﻪ اﺿﺎﻓﻪ ﻛﻨﻴﺪ ﻛﻪ ﻣﻜﺎن ﺟﺎري را ﻛﻪ ﺑﺎ ‪ current_x‬و‬ ‫‪ current_y‬ﻣﺸﺨﺺ ﻣﻲﺷﻮد ﺗﻐﻴﻴﺮ ﺑﺪﻫﺪ‪.‬‬ ‫د( آﻳﺎ ﻓﺮاﻳﻨﺪ ﭼﺎپ ﻛﺎراﻛﺘﺮ '‪ '\n‬درﺳﺖ اﺳﺖ؟ اﮔﺮ درﺳﺖ ﻧﻴﺴﺖ آن را اﺻﻼح ﻛﻨﻴﺪ‪.‬‬ ‫ه( ﻛﻼسﻫﺎي ﺑﺮﻧﺎﻣﻪ را ﻃﻮري ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﺪ ﻛﻪ اﮔﺮ ﺑﻴﺶ از ‪ 25‬ﺧﻂ ﭼﺎپ ﻛﻨﻴﻢ‪ ،‬ﺧﻂ اول ﺣﺬف ﺷﻮد و‬ ‫ﻣﺤﺘﻮﻳﺎت آراﻳﻪي ﺑﺎ آن ﭼﻪ در ﺻﻔﺤﻪ ﻧﻤﺎﻳﺶ ﻣﻲﺑﻴﻨﻴﺪ ﻳﻜﻲ ﺑﺎﺷﺪ‪.‬‬ ‫‪ (3‬ﺑﺎ ﻛﻼسﻫﺎ ﻳﻚ ﺗﻠﻮﻳﺰﻳﻮن را ﻛﻪ ﻛﻨﺘﺮل از راه دور دارد ﺷﺒﻴﻪ ﺳﺎزي ﻛﻨﻴﺪ‪:‬‬

‫‪293‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ (a‬ﻛﻼﺳﻲ ﺑﺎ ﻧﺎم ‪ TV‬ﺑﺴﺎزﻳﺪ ﻛﻪ ﻧﻤﺎﻳﻨﺪهي ﺗﻠﻮﻳﺰﻳﻮن ﺑﺎﺷﺪ‪ int n\ TV .‬دارد ﻛﻪ ﻧﺸﺎن دﻫﻨﺪه‪-‬‬ ‫ي ﻛﺎﻧﺎل در ﺣﺎل ﻧﻤﺎﻳﺶ اﺳﺖ‪.‬‬ ‫‪ (b‬ﻛﻼﺳﻲ ﺑﺴﺎزﻳﺪ ﻛﻪ ﻧﻤﺎﻳﻨﺪهي ﻣﻮﺟﻲ ﺑﺎﺷﺪ ﻛﻪ از ﻛﻨﺘﺮل از راه دور ﺑﻪ ﺗﻠﻮﻳﺰﻳﻮن ﻣﻲرﺳﺪ‪.‬‬ ‫‪ (c‬ﻛﻼﺳﻲ ﺑﺴﺎزﻳﺪ ﻛﻪ ﻧﻤﺎﻳﻨﺪهي ﺧﻮد ﻛﻨﺘﺮل از راه دور ﺑﺎﺷﺪ ﻫﻤﺮاه ﺑﺎ ‪method‬ﻫﺎﻳﻲ ﻛﻪ ﻫﺮ‬ ‫ﻛﺪام ﻧﻤﺎﻳﻨﺪهي ﻳﻚ دﮔﻤﻪ از ﻛﻨﺘﺮل ﻫﺴﺘﻨﺪ و ‪ constructor‬آن ﻳﻚ ﭘﺎراﻣﺘﺮ از ﻧﻮع ‪ TV‬دارد‪.‬‬ ‫ﺑﺎ ﻓﺸﺎر ﻫﺮ دﮔﻤﻪ‪ ،‬ﻣﻮﺟﻲ ﺑﻪ ﺗﻠﻮﻳﺰون ارﺳﺎل ﻣﻲﺷﻮد ﻛﻪ ﻛﺎﻧﺎل آن را ﺗﻐﻴﻴﺮ ﻣﻲدﻫﺪ‪.‬‬

‫' ه ‪ A#‬‬

‫‪ (1‬ﭼﻨﺪ وﻗﺖ ﭘﻴﺶ در ﻳﻜﻲ از ‪forum‬ﻫﺎي ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ ﻣﺴﺄﻟﻪاي را ﻣﻄﺮح ﻛﺮدم ﻛﻪ ﺑﻌﻀﻲ از ﺑﺮﻧﺎﻣﻪ‬ ‫ﻧﻮﻳﺲﻫﺎي ﺣﺮﻓﻪاي آن ﺟﺎ ﮔﻔﺘﻨﺪ ﻛﻪ ﻧﻮﺷﺘﻦ اﻳﻦ ﺑﺮﻧﺎﻣﻪ اﻣﻜﺎن ﻧﺪارد‪ .‬ﺑﻌﺪ ﻣﻦ و ﻳﻜﻲ دﻳﮕﺮ از اﻋﻀﺎي‬ ‫‪ forum‬ﻫﺮ ﻛﺪام آن ﺑﺮﻧﺎﻣﻪ را ﻧﻮﺷﺘﻴﻢ‪ .‬راه ﺣﻞ ﻣﻦ از ﻛﻼسﻫﺎ و ﻗﺎﺑﻠﻴﺖﻫﺎي آنﻫﺎ ﻛﻤﻚ ﻣﻲﮔﺮﻓﺖ و‬ ‫ﺗﻨﻬﺎ در ‪ C++‬ﻣﻌﻨﻲ داﺷﺖ‪ .‬راه ﺣﻞ دﻳﮕﺮ ﺟﺎﻟﺐ ﺗﺮ ﺑﻮد و در ‪ C‬ﻫﻢ ﻣﻌﻨﻲ داﺷﺖ‪ .‬ﻣﺴﺄﻟﻪ اﻳﻦ اﺳﺖ‪:‬‬ ‫»ﺑﺪون اﺳﺘﻔﺎده از آراﻳﻪ و ﺑﺪون اﺳﺘﻔﺎده از ﺣﺎﻓﻈﻪي ‪ heap‬ﺑﺮﻧﺎﻣﻪاي ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﻋﺪد ‪ n‬را از ﻛﺎرﺑﺮ‬ ‫ﺑﮕﻴﺮد‪ .‬ﺑﻌﺪ ‪ n‬ﺗﺎ ﻋﺪد ﺻﺤﻴﺢ از ﻛﺎرﺑﺮ ﺑﮕﻴﺮد و در ﻧﻬﺎﻳﺖ اﻋﺪاد ﺻﺤﻴﺢ را ﺑﺎ ﻫﻤﺎن ﺗﺮﺗﻴﺒﻲ ﻛﻪ وارد ﺷﺪهاﻧﺪ‬ ‫ﭼﺎپ ﻛﻨﺪ«‬ ‫اﮔﺮ اﻳﻦ ﻣﺴﺄﻟﻪ را ﺣﻞ ﻛﺮدﻳﺪ ﺑﺎﻳﺪ ﺑﮕﻮﻳﻢ اﺳﺘﻌﺪاد ﺧﻮﺑﻲ در ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ دارﻳﺪ‪ .‬اﮔﺮ ﻧﺘﻮاﻧﺴﺘﻴﺪ ﺣﻞ ﻛﻨﻴﺪ‬ ‫ﻣﻲﺗﻮاﻧﻴﺪ ﺑﺎ ﺟﻤﻠﻪﻫﺎﻳﻲ ﻣﺜﻞ »ﻧﻮﺷﺘﻦ اﻳﻦ ﺑﺮﻧﺎﻣﻪ اﺻﻼ ﭼﻪ ﻓﺎﻳﺪهاي دارد؟« ﻳﺎ »وﻗﺘﻲ ﻣﻲﺷﻮد از آراﻳﻪ اﺳﺘﻔﺎده‬ ‫ﻛﻨﻴﻢ ﭼﺮا ﻧﻜﻨﻴﻢ؟« ﻧﺎﺗﻮاﻧﻲ ﺧﻮدﺗﺎن را ﺗﻮﺟﻴﻪ ﻛﻨﻴﺪ‬

‫‪.‬‬

‫‪ (2‬اول ﻛﻼﺳﻲ ﺑﺎ ﻧﺎم ‪ Integer‬ﺑﻨﻮﻳﺴﺪ ﻛﻪ ﻫﺮ ‪ object‬از آن‪ ،‬ﻧﻤﺎﻳﻨﺪهي ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ )ﻣﺜﻞ ‪- ،12‬‬ ‫‪ 0 ، 126‬و ‪ (...‬ﺑﺎﺷﺪ و اﻳﻦ ﻋﺪد ﺻﺤﻴﺢ ﻫﺮ ﭼﻘﺪر ﻫﻢ ﻃﻮﻻﻧﻲ ﺑﺎﺷﺪ )ﻣﺜﻼ ‪ 200‬رﻗﻢ( ﻣﺸﻜﻠﻲ ﭘﻴﺶ ﻧﻴﺎﻳﺪ و‬ ‫اﻋﻤﺎل ﺿﺮب‪ ،‬ﺟﻤﻊ و‪ ...‬در ﻛﻼس ﺑﺎﺷﺪ و ‪constructor‬ﻫﺎ و ﻋﻤﻠﮕﺮﻫﺎي ﻣﻨﺎﺳﺐ را ﻫﻢ داﺷﺘﻪ ﺑﺎﺷﺪ‪ .‬ﺑﻌﺪ‬ ‫ﻛﻼس و ﺗﻌﺮﻳﻒﻫﺎي ﻣﺮﺑﻮط ﺑﻪ آن را در ﻳﻚ ﻓﺎﻳﻞ ﺑﺎ ﻧﺎم ‪ integer.h‬ﻗﺮار ﺑﺪﻫﻴﺪ و ﻓﺎﻳﻞ را در ﻣﻜﺎن‬ ‫ﻣﻨﺎﺳﺐ ﺑﮕﺬارﻳﺪ ﺗﺎ ‪ compiler‬ﻗﺎدر ﺑﻪ ﭘﻴﺪا ﻛﺮدن آن ﺑﺎﺷﺪ‪ .‬ﻫﻤﻪي اﻳﻦ ﺗﻌﺮﻳﻒﻫﺎ ﺑﺎﻳﺪ ﻃﻮري ﺑﺎﺷﺪ ﻛﻪ‬ ‫ﺑﺮﻧﺎﻣﻪ زﻳﺮ اﺟﺮا ﺷﻮد و ﺧﺮوﺟﻲ آن ﻋﺪد ﻧﺸﺎن داده ﺷﺪه ﺑﺎﺷﺪ‪:‬‬

‫‪294‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫"‪#include "integer.h‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;"‪Integer a = "12345678901234567890123456789012345678901234567890‬‬ ‫;‪a++‬‬ ‫;‪cout<< a << endl‬‬ ‫;)‪cout<< factorial(50‬‬ ‫}‬

‫‪Output:‬‬ ‫‪12345678901234567890123456789012345678901234567891‬‬ ‫‪30414093201713378043612608166064768844377641568960512000000000000‬‬

‫ﻣﻨﻈﻮر از ‪ factorial‬ﻫﻤﺎن ﻓﺎﻛﺘﻮرﻳﻞ اﺳﺖ )‪ 50‬ﻓﺎﻛﺘﻮرﻳﻞ ﺑﺮاﺑﺮ ﺑﺎ ﺣﺎﺻﻞ ﺿﺮب ‪ 1‬ﺗﺎ ‪ 50‬اﺳﺖ(‪.‬‬ ‫آﻳﺎ ‪ 11111111111111111111111111111111111111111‬ﻋﺪدي اول اﺳﺖ؟ )آﻳﺎ ﺗﻨﻬﺎ‬ ‫راه ﭘﺎﺳﺦ ﮔﻮﻳﻲ ﻧﻮﺷﺘﻦ ﺗﺎﺑﻊ ﺗﺸﺨﻴﺺ اﻋﺪاد اول اﺳﺖ؟!(‬ ‫‪ (3‬اﻟﻒ( اﮔﺮ ﺑﺎزي ‪ checkers‬را ﺑﻠﺪ ﻫﺴﺘﻴﺪ‪ .‬ﺑﺮﻧﺎﻣﻪ ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﺑﺎ ﺷﻤﺎ ‪ checkers‬ﺑﺎزي ﻛﻨﺪ‪) .‬ﻧﻮﺷﺘﻦ آن‬ ‫ﻣﻤﻜﻦ اﺳﺖ ﺣﺘﻲ ﻳﻚ ﻣﺎه از وﻗﺖ ﺷﻤﺎ را ﺑﮕﻴﺮد‪(.‬‬ ‫ب( ﺑﺪون ﺗﻮﺟﻪ زﻳﺎد ﺑﻪ ﮔﺮاﻓﻴﻚ )ﻣﺜﻼ ﺑﺎ اﺳﺘﻔﺎده از اﺳﻢﻫﺎي اﺳﺘﺎﻧﺪارد ﻣﻬﺮهﻫﺎ و ﺧﺎﻧﻪﻫﺎ( ﺑﺮﻧﺎﻣﻪاي‬ ‫ﺑﻨﻮﻳﺴﻴﺪ ﻛﻪ ﺷﻄﺮﻧﺞ ﺑﺎزي ﻛﻨﺪ‪ .‬ﺑﻌﺪ ﺑﺮﻧﺎﻣﻪي ﺧﻮدﺗﺎن را ﺑﺎ ﺑﺮﻧﺎﻣﻪﻫﺎي ﻣﻌﺘﺒﺮ )ﻣﺜﻼ ‪ ICC Dasher‬ﻛﻪ از‬ ‫‪ http://www.chessclub.com‬ﻗﺎﺑﻞ ‪ download‬اﺳﺖ( ﻣﻘﺎﻳﺴﻪ ﻛﻨﻴﺪ )زور آزﻣﺎﻳﻲ ﻛﻨﻴﺪ(‪.‬‬ ‫ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪاي ﻋﺎﻟﻲ ﻣﻤﻜﻦ اﺳﺖ ﭼﻨﺪ ﻣﺎه از وﻗﺖ ﺷﻤﺎ را ﺑﮕﻴﺮد!‬

‫‪295‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ‪ Q@ 6L‬رم‬ ‫در ﺳﻪ ﻓﺼﻞ ﻗﺒﻞ ﺷﻤﺎ ﺗﺎ اﻧﺪازهي زﻳﺎدي ﺑﺎ اﺑﺰارﻫﺎي ﻣﻮﺟﻮد در ‪ C++‬آﺷﻨﺎ ﺷﺪﻳﺪ‪ .‬در اﻳﻦ ﻓﺼﻞ ﻗﺼﺪ دارم ﺷﻤﺎ را ﺑﺎ‬ ‫‪ C++‬ﺑﻬﺘﺮ آﺷﻨﺎ ﻛﻨﻢ‪ .‬اﺷﺎرهاي ﺑﻪ دﺳﺘﻮرات ‪ preprocessor‬ﺧﻮاﻫﻢ داﺷﺖ‪ .‬ﻧﺤﻮهي ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ در ﭼﻨﺪ ﻓﺎﻳﻞ و‬ ‫ﺑﺮﺧﻲ ﻣﺴﺎﺋﻞ ﻣﺮﺑﻮط ﺑﻪ آن را ﻣﻲﮔﻮﻳﻢ و ﺗﻮﺿﻴﺤﺎﺗﻲ درﺑﺎرهي ﺑﺮﺧﻲ ‪header file‬ﻫﺎ و ﺑﻌﻀﻲ ﺗﻮاﺑﻊ ﺧﺎص آنﻫﺎ‬ ‫ﺧﻮاﻫﻢ داد )ﻣﺜﻞ ﺗﺎﺑﻊﻫﺎي ﻣﺮﺑﻮط ﺑﻪ اﻳﺠﺎد ﻓﺎﻳﻞ روي ‪ .(hard disk‬در ﭘﺎﻳﺎن ﻓﻘﻂ ﺑﺮاي ﺗﺸﻮﻳﻖ ﺷﻤﺎ ﺑﺮﻧﺎﻣﻪاي ﺳﺎده‬ ‫ﺑﺮاي ﻣﺤﻴﻂ وﻳﻨﺪوز ﺑﺪون ﺗﻮﺿﻴﺢ زﻳﺎد اراﺋﻪ ﻣﻲﻛﻨﻢ‪.‬‬

‫د‪ "#‬ره ‪preprocessor‬‬

‫دﺳﺘﻮرﻫﺎي ‪ ،preprocessor‬دﺳﺘﻮرﻫﺎﻳﻲ ﻫﺴﺘﻨﺪ ﻛﻪ ﻗﺒﻞ از ‪ compile‬ﺷﺪن ﺑﺮﻧﺎﻣﻪ اﺟﺮا ﻣﻲﺷﻮﻧﺪ و ﺗﻐﻴﻴﺮاﺗﻲ را‬ ‫در ﻣﺘﻦ ﺑﺮﻧﺎﻣﻪ و در ‪ compiler‬اﻳﺠﺎد ﻣﻲﻛﻨﻨﺪ‪ .‬ﺑﻌﺪ از اﺟﺮاي ﺑﺮﻧﺎﻣﻪ و اﻧﺠﺎم ﺗﻐﻴﻴﺮات ﻻزم در ‪source code‬‬ ‫)ﻣﺘﻦ ﺑﺮﻧﺎﻣﻪ( و ‪ compiler ،compiler‬ﺷﺮوع ﺑﻪ ‪ compile‬ﻛﺮدن ﻣﺘﻦ ﺗﻐﻴﻴﺮ ﻛﺮدهي ﺑﺮﻧﺎﻣﻪ ﻣﻲﻛﻨﺪ‪ .‬ﻫﺮ دﺳﺘﻮر‬ ‫‪ preprocessor‬ﻣﻌﻤﻮﻻ در ﻳﻚ ﺧﻂ ﺟﺪاﮔﺎﻧﻪ ﻗﺮار ﻣﻲﮔﻴﺮد ﻛﻪ ﺑﺎ ‪ #‬ﺷﺮوع ﻣﻲﺷﻮد‪ .‬اﻏﻠﺐ ‪compiler‬ﻫﺎ رﻧﮓ‬ ‫ﺧﺎﺻﻲ ﺑﺮاي آنﻫﺎ در ﻧﻈﺮ ﻣﻲﮔﻴﺮﻧﺪ وﻟﻲ ﻣﻲﺷﻮد آن را ﺗﻐﻴﻴﺮ داد‪ .‬ﻣﻦ رﻧﮓ ﺳﺒﺰ را در زﻣﻴﻨﻪي آﺑﻲ ﭘﻴﺶ ﻧﻬﺎد ﻣﻲ‪-‬‬ ‫ﻛﻨﻢ‪:‬‬

‫ﺑﻪ اﺣﺘﻤﺎل زﻳﺎد ‪ compiler‬ﺷﻤﺎ ﻗﺎﺑﻠﻴﺖ ﺗﻐﻴﻴﺮ رﻧﮓ ﻣﺘﻦ ﺑﺮﻧﺎﻣﻪ و ‪ font‬آن را دارد‪.‬‬ ‫در ﻣﻮاردي ﻛﻪ دﺳﺘﻮر ﺑﻴﺶ از ﺣﺪ ﻃﻮﻻﻧﻲ ﺑﺎﺷﺪ و ﻗﺮار دادن آن در ﻳﻚ ﺳﻄﺮ ﻣﻨﺎﺳﺐ ﻧﺒﺎﺷﺪ ﺑﺎ ﮔﺬاﺷﺘﻦ »\« در‬ ‫اﻧﺘﻬﺎي ﺧﻂ ﻣﻲﺷﻮد ﺑﻘﻴﻪي دﺳﺘﻮر را ﺑﻪ ﺳﻄﺮ ﺑﻌﺪي ﻣﻨﺘﻘﻞ ﻛﺮد‪.‬‬

‫‪296‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫در ﻣﻮرد دﺳﺘﻮر ‪ #include‬ﻗﺒﻼ ﺗﻮﺿﻴﺤﺎت ﻛﺎﻓﻲ دادهام و ﻧﻴﺎزي ﺑﻪ ﺗﻮﺿﻴﺢ ﺑﻴﺶ ﺗﺮ ﻧﻴﺴﺖ‪ .‬ﺑﻌﺪ از آن‪ ،‬ﻣﻬﻢ‬ ‫ﺗﺮﻳﻦ دﺳﺘﻮر ‪ ،preprocessor‬دﺳﺘﻮر ‪ #define‬اﺳﺖ‪ .‬دﺳﺘﻮر ‪ #define‬ﺑﺮاي ﺟﺎﻳﮕﺰﻳﻦ ﻛﺮدن ﺑﻪ ﻛﺎر‬ ‫ﻣﻲرود‪ .‬ﻣﺜﻼ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻫﻤﻪي ‪for‬ﻫﺎ در ﺑﺮﻧﺎﻣﻪ ﺑﻪ ‪ if‬ﺗﺒﺪﻳﻞ ﺷﻮﻧﺪ ﻣﻲﻧﻮﻳﺴﻴﻢ‪:‬‬ ‫‪#define for if‬‬

‫ﺑﻪ ﻣﺜﺎل زﻳﺮ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪#define for if‬‬ ‫)(‪int main‬‬ ‫{‬ ‫)‪for(2 > 1‬‬ ‫;"‪cout<< "2 > 1‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪2 > 1‬‬

‫در اﻳﻦ ﻣﺜﺎل ‪ preprocessor‬اول ‪ for‬را ﺑﺎ ‪ if‬ﺟﺎﻳﮕﺰﻳﻦ ﻣﻲﻛﻨﺪ و ﺑﻌﺪ ﺑﺮﻧﺎﻣﻪ ‪ compile‬ﻣﻲﺷﻮد‪ .‬اﮔﺮ ﺑﺨﻮاﻫﻴﺪ‬ ‫‪ source code‬را ﺑﻌﺪ از ﻋﻤﻠﻜﺮد ‪ preprocessor‬ﺑﺒﻨﻴﺪ در ‪ Visual C++ 2005‬ﻣﺴﻴﺮ زﻳﺮ‬ ‫| ‪Project | console Properties… | Configuration Properties | C/C++‬‬ ‫‪Preprocessor‬‬ ‫را از ﻃﺮﻳﻖ ﻣﻨﻮ ﻃﻲ ﻛﻨﻴﺪ و ﺟﻠﻮي ‪ Generate Preprocessed File‬ﻗﺮار دﻫﻴﺪ ‪Without Line‬‬ ‫)‪:Numbers(/EP /P‬‬

‫‪297‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫ﺑﻌﺪ ﺑﺮﻧﺎﻣﻪ را ‪ compile‬ﻛﻨﻴﺪ و از ﻃﺮﻳﻖ ‪ Windows‬ﺑﻪ ﻣﻜﺎﻧﻲ ﺑﺮوﻳﺪ ﻛﻪ ﻓﺎﻳﻞ ‪ .cpp‬ﺑﺮﻧﺎﻣﻪ ﺷﻤﺎ ﻗﺮار دارد‪.‬‬ ‫ﻓﺎﻳﻠﻲ ﺑﺎ ﭘﺴﻮﻧﺪ ‪ .i‬ﻣﺸﺎﻫﺪه ﻣﻲﻛﻨﻴﺪ ﻛﻪ ﻫﻤﺎن ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ ﺑﻌﺪ از ‪ preprocess‬ﺷﺪن اﺳﺖ‪:‬‬

‫در ‪ BDS 2006‬ﻓﺎﻳﻞ ‪ preprocess‬ﺷﺪه را ﺑﻪ راﺣﺘﻲ ﻣﻲﺷﻮد ﺑﺎ ‪) right – click‬راﺳﺖ ﻛﻠﻴﻚ( ﻛﺮدن روي‬ ‫ﻓﺎﻳﻞ در ﻗﺴﻤﺖ ‪ Project Manager‬و اﻧﺘﺨﺎب ‪ Preprocess‬دﻳﺪ‪:‬‬

‫‪298‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

:‫ اﮔﺮ ﺑﻨﻮﻳﺴﻴﻢ‬.‫ )ﻣﺎﻛﺮو( ﻣﻌﺮوف اﺳﺖ‬macro ‫ ﻣﻲﺷﻮد ﭼﻴﺰي ﺷﺒﻴﻪ ﺑﻪ ﺗﺎﺑﻊ ﺗﻌﺮﻳﻒ ﻛﺮد ﻛﻪ ﺑﻪ‬#define ‫ﺑﺎ‬ #define f(x) cout<< x;

:‫ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‬.‫ ﻣﻌﺎدل اﺳﺖ‬cout<< 3; ‫ ﺑﺎ ﻧﻮﺷﺘﻦ‬f(3) ‫آن وﻗﺖ ﻧﻮﺷﺘﻦ‬ #include <conio.h> #include <iostream> using namespace std; #define f(x) cout<< x; int main() { f(3<<endl) f("hello") _getch(); }

Output: 3 hello

.‫ ﺗﺒﺪﻳﻞ ﻣﻲﺷﻮد‬cout<< 3<<endl; ‫ ﺑﻪ‬f(3<<endl) ‫ ﺷﺪن‬compile ‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻗﺒﻞ از‬ :‫اﻳﻦ ﻣﺜﺎل ﺟﺎﻟﺐ اﺳﺖ‬ #include <conio.h> #include <iostream> using namespace std;

299

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪#define f(a) about‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int f(s) = 4‬‬ ‫;‪cout<< about‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪4‬‬

‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ‪ a‬در ‪ about‬ﺑﻪ ﻋﻨﻮان ﻣﺘﻐﻴﺮ در ﻧﻈﺮ ﮔﺮﻓﺘﻪ ﻧﺸﺪه‪ .‬ﺑﺮاي ﻫﻤﻴﻦ اﺳﺖ ﻛﻪ ﻧﻨﻮﺷﺘﻢ‪:‬‬ ‫;‪cout<< sbout‬‬

‫ﻣﺎﻛﺮوﻫﺎ ﻣﻲﺗﻮاﻧﻨﺪ ﭼﻨﺪ ﺗﺎ ﻣﺘﻐﻴﺮ ﻫﻢ داﺷﺘﻪ ﺑﺎﺷﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪#define mul1(a,b) a*b‬‬ ‫)‪#define mul2(a,b) (a)*(b‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪mul1(int,p) = new int‬‬ ‫;‪cout<< mul1(2+3,2) << endl‬‬ ‫;)‪cout<< mul2(2+3,2‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪8‬‬ ‫‪10‬‬

‫در واﻗﻊ آن ﭼﻪ در )(‪ main‬ﻣﻲﺑﻴﻨﻴﺪ ﺑﻪ ﺻﻮرت زﻳﺮ در ﻣﻲآﻳﺪ و ﺑﻌﺪ ‪ compile‬ﻣﻲﺷﻮد‪:‬‬ ‫;‪int*p = new int‬‬ ‫;‪cout<< 2+3*2 << endl‬‬ ‫;)‪cout<< (2+3)*(2‬‬ ‫;)(‪_getch‬‬

‫ﭼﻮن اوﻟﻮﻳﺖ * ﺑﻴﺶ از ‪ +‬اﺳﺖ‪ 2+3*2 ،‬ﺑﺮاﺑﺮ ﺑﺎ ‪ 2+6‬ﺑﺮاﺑﺮ ﺑﺎ ‪ 8‬اﺳﺖ‪ (2+3)*(2) .‬ﺑﺮاﺑﺮ ﺑﺎ ‪ 5*2‬ﺑﺮاﺑﺮ ﺑﺎ‬ ‫‪ 10‬اﺳﺖ‪.‬‬ ‫ﻣﺜﺎلﻫﺎي ﺑﺎﻻ ﻛﻤﻲ ﻏﻴﺮ ﻣﺘﻌﺎرﻓﻨﺪ‪ .‬ﻣﻌﻤﻮﻻ از ‪) #define‬ﻛﻪ ﺑﻪ آن دﺳﺘﻮر »ﺗﻌﺮﻳﻒ« ﻣﻲﮔﻮﻳﻨﺪ( ﺑﻪ ﻳﻜﻲ از ﺷﻜﻞ‪-‬‬ ‫ﻫﺎي زﻳﺮ اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪:‬‬ ‫‪#define M 2‬‬

‫‪300‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻛﻪ ﻣﺜﻞ ﺗﻌﺮﻳﻒ ﻳﻚ ﺛﺎﺑﺖ اﺳﺖ و‬ ‫)‪#define SQR(x) (x)*(x‬‬

‫ﻛﻪ ﺑﺮاي ﺗﻌﺮﻳﻒ ﺗﻮان ‪ 2‬اﺳﺖ و‬ ‫‪#define _CPP‬‬

‫ﻛﻪ ﺗﻘﺮﻳﺒﺎ ﻫﻴﭻ ﻛﺎري ﻧﻤﻲﻛﻨﺪ ﺑﻪ ﺟﺰ اﻳﻦ ﻛﻪ ﻣﻲﮔﻮﻳﺪ ‪ _CPP‬ﺗﻌﺮﻳﻒ ﺷﺪه اﺳﺖ )اﻟﺒﺘﻪ ‪_CPP‬ﻫﺎي ﻣﻮﺟﻮد در ﻣﺘﻦ‬ ‫ﺑﺮﻧﺎﻣﻪ را ﻫﻢ ﭘﺎك ﻣﻲﻛﻨﺪ( و‬ ‫‪#define far‬‬

‫ﻛﻪ ﻛﻠﻤﻪي ‪ far‬را )ﻛﻪ از ‪ C++‬ﺣﺬف ﺷﺪه( از ﺑﺮﻧﺎﻣﻪ ﺣﺬف ﻣﻲﻛﻨﺪ‪.‬‬ ‫ﻛﺎرﺑﺮد ﻣﻬﻢ دﻳﮕﺮ ‪ #define‬ﺗﻌﺮﻳﻒ ﻣﺎﻛﺮوﻫﺎﻳﻲ اﺳﺖ ﻛﻪ ﻗﺮار اﺳﺖ ﻛﺎر ﺗﺎﺑﻊ ‪ inline‬را اﻧﺠﺎم دﻫﻨﺪ‪ .‬ﻣﺜﻼ‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪#define f(x,y‬‬ ‫\‬ ‫{‬ ‫\‬ ‫;‪int a = x‬‬ ‫\‬ ‫;‪a++‬‬ ‫\‬ ‫\ ;‪cout<< a << endl‬‬ ‫;‪cout<< x+y‬‬ ‫\‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪f(2,3‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪3‬‬ ‫‪5‬‬

‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﺑﻪ ﺟﺎي )‪ f(2,3‬ﻳﻚ ‪ block‬ﻗﺮار ﻣﻲﮔﻴﺮد ﭼﻮن )‪ f(x,y‬را ﻳﻚ ‪ block‬ﮔﺮﻓﺘﻴﻢ‪ .‬ﻣﻲ‪-‬‬ ‫ﺗﻮاﻧﺴﺘﻴﻢ ﺑﺎ ﺣﺬف { و } در ‪ #define‬دﺳﺘﻮرات را ﺑﺪون ‪ block‬ﺗﻌﺮﻳﻒ ﻛﻨﻴﻢ‪ .‬در ‪ BDS 2006‬رﻧﮓ آن ﭼﻪ‬ ‫ﭘﺲ از ‪ #define‬ﻗﺮار ﻣﻲﮔﻴﺮد ﺑﺎ ﺧﻮد ‪ #define‬ﻳﻜﻲ اﺳﺖ‪:‬‬

‫‪301‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫در اﻳﻦ ﻛﺎرﺑﺮد‪ f() ،‬ﺑﻪ ﻧﺎﭼﺎر ‪ inline‬اﺳﺖ ﭼﻮن ﻗﺒﻞ از اﻳﻦ ﻛﻪ ‪ compiler‬ﻛﺎري ﺑﻜﻨﺪ‪ preprocessor ،‬آن‬ ‫را ﺟﺎﻳﮕﺰﻳﻦ ﻣﻲﻛﻨﺪ و اﺻﻼ ﻓﺮﺻﺖ ﺗﺼﻤﻴﻢ ﮔﻴﺮي ﺑﺮاي ﺧﻮد ‪ compiler‬ﺑﺎﻗﻲ ﻧﻤﻲﻣﺎﻧﺪ‪) .‬از ‪ compiler‬ﻛﺴﻲ‬ ‫ﺧﻴﺮي ﻧﺪﻳﺪه اﺳﺖ ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﺗﺎ ﺣﺪ اﻣﻜﺎن از آن درﺧﻮاﺳﺘﻲ ﻧﻤﻲﻛﻨﻴﻢ ﻣﺜﻼ درﺧﻮاﺳﺖ ‪ inline‬ﻛﺮدن ﺗﺎﺑﻊ ﻳﺎ‬

‫‪ register‬ﻛﺮدن ﻣﺘﻐﻴﺮ‬

‫(‬

‫ﺑﻪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫"‪#define f(x) "x‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪cout<< f(hello‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪x‬‬

‫ﻣﻦ ﻣﻲﺧﻮاﺳﺘﻢ ‪ hello‬ﭼﺎپ ﺷﻮد وﻟﻲ ‪ x‬ﭼﺎپ ﺷﺪه‪ .‬ﻋﻠﺘﺶ اﻳﻦ اﺳﺖ ﻛﻪ در ‪ x ،#define‬در "‪ "x‬ﺑﻪ ﻋﻨﻮان‬ ‫ﻣﺘﻐﻴﺮ در ﻧﻈﺮ ﮔﺮﻓﺘﻪ ﻧﺸﺪه‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ‪ hello‬ﭼﺎپ ﺑﺸﻮد ﺑﺎﻳﺪ ‪ #define‬را ﺑﻪ اﻳﻦ ﺻﻮرت ﺗﻐﻴﻴﺮ ﺑﺪﻫﻢ‪:‬‬ ‫‪#define f(x) #x‬‬

‫ﺗﺎ ﺑﺮﻧﺎﻣﻪ ﺑﻪ اﻳﻦ ﺻﻮرت در ﺑﻴﺎﻳﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪#define f(x) #x‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪cout<< f(hello‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪hello‬‬

‫‪302‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺣﺎﻻ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ )‪ f(x,y‬ﻳﻚ ﻣﺎﻛﺮو ﺑﺎﺷﺪ ﻛﻪ ‪ x‬و ‪ y‬را ﭘﺸﺖ ﺳﺮ ﻫﻢ ﺑﻪ ﺻﻮرت رﺷﺘﻪ ﭼﺎپ ﻣﻲﻛﻨﺪ ﻣﻲﺗﻮاﻧﻴﻢ‬ ‫ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫‪#define f(x,y) #x###y‬‬

‫در واﻗﻊ ﻋﻤﻠﮕﺮ ‪ ##‬ﻛﺎر ﭼﺴﺒﺎﻧﺪن رﺷﺘﻪﻫﺎ را ﺑﻪ ﻫﻢ اﻧﺠﺎم ﻣﻲدﻫﺪ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪#define f(x,y) #x##":/Windows/System32/"###y‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪cout<< f(C,TweakUI.exe‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪C:/Windows/System32/TweakUI.exe‬‬

‫اﻳﻦ ﻣﺜﺎل را ﻣﻲﺷﻮد ﺑﻪ ﺻﻮرت زﻳﺮ ﻫﻢ ﺗﻐﻴﻴﺮ داد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪#define f(x,y) #x##":/Windows/System32/"##y‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)"‪cout<< f(C,"TweakUI.exe‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪C:/Windows/System32/TweakUI.exe‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ اﻳﻦ ﻛﺎرﺑﺮد از ‪ #define‬ﮔﺎﻫﻲ ﻣﻲﺗﻮاﻧﺪ ﻛﺎر ﺑﺎ رﺷﺘﻪﻫﺎ را ﺧﻴﻠﻲ راﺣﺖ ﻛﻨﺪ‪ .‬اﻣﺎ ﻛﺎر آن ﻣﻨﺤﺼﺮ ﺑﻪ‬ ‫رﺷﺘﻪﻫﺎي ﺛﺎﺑﺖ ‪ literal‬اﺳﺖ‪.‬‬ ‫اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﺧﻄﻮﻃﻲ را ﺑﺮﺣﺴﺐ اﻳﻦ ﻛﻪ ﭼﻴﺰي ‪ #define‬ﺷﺪه ﻳﺎ ﻧﺸﺪه اﺿﺎﻓﻪ ﻳﺎ ﻛﻢ ﻛﻨﻴﻢ از دﺳﺘﻮرات‬ ‫‪ preprocessor #ifdef‬و ‪ #ifndef‬اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﭼﻴﺰي را ﻛﻪ ‪ #define‬ﺷﺪه ﭘﺎك‬ ‫ﻛﻨﻴﻢ )اﻧﮕﺎر ‪ #define‬ﻧﺸﺪه ﺑﺎﺷﺪ( از ‪ #undef‬اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ‪ .‬ﻣﺜﺎل زﻳﺮ ﻛﺎرﺑﺮد اﻳﻦﻫﺎ را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪303‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #define POLITE int main() { //-----------------------------------------part 1 #ifdef POLITE cout<< "What is your name, please?(1)\n"; // printed #endif #ifndef POLITE cout<< "Name?(1)\n"; #endif //------------------------------------end of part 1 #undef POLITE // where the action is //-----------------------------------------part 2 #ifdef POLITE // not defined cout<< "What is your name, please?(2)\n"; // not printed #endif #ifndef POLITE cout<< "Name?(2)\n"; // printed #endif //------------------------------------end of part 2 _getch(); }

Output: What is your name, please?(1) Name?(2)

.‫ ﺑﻪ وﺟﻮد آﻣﺪه‬#ifndef ‫ ﻳﺎ‬#ifdef ‫ ﺑﺮاي ﭘﺎﻳﺎن ﺑﺨﺸﻲ ﺑﻪ ﻛﺎر ﻣﻲرود ﻛﻪ ﺑﺎ‬#endif :‫ ﻛﺮد‬#undef ‫ﻣﺎﻛﺮوﻫﺎ را ﻫﻢ ﻣﻲﺷﻮد‬ #include <conio.h> #include <iostream> using namespace std; int f(int) { return 0; } #define f(x) x*x int main() { cout<< f(2) << endl; #undef f cout<< f(2) << endl; getch(); }

304

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪Output:‬‬ ‫‪4‬‬ ‫‪0‬‬

‫)‪f(2‬ي اول ﺑﻪ وﺳﻴﻠﻪي ﻣﺎﻛﺮوي ‪ f‬ﺑﺎ ‪ 2*2‬ﺟﺎﻳﮕﺰﻳﻦ ﻣﻲﺷﻮد و ﺗﺎﺑﻊ )(‪ ِ f‬ﺗﻌﺮﻳﻒ ﺷﺪه ﻓﺮاﺧﻮاﻧﻲ ﻧﻤﻲﺷﻮد‪ .‬ﺑﺎ‬ ‫‪ #undef‬ﻣﺎﻛﺮوي ‪ f‬ﻏﻴﺮ ﻓﻌﺎل ﻣﻲﺷﻮد و )‪f(2‬ي دوم را رﻫﺎ ﻣﻲﻛﻨﺪ ﺗﺎ ‪ compiler‬ﺑﻪ وﺿﻌﻴﺖ آن رﺳﻴﺪﮔﻲ‬ ‫ﻛﻨﺪ و ‪ compiler‬ﻫﻢ ﺗﺎﺑﻊ )(‪ f‬را ﻓﺮا ﻣﻲﺧﻮاﻧﺪ‬

‫‪.‬‬

‫اﮔﺮ ﻳﻚ ‪ header file‬ﺑﺎ ﻧﺎم ‪ myheader.h‬درﺳﺖ ﻛﻨﻴﺪ ﻣﻤﻜﻦ اﺳﺖ ﻻزم ﺑﺸﻮد ﭼﻨﺪ ﺑﺎر آن را ‪#include‬‬ ‫ﻛﻨﻴﺪ‪ .‬اﻣﺎ اﻏﻠﺐ اﻳﻦ ﻛﺎر اﻣﻜﺎن ﭘﺬﻳﺮ ﻧﻴﺴﺖ ﻣﺜﻼ اﮔﺮ ‪ myheader.h‬ﺣﺎوي ﺧﻄﻮط زﻳﺮ ﺑﺎﺷﺪ‪:‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪void f‬‬ ‫{‬ ‫;"‪cout<< "a function in header file\n‬‬ ‫}‬ ‫;‪int a‬‬

‫در اﻳﻦ ﺣﺎﻟﺖ ﻧﻤﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫>‪#include <myheader.h‬‬ ‫>‪#include <myheader.h‬‬

‫ﺑﺮاي اﻳﻦ ﻛﻪ اﻳﻦ ﻛﺎر اﻣﻜﺎن ﭘﺬﻳﺮ ﺑﺎﺷﺪ ﻣﻲﺗﻮاﻧﻴﻢ از ‪ #define‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ و ‪ myheader.h‬را ﺑﻪ اﻳﻦ ﺻﻮرت‬ ‫ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﻢ‪:‬‬ ‫‪#ifndef __MYHEADER‬‬ ‫‪#define __MYHEADER‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪void f‬‬ ‫{‬ ‫;"‪cout<< "a function in header file\n‬‬ ‫}‬ ‫;‪int a‬‬ ‫‪#endif‬‬

‫در اﻳﻦ ﺻﻮرت ﺣﺘﻲ اﮔﺮ ‪ 10‬ﺑﺎر ﻫﻢ ‪ myheader.h‬را ‪ #include‬ﻛﻨﻴﻢ اﺷﻜﺎﻟﻲ ﭘﻴﺶ ﻧﻤﻲآﻳﺪ و ﺑﺎ ﻳﻚ ﺑﺎر‬ ‫‪ #include‬ﻛﺮدن ﻓﺮﻗﻲ ﻧﺪارد ﭼﻮن در دﻓﻌﻪﻫﺎي ﺑﻌﺪي ‪ __MYHEADER‬ﺗﻌﺮﻳﻒ ﺷﺪه و ‪ #ifndef‬ﻣﺎﻧﻊ دوﺑﺎره‬ ‫ﺧﻮاﻧﻲ ‪ header file‬ﻣﻲﺷﻮد‪.‬‬ ‫دﺳﺘﻮر ‪ preprocessor‬ﻣﻬﻢ ﺑﻌﺪي دﺳﺘﻮر ‪ #if‬اﺳﺖ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬

‫‪305‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ using namespace std; int main() { const int a = 2; #if a > 2 cout<< "if\n"; #else cout<< "else\n"; #endif getch(); }

Output: else

‫ در اﻳﻦ‬a ‫ ﺛﺎﺑﺖ ﺑﻮدن‬BDS 2006 ‫ در‬.‫ را در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻣﻲﺑﻴﻨﻴﺪ‬#endif ‫ و‬#else ،#if ‫ﻧﺤﻮهي ﻛﺎرﺑﺮد‬ ‫ ﺑﻪ ﻣﺜﺎل زﻳﺮ ﻛﻪ‬.‫ اﻟﺰاﻣﻲ ﻧﻴﺴﺖ وﻟﻲ اﻳﻦ ﺧﻴﻠﻲ ﻫﻢ ﺧﻮب ﻧﻴﺴﺖ‬Visual C++ 2005 ‫ﺑﺮﻧﺎﻣﻪ اﻟﺰاﻣﻲ اﺳﺖ اﻣﺎ در‬ :‫ اﺟﺮا ﻧﻤﻲﺷﻮد ﻧﮕﺎه ﻛﻨﻴﺪ‬BDS 2006 ‫در‬ #include <conio.h> #include <iostream> using namespace std; int main() { int a = 2; a++; #if a > 2 cout<< "if\n"; #else cout<< "else\n"; #endif getch(); }

Output (Visual C++ 2005): else

:#else if ‫ اﺳﺖ ﺑﻪ ﻣﻌﻨﻲ‬#elif ‫ دﺳﺘﻮر دﻳﮕﺮ‬.‫ ﻧﺎدﻳﺪه ﮔﺮﻓﺘﻪ ﺷﺪه‬a++ ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬ #include <conio.h> #include <iostream> using namespace std; #define M 5 int main() { #if M > 5 cout<< "if\n"; #else if M == 5 cout<< "else if\n"; #endif

306

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪#if M > 5‬‬ ‫;"‪cout<< "if\n‬‬ ‫‪#elif M == 5‬‬ ‫;"‪cout<< "elif\n‬‬ ‫‪#endif‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪else if‬‬ ‫‪elif‬‬

‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺳﻌﻲ ﻛﺮدهام ﻣﻌﺎدل ﺑﻮدن ‪ #elif‬و ‪ #else if‬را ﻧﺸﺎن دﻫﻢ‪.‬‬ ‫دﺳﺘﻮر ‪ preprocessor‬دﻳﮕﺮ دﺳﺘﻮر ‪ #pragma‬اﺳﺖ‪ .‬اﻳﻦ دﺳﺘﻮر در ‪compiler‬ﻫﺎي ﮔﻮﻧﺎﮔﻮن ﺑﻪ ﺷﻜﻞﻫﺎي‬ ‫ﻣﺨﺘﻠﻔﻲ اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪ .‬دو ‪#pragma‬ي زﻳﺮ را ﻗﺒﻼ در ‪ BDS 2006‬ﻣﻌﺮﻓﻲ ﻛﺮدهام‪:‬‬ ‫‪#pragma argsused‬‬ ‫‪#pragma option –b‬‬

‫ﻛﻪ ‪ –b‬اﺳﻢ ﻳﻜﻲ از ﺗﻨﻈﻴﻤﺎت ‪ compiler‬اﺳﺖ‪ .‬ﺑﺮاي ﻳﺎﻓﺘﻦ اﺳﻢ ﺗﻨﻈﻴﻤﺎت ﺑﺎﻳﺪ از ﻃﺮﻳﻖ ﻣﻨﻮﻫﺎ آن ﺗﻨﻈﻴﻢ را ﭘﻴﺪا‬ ‫ﻛﻨﻴﺪ‪ .‬اﺳﻢ ﻫﺮ ﺗﻨﻈﻴﻢ ﻛﻨﺎر آن ﻧﻮﺷﺘﻪ ﺷﺪه‪.‬‬ ‫‪#pragma‬ي زﻳﺮ در ‪ Visual C++ 2005‬ﻛﺎرﺑﺮد دارد‪:‬‬ ‫‪#pragma region‬‬

‫ﺗﻜﻪ ﺑﺮﻧﺎﻣﻪ زﻳﺮ را در ﺟﺎﻳﻲ از ‪ editor‬در ‪ Visual C++ 2005‬ﺑﻨﻮﻳﺴﻴﺪ‪:‬‬ ‫‪#pragma region‬‬ ‫;‪int a = 2‬‬ ‫;‪cout<< a‬‬ ‫‪#pragma endregion‬‬

‫ﺑﻪ اﻳﻦ ﻋﻜﺲ ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬

‫ﻛﺎر ‪ #pragma region‬ﺑﻪ وﺟﻮد آوردن ﭼﻴﺰي اﺳﺖ ﻛﻪ دور آن ﺧﻂ ﻛﺸﻴﺪهام‪ .‬ﺑﺎ ‪ click‬روي آن ﺑﺨﺸﻲ از‬ ‫‪ code‬ﺑﻪ ﻃﻮر ﻣﻮﻗﺖ ﻧﺎﭘﺪﻳﺪ ﻣﻲﺷﻮد‪.‬‬

‫‪307‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪precompiled headers‬‬

‫وﻗﺘﻲ ﻳﻚ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﻳﻚ ﺑﺮﻧﺎﻣﻪ ﻣﻲﻧﻮﻳﺴﺪ ﺑﺎرﻫﺎ آن را ‪ compile‬ﻣﻲﻛﻨﺪ ﺗﺎ ﺑﻪ ﺷﻜﻞ ﻣﻮرد ﻧﻈﺮ در آﻳﺪ‪ .‬اﮔﺮ‬ ‫ﻗﺮار ﺑﺎﺷﺪ ﻫﺮ ﺑﺎر ﻛﻪ ﺑﺮﻧﺎﻣﻪ را ‪ compile‬ﻣﻲﻛﻨﻴﻢ ﻫﻤﻪي ‪header file‬ﻫﺎﻳﻲ ﻛﻪ اﺻﻼ ﺗﻐﻴﻴﺮ ﻧﻤﻲﻛﻨﻨﺪ ‪compile‬‬ ‫ﺷﻮﻧﺪ زﻣﺎن ‪ compile‬ﺷﺪن ﺑﻲ ﺧﻮدي زﻳﺎد ﻣﻲﺷﻮد )ﺑﻪ ﺧﺼﻮص در ‪ .(Visual C++ 2005‬ﺑﺮاي ﺟﻠﻮﮔﻴﺮي از‬ ‫اﻳﻦ ﻫﺪر رﻓﺘﻦ زﻣﺎن‪compiler ،‬ﻫﺎ ﺑﺨﺶﻫﺎي از ‪ source code‬را ﻛﻪ ﺗﻐﻴﻴﺮ ﻧﻤﻲﻛﻨﻨﺪ ‪ precompile‬ﻣﻲﻛﻨﻨﺪ و‬ ‫ﺣﺎﺻﻞ را در ‪file‬ي ذﺧﻴﺮه ﻣﻲﻛﻨﻨﺪ ﺗﺎ ﻧﻴﺎزي ﺑﻪ ‪ compile‬ﺷﺪن ﻣﺠﺪد ﻧﺒﺎﺷﺪ‪ .‬اﮔﺮ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺲ ﺑﻪ ‪compiler‬‬ ‫اﺟﺎزهي ‪ precompile‬ﻛﺮدن ﺑﺪﻫﺪ ﺑﺮﻧﺎﻣﻪي او ﺳﺮﻳﻊ ﺗﺮ ‪ compile‬ﻣﻲﺷﻮد‪ .‬ﺑﺎ اﺳﺘﻔﺎده از ﺗﻨﻈﻴﻤﺎت ‪compiler‬‬ ‫ﻣﻲﺗﻮاﻧﻴﺪ ‪ precompilation‬را ﻛﻨﺘﺮل ﻛﻨﻴﺪ‪.‬‬ ‫ﺑﺮاي ﻣﺘﻮﻗﻒ ﺷﺪن ‪ precompilation‬از‬ ‫‪#pragma hdrstop‬‬

‫اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪ .‬در ‪ BDS 2006‬ﻗﺮار دادن اﻳﻦ ‪ #pragma‬در ‪header file‬ﻫﺎ ﻫﻴﭻ اﺛﺮي ﻧﺪارد‪ .‬ﺑﺮاي ﭘﻴﺪا‬ ‫ﻛﺮدن ﺟﺰﺋﻴﺎت ﺑﻴﺶ ﺗﺮ درﺑﺎرهي ‪ precompilation‬ﺑﺎﻳﺪ ﺑﻪ ‪ help‬ﻣﻮﺟﻮد در ‪ compiler‬ﺧﻮدﺗﺎن ﻣﺮاﺟﻌﻪ‬ ‫ﻛﻨﻴﺪ‪ ،BDS 2006 .‬اﻃﻼﻋﺎت ‪ help‬در ‪compiler‬ﻫﺎي ‪ Microsoft‬را ﻫﻢ ﻧﻤﺎﻳﺶ ﻣﻲدﻫﺪ‪ .‬اﻳﻦ ﻧﺒﺎﻳﺪ ﺷﻤﺎ را‬ ‫ﮔﻤﺮاه ﻛﻨﺪ‪.‬‬

‫ وه از * ‪ ; <' R‬‬

‫ﻣﺎﻛﺮوﻫﺎﻳﻲ ﻫﺴﺘﻨﺪ ﻛﻪ ﺑﺪون اﻳﻦ ﻛﻪ در ‪ header file‬ﺧﺎﺻﻲ ﺗﻌﺮﻳﻒ ﺷﺪه ﺑﺎﺷﻨﺪ ﻳﺎ ﻣﺎ آنﻫﺎ را ﺗﻌﺮﻳﻒ ﻛﺮده‬ ‫ﺑﺎﺷﻴﻢ ﻗﺎﺑﻞ اﺳﺘﻔﺎدهاﻧﺪ‪ .‬اﻳﻦ ﻣﺎﻛﺮوﻫﺎ را از ﭘﻴﺶ ﺗﻌﺮﻳﻒ ﺷﺪه )‪ (predefined‬ﻣﻲﮔﻮﻳﻨﺪ‪.‬‬ ‫‪ (1‬ﻣﺎﻛﺮوي __‪:__DATE‬‬ ‫اﻳﻦ ﻣﺎﻛﺮو ﺗﺎرﻳﺦ را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪cout<< __DATE__ << endl‬‬ ‫;)(‪cout<< typeid(__DATE__).name‬‬ ‫;)(‪_getch‬‬

‫‪308‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ }

Output (BDS 2006): Feb 22 2009 char[12] Output (Visual C++ 2005): Feb 22 2009 char const [12]

:__FILE__ ‫( ﻣﺎﻛﺮوي‬2 :‫اﻳﻦ ﻣﺎﻛﺮو اﺳﻢ و آدرس ﻓﺎﻳﻠﻲ را ﻛﻪ در آن ﻗﺮار دارد ﺑﺮ ﻣﻲﮔﺮداﻧﺪ‬ #include <conio.h> #include <iostream> using namespace std; int main() { cout<< __FILE__ << endl; _getch(); }

Output (BDS 2006): G:\Important Files\My Documents\Borland Studio Projects\Console\Console.cpp Output (Visual C++ 2005): c:\documents and settings\administrator\my documents\visual studio 2005\projects \console\console\console.cpp :__LINE__ ‫( ﻣﺎﻛﺮوي‬3

:‫ﺷﻤﺎرهي ﺧﻄﻲ را ﻛﻪ آن ﻗﺮار ﮔﺮﻓﺘﻪ ﺑﺮﻣﻲﮔﺮداﻧﺪ‬ #include <conio.h> /* 1 */ #include <iostream> /* 2 */ using namespace std; /* 3 */ // /* 4 */ #define M cout<< __LINE__ << endl; /* 5 */ // /* 6 */ void f() /* 7 */ { /* 8 */ cout<< __LINE__ << endl; /* 9 */ } /* 10 */ int main() /* 11 */ { /* 12 */ cout<< __LINE__ << endl; /* 13 */ cout<< __LINE__ << endl; /* 14 */ M /* 15 */ f(); /* 16 */ cout<< typeid(__LINE__).name(); /* 17 */

309

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;)(‪_getch‬‬

‫‪/* 18 */‬‬ ‫‪/* 19 */‬‬

‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪13‬‬ ‫‪14‬‬ ‫‪15‬‬ ‫‪9‬‬ ‫‪int‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫‪13‬‬ ‫‪14‬‬ ‫‪15‬‬ ‫‪9‬‬ ‫‪long‬‬

‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ‪ 15 ،M‬را ﭼﺎپ ﻛﺮده ﻧﻪ ‪.5‬‬ ‫‪ (4‬ﻣﺎﻛﺮوي __‪:__TIME‬‬ ‫اﻳﻦ ﻣﺎﻛﺮو زﻣﺎن )ﺳﺎﻋﺖ( آﺧﺮﻳﻦ ‪ compilation‬را ﺑﺮﻣﻲﮔﺮداﻧﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪cout<< __TIME__ << endl‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪22:34:49‬‬

‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ __‪ __TIME‬زﻣﺎن آﺧﺮﻳﻦ ﺑﺎر ‪ compile‬ﻛﺮدن ﺑﺮﻧﺎﻣﻪ را ﻧﺸﺎن ﻣﻲدﻫﺪ ﻧﻪ زﻣﺎن ﺣﺎل‬ ‫را‪.‬‬ ‫‪ (5‬ﻣﺎﻛﺮوي __‪:__TIMESTAMP‬‬ ‫زﻣﺎن آﺧﺮﻳﻦ ﺗﻐﻴﻴﺮ ﻣﺘﻦ ﺑﺮﻧﺎﻣﻪ در ﻓﺎﻳﻠﻲ ﻛﻪ ﻣﺎﻛﺮو در آن ﻗﺮار دارد را ﺑﺮ ﻣﻲﮔﺮداﻧﺪ‪ .‬اي ﻣﺎﻛﺮو در ‪BDS‬‬ ‫‪ 2006‬و ‪ Dec_C++‬وﺟﻮد ﻧﺪارد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬

‫‪310‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪cout<< __TIMESTAMP__ << endl‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (Visual C++ 2005):‬‬ ‫‪Sun Feb 22 22:57:07 2009‬‬

‫در ‪ Visual C++ 2005‬ﻣﺎﻛﺮوﻫﺎي از ﭘﻴﺶ ﺗﻌﺮﻳﻒ ﺷﺪهي دﻳﮕﺮي ﻫﻢ ﻫﺴﺘﻨﺪ ﻛﻪ ﻣﻲﺗﻮاﻧﻴﺪ آنﻫﺎ را در ‪help‬‬ ‫ﭘﻴﺪا ﻛﻨﻴﺪ‪.‬‬

‫ " در @? ‪6‬‬

‫در ‪ Visual C++ 2005‬در ﻗﺴﻤﺖ ‪ Solution Explorer‬روي ﻗﺴﻤﺖ ﻧﺸﺎن داده ﺷﺪه در ﺷﻜﻞ زﻳﺮ‬ ‫‪ right-click‬ﻛﻨﻴﺪ )ﻛﻠﻴﻚ راﺳﺖ )ﻳﺎ ﻛﻠﻴﻚ ﭼﭗ اﮔﺮ ﭼﭗ دﺳﺖ ﻫﺴﺘﻴﺪ‬

‫و روي …‪ New Item‬ﻛﻪ در ﺷﻜﻞ زﻳﺮ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻠﻴﻚ ﻛﻨﻴﺪ‪:‬‬

‫ﭘﻨﺠﺮه زﻳﺮ ﺑﺎز ﻣﻲﺷﻮد‪ .‬ﺑﻪ ﻗﺴﻤﺖ ‪ Code‬ﺑﺮوﻳﺪ‪:‬‬

‫‪311‬‬

‫‪www.pupuol.com‬‬

‫((‪:‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫و ﻳﻚ ﻓﺎﻳﻞ ﺑﺎ ﭘﺴﻮﻧﺪ ‪ .h‬و ﻓﺎﻳﻞ دﻳﮕﺮي ﺑﺎ ﭘﺴﻮﻧﺪ ‪ .cpp‬ﺑﻪ ﺑﺮﻧﺎﻣﻪي ﺧﻮدﺗﺎن اﺿﺎﻓﻪ ﻛﻨﻴﺪ‪ .‬ﺑﺎﻳﺪ ﻓﺎﻳﻞﻫﺎي ﺷﻤﺎ ﺑﻪ اﻳﻦ‬ ‫ﺻﻮرت ﺑﺎﺷﻨﺪ‪:‬‬

‫ﺷﻜﻞ زﻳﺮ ﻧﺤﻮهي اﻧﺠﺎم ﻫﻤﻴﻦ ﻛﺎر را در ‪ BDS 2006‬ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬

‫‪312‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫‪ BDS 2006‬ﻓﺎﻳﻞ ‪ .cpp‬و ‪ .h‬را ﻫﻤﺰﻣﺎن وارد ﻣﻲﻛﻨﺪ و ﻓﺎﻳﻞﻫﺎي ﺷﻤﺎ را ﺑﻪ اﻳﻦ ﺻﻮرت ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬

‫ﺑﻪ ﻓﺎﻳﻞ ‪ .bpf‬ﻛﻪ ﺧﻮد ﺑﻪ ﺧﻮد ﻫﻨﮕﺎم اﻳﺠﺎد ﺑﺮﻧﺎﻣﻪ ﺑﻪ وﺟﻮد آﻣﺪه ﻛﺎري ﻧﺪارﻳﻢ اﻳﻦ ﻓﺎﻳﻞ ﺗﻨﻬﺎ ﺑﻪ وﺳﻴﻠﻪي ‪Project‬‬ ‫‪) Manager‬ﻳﻌﻨﻲ ﻗﺴﻤﺘﻲ ﻛﻪ در ﺷﻜﻞ ﻗﺒﻞ ﻧﺸﺎن دادهام( اﺳﺘﻔﺎده ﻣﻲﺷﻮد‪ .‬ﻓﺎﻳﻞ ‪ .rc‬ﻧﺸﺎن داده ﺷﺪه در اﻳﻦ ﺟﺎ‬ ‫ﻓﻘﻂ وﻇﻴﻔﻪي دادن ‪ icon‬ﻣﻨﺎﺳﺐ ﺑﺮاي ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ را دارد و ﺣﺘﻲ اﮔﺮ آن را ﺣﺬف ﻛﻨﻴﺪ ﻣﺸﻜﻠﻲ ﭘﻴﺶ ﻧﻤﻲآﻳﺪ‬ ‫ﻣﻤﻜﻦ اﺳﺖ ﺑﻪ ﺟﺎي آن ﻳﻚ ﻓﺎﻳﻞ ﺑﺎ ﭘﺴﻮﻧﺪ ‪ .res‬ﻗﺮار داﺷﺘﻪ ﺑﺎﺷﺪ‪.‬‬ ‫وﻗﺘﻲ در ‪ Unit1.cpp ،BDS 2006‬و ‪ Unit1.h‬اﺿﺎﻓﻪ ﻣﻲﺷﻮﻧﺪ ﭼﻴﺰﻫﺎﻳﻲ از ﻗﺒﻞ در آنﻫﺎ ﻧﻮﺷﺘﻪ ﺷﺪه‪ .‬ﻓﻌﻼ‬ ‫آنﻫﺎ را ﭘﺎك ﻛﻨﻴﺪ و ﻓﺎﻳﻞﻫﺎ را ﺑﻪ ﺻﻮرت زﻳﺮ ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﺪ و ﺑﺮﻧﺎﻣﻪ را اﺟﺮا ﻛﻨﻴﺪ‪:‬‬ ‫‪Console.cpp:‬‬ ‫>‪#include <conio.h‬‬ ‫"‪#include "Unit1.h‬‬ ‫)(‪int main‬‬

‫‪313‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { f(); Cat Tom; Tom.Meow(); _getch(); }

Unit1.cpp: #pragma hdrstop #include "Unit1.h" void f() { cout<<"f()\n"; } void Cat::Meow() { cout<< "Meow\n"; }

Unit1.h: #ifndef Unit1H #define Unit1H #include<iostream> using namespace std; void f(); class Cat { public: void Meow(); }; #endif

Output: f() Meow

‫ )و ﺧﻮد آن را( ﭘﺎك ﻛﻨﻴﺪ و از‬project ‫ داد ﻫﻤﻪي ﻓﺎﻳﻞﻫﺎي‬error ،Visual C++ 2005 ‫ در‬linker ‫اﮔﺮ‬ ‫ روي ﻫﺎرد ﺑﺮوﻳﺪ ﻛﻪ ﻣﻌﻤﻮﻻ‬project ‫ و ﻓﺎﻳﻞﻫﺎ را ﺑﺴﺎزﻳﺪ )ﺑﺮاي اﻳﻦ ﻛﺎر ﺑﺎﻳﺪ ﺑﻪ ﻣﺤﻞ ذﺧﻴﺮه ﺷﺪن‬project ‫ﻧﻮ‬ ‫ در وﺿﻌﻴﺘﻲ‬compiler ‫ ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﻧﺒﺎﻳﺪ‬.(‫ ﻗﺮار دارد‬My Document / Visual Studio 2005 ‫در‬ ‫ ﻣﻌﻤﻮﻻ ﺗﻨﻈﻴﻤﺎت را ﻃﻮري ﺗﻐﻴﻴﺮ‬project ‫ از ﻧﻮ ﺳﺎﺧﺘﻦ‬.‫ ﺷﺪه ﺗﻮﻟﻴﺪ ﻛﻨﺪ‬preprocess ‫ﻗﺮار داﺷﺘﻪ ﺑﺎﺷﺪ ﻛﻪ ﻓﺎﻳﻞ‬ ِ ‫ ﺧﻮد ﺷﻤﺎ ﻣﻲﺗﻮاﻧﻴﺪ ﺑﺎ ﭘﻴﻤﺎﻳﺶ ﻣﺴﻴﺮ‬.‫ ﺷﺪه ﺗﻮﻟﻴﺪ ﻧﺸﻮد‬preprocess ‫ﻣﻲدﻫﺪ ﻛﻪ ﻓﺎﻳﻞ‬ Project | console Properties… | Configuration Properties | C/C++ | Generate Preprocessed File | No

314

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ compiler‬را ﻃﻮري ﺗﻨﻈﻴﻢ ﻛﻨﻴﺪ ﻛﻪ ﻓﺎﻳﻞ ‪ preprocess‬ﺷﺪه اﻳﺠﺎد ﻧﻜﻨﺪ‪.‬‬ ‫در ﻓﺎﻳﻞ ‪ Unit1.h‬ﺳﻪ ﺧﻂ زﻳﺮ وﺟﻮد دارد ﻛﻪ ﺑﺎﻋﺚ ﻣﻲﺷﻮد ﻣﺤﺘﻮﻳﺎت ﻓﺎﻳﻞ ﺑﻴﺶ از ﻳﻚ ﺑﺎر وارد ‪source‬‬ ‫‪ code‬ﻧﺸﻮد‪:‬‬ ‫‪#ifndef Unit1H‬‬ ‫‪#define Unit1H‬‬ ‫‪#endif‬‬

‫در ‪ Visual C++ 2005‬ﺑﻪ ﺟﺎي آنﻫﺎ ﻣﻲﺷﻮد در اول ‪ header file‬ﻧﻮﺷﺖ‪:‬‬ ‫‪#pragma once‬‬

‫ﻧﻜﺘﻪي ﻣﻬﻢ اﻳﻦ اﺳﺖ ﻛﻪ ﺗﻌﺮﻳﻒ ﺗﺎﺑﻊ )(‪ f‬و ‪ ِ method‬ﻣﻮﺟﻮد در ﻛﻼس ‪ Cat‬در ‪ Unit1.cpp‬اﺳﺖ و‬ ‫‪ Unit1.cpp‬اﺻﻼ در ‪ #include ،console.cpp‬ﻧﺸﺪه و ﺑﻪ ﺟﺎي آن ﻓﻘﻂ ‪ #include ،Unit1.h‬ﺷﺪه‪.‬‬ ‫ﺑﻪ اﻳﻦ ﻧﻜﺘﻪ ﻫﻢ ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﮔﺮﭼﻪ‬ ‫‪#ifndef Unit1H‬‬ ‫‪#define Unit1H‬‬ ‫‪#endif‬‬

‫ﻓﻘﻂ ﻳﻚ ﺑﺎر اﺟﺎزه وارد ﺷﺪن ﻣﺤﺘﻮﻳﺎت ‪ Unit1.h‬را ﻣﻲدﻫﺪ‪ Unit1.h ،‬در ﻫﺮ ﻛﺪام از دو ﻓﺎﻳﻞ ‪.cpp‬‬ ‫‪ #include‬ﺷﺪه‪.‬‬

‫ ‪extern‬‬

‫ﺑﺎ اﺳﺘﻔﺎده از ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ extern‬ﻣﻲﺗﻮاﻧﻴﺪ از ﺗﺎﺑﻌﻲ ﻛﻪ در ﻓﺎﻳﻞ دﻳﮕﺮي ﺗﻌﺮﻳﻒ ﺷﺪه اﺳﺘﻔﺎده ﻛﻨﻴﺪ ﺑﺪون اﻳﻦ‬ ‫ﻛﻪ آن ﻓﺎﻳﻞ ‪ #include‬ﺑﺸﻮد‪ .‬ﺑﻪ ﻋﺒﺎرت ﺑﻬﺘﺮ ﺑﺎ ‪ extern‬ﺗﺎﺑﻊ ﻳﺎ ﻣﺘﻐﻴﺮي را ﻣﻌﺮﻓﻲ ﻣﻲﻛﻨﻴﻢ و ﺗﻌﺮﻳﻒ آن را در‬ ‫ﻓﺎﻳﻞ دﻳﮕﺮي اﻧﺠﺎم ﻣﻲدﻫﻴﻢ‪ .‬ﻓﺎﻳﻞﻫﺎي ‪ project‬را ﺑﻪ ﺻﻮرت زﻳﺮ ﺗﻐﻴﻴﺮ ﺑﺪﻫﻴﺪ و ﺑﺮﻧﺎﻣﻪ را اﺟﺮا ﻛﻨﻴﺪ‪:‬‬ ‫‪Console.cpp:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫;)(‪extern void f‬‬ ‫;‪extern int a‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪f‬‬ ‫;‪cout<< a‬‬

‫‪315‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Unit1.cpp:‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪void f‬‬ ‫{‬ ‫;"‪cout<<"f() in Unit1.cpp\n‬‬ ‫}‬ ‫;‪int a = 123456‬‬

‫‪Unit1.h:‬‬ ‫‪#ifndef Unit1H‬‬ ‫‪#define Unit1H‬‬ ‫‪#endif‬‬

‫‪Output:‬‬ ‫‪f() in Unit1.cpp‬‬ ‫‪123456‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ‪ a‬در ‪ console.cpp‬ﺑﻪ ﺻﻮرت ‪ extern‬ﻣﻌﺮﻓﻲ ﺷﺪه و در ‪ Unit1.cpp‬دوﺑﺎره ﻣﻌﺮﻓﻲ ﺷﺪه و ﺑﻪ‬ ‫آن ﻣﻘﺪار اوﻟﻴﻪ داده ﺷﺪه‪ .‬وﻗﺘﻲ در ‪ console.cpp‬ﻣﻘﺪار آن را ﭼﺎپ ﻣﻲﻛﻨﻴﻢ ﻣﻘﺪار اوﻟﻴﻪي داده ﺷﺪه در‬ ‫‪ Unit1.cpp‬ﭼﺎپ ﻣﻲﺷﻮد‪ .‬اﮔﺮ ﻛﻠﻤﻪي ‪ extern‬را ﭘﺎك ﻛﻨﻴﺪ ﻳﺎ ﺑﻪ ‪ a‬در ‪ console.cpp‬ﻣﻘﺪار اوﻟﻴﻪ ﺑﺪﻫﻴﺪ‬ ‫در ‪ BDS 2006‬ﻳﻚ ‪ warning‬و در ‪ Visual C++ 2005‬ﻳﻚ ‪ error‬درﻳﺎﻓﺖ ﻣﻲﻛﻨﻴﺪ ﻛﻪ ﻣﻲﮔﻮﻳﺪ ‪a‬‬

‫دوﺑﺎر ﺗﻌﺮﻳﻒ ﺷﺪه‪ f() .‬ﻫﻢ ﺑﻪ ﻫﻤﻴﻦ ﺻﻮرت ﺗﻌﺮﻳﻒ ﺷﺪه‪.‬‬ ‫اﮔﺮ ﺑﻪ ‪ a‬در ‪ console.cpp‬ﻣﻘﺪار اوﻟﻴﻪ ﺑﺪﻫﻴﺪ در ‪ BDS 2006‬ﻳﻚ ‪ warning‬درﻳﺎﻓﺖ ﻣﻲﻛﻨﻴﺪ وﻟﻲ ﺑﺮﻧﺎﻣﻪ‬ ‫اﺟﺮا ﻣﻲﺷﻮد و ﻣﻘﺪار اوﻟﻴﻪي داده ﺷﺪه در ‪ console.cpp‬ﭼﺎپ ﻣﻲﺷﻮد‪.‬‬ ‫اﮔﺮ;‪a = 123456‬‬

‫و ﻣﻲﺷﻮد ﻓﻘﻂ ﻧﻮﺷﺖ‬ ‫اﮔﺮ‬

‫‪ int‬ﺣﺬف ﺷﻮد ﻳﻚ ‪ linker error‬درﻳﺎﻓﺖ ﻣﻲﺷﻮد‪ .‬اﻟﺒﺘﻪ ﻧﻴﺎزي ﺑﻪ دادن ﻣﻘﺪار اوﻟﻴﻪ ﻧﻴﺴﺖ‬ ‫;‪a‬‬

‫‪.int‬‬

‫;‪int a = 123456‬‬

‫ﺑﻪ ﺟﺎي ‪ Unit1.cpp‬در ‪ Unit1.h‬ﻧﻮﺷﺘﻪ ﺷﻮد‪ ،‬ﺑﺎز ﻫﻢ ‪ linker error‬دارﻳﻢ‪ .‬در‬

‫واﻗﻊ ﺑﺎ ﻧﻮﺷﺘﻦ ‪ extern compiler‬در ﻓﺎﻳﻞﻫﺎي ﺑﺎ ﭘﺴﻮﻧﺪ ‪ .cpp‬ﺑﻪ دﻧﺒﺎل ﺗﻌﺮﻳﻒ ﻣﻲﮔﺮدد ﻧﻪ ‪ ..h‬ﺑﻪ ﺟﺎي‬ ‫;‪extern int a‬‬

‫ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫;‪extern "C++" int a‬‬

‫‪316‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ در "‪ "C++‬ﺣﺮف‬

‫‪C‬‬

‫ ‪X‬رگ ر ر‪ 0P3 . 8E‬ا‪ Z1 6 C4‬در ‪) .c /!GY L1 E Q1‬ﻛﻪ‬

‫ﻣﺮﺑﻮط ﺑﻪ زﺑﺎن ‪ C‬اﺳﺖ( ﻗﺮار داﺷﺘﻪ ﺑﺎﺷﺪ‪ ،‬در اﻳﻦ ﺻﻮرت ﺑﻬﺘﺮ اﺳﺖ )وﻟﻲ ﻓﻌﻼ اﻟﺰاﻣﻲ ﻧﻴﺴﺖ( ﻛﻪ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;‪extern "C" int a‬‬

‫اﻟﺒﺘﻪ )اﮔﺮ ﻓﺎﻳﻠﻲ ﻗﺒﻼ ﺑﺎ ‪ compile ،C ِ compiler‬ﻧﺸﺪه ﺑﺎﺷﺪ‪ "C++" (،‬و "‪ "C‬ﺑﻴﺶ ﺗﺮ ﺑﺮاي ﺗﻮﺿﻴﺢ ﻫﺴﺘﻨﺪ و‬ ‫ﻋﻤﻼ ﻧﻘﺶ ﺧﺎﺻﻲ ﻧﺪارﻧﺪ‪ .‬در ﺑﺨﺶ ﺑﻌﺪ ﺑﻪ ﻃﻮر ﻣﻔﺼﻞ درﺑﺎرهي ‪ extern‬و ﻛﺎﺑﺮدﻫﺎي آن ﺗﻮﺿﻴﺢ ﻣﻲدﻫﻢ‪.‬‬

‫‪linkage‬‬

‫ﺑﻌﺪ از آﺷﻨﺎﻳﻲ ﺑﺎ ﻧﻮﺷﺘﻦ ﺑﺮﻧﺎﻣﻪ در ﭼﻨﺪ ﻓﺎﻳﻞ‪ ،‬ﺧﻮب اﺳﺖ ﻛﻤﻲ درﺑﺎرهي وﻳﮋﮔﻲﻫﺎي ﺑﺮﻧﺎﻣﻪﻫﺎي ‪ C++‬و ﻣﺮاﺣﻞ‬ ‫ﺳﺎﺧﺘﻦ ﻳﻚ ﻓﺎﻳﻞ اﺟﺮاﻳﻲ ﺣﺮف ﺑﺰﻧﻢ‪.‬‬ ‫ﻳﻚ ﺑﺮﻧﺎﻣﻪي ‪ C++‬از ﭼﻨﺪ ﺗﺎ ﻓﺎﻳﻞ ﺗﺸﻜﻴﻞ ﺷﺪه ﻛﻪ ﺑﻪ ﻫﺮ ﻛﺪام ﻳﻚ ‪ source file‬ﻣﻲﮔﻮﻳﻴﻢ‪ .‬ﻫﺮ ‪source‬‬ ‫‪ file‬را ﻫﻤﺮاه ﺑﺎ ﻫﻤﻪي ﻓﺎﻳﻞﻫﺎﻳﻲ ﻛﻪ در آن ‪ #include‬ﻣﻲﺷﻮد ﻳﻚ ‪ translation unit‬ﻳﺎ ﻓﻘﻂ ‪unit‬‬ ‫ﻣﻲﮔﻮﻳﻴﻢ‪ .‬ﺑﻌﺪ از ‪ compile‬ﻛﺮدن ﺑﺮﻧﺎﻣﻪ‪ ،‬از ﻫﺮ ‪ unit‬ﻳﻚ ﻓﺎﻳﻞ ﺑﺎ ﭘﺴﻮﻧﺪ ‪ .obj‬ﺳﺎﺧﺘﻪ ﻣﻲﺷﻮد‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ از‬ ‫ﺻﺤﺖ اﻳﻦ ﺣﺮف ﻣﻄﻤﺌﻦ ﺑﺸﻮﻳﺪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ را اﺟﺮا ﻛﻨﻴﺪ‪:‬‬ ‫‪Console.cpp:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Unit1.cpp:‬‬ ‫;‪int s‬‬

‫‪Unit1.h:‬‬ ‫‪#ifndef Unit1H‬‬ ‫‪#define Unit1H‬‬ ‫‪#endif‬‬

‫‪Output: empty‬‬

‫‪317‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺑﻌﺪ از اﺟﺮاي ﺑﺮﻧﺎﻣﻪ در ‪ folder‬ﻣﺨﺼﻮص ‪ project‬ﺧﻮد ﺑﮕﺮدﻳﺪ ﺗﺎ ﻓﺎﻳﻞﻫﺎي ﻧﺸﺎن داده ﺷﺪه در ﺗﺼﻮﻳﺮ زﻳﺮ را‬ ‫ﭘﻴﺪا ﻛﻨﻴﺪ‪:‬‬

‫اﻳﻦ دو ﺗﺎ ﻓﺎﻳﻞ ﻗﺒﻞ از ﺑﻪ وﺟﻮد آﻣﺪن ﻓﺎﻳﻞ ‪.exe‬ي ﺑﺮﻧﺎﻣﻪ اﻳﺠﺎد ﻣﻲﺷﻮﻧﺪ و ‪ linker‬ﺑﺎ اﺳﺘﻔﺎده از آنﻫﺎ )و ﻓﺎﻳﻞ‪-‬‬ ‫ﻫﺎي دﻳﮕﺮ( )و ارﺗﺒﺎط دادن آنﻫﺎ( ﻓﺎﻳﻞ ‪ .exe‬را ﻣﻲﺳﺎزد‪.‬‬ ‫ارﺗﺒﺎط دادن ﻓﺎﻳﻞﻫﺎ ﺗﻮﺳﻂ ‪ linker‬ﺑﺮاي ﺳﺎﺧﺘﻦ ﻓﺎﻳﻞ ‪.exe‬ي ﻧﻬﺎﻳﻲ ‪ linkage‬ﮔﻔﺘﻪ ﻣﻲﺷﻮد‪ .‬در واﻗﻊ اﮔﺮ‬ ‫ﻳﻚ ﻣﺘﻐﻴﺮ ﻳﺎ ﺗﺎﺑﻊ )ﻳﺎ ﻫﺮ ‪ identifier‬دﻳﮕﺮ( دو ﻳﺎ ﭼﻨﺪ ﺑﺎر در ﻳﻚ ‪ unit‬ﻳﺎ ﭼﻨﺪ ‪ unit‬ﺗﻌﺮﻳﻒ ﺑﺸﻮﻧﺪ ﻣﻮﻗﻊ‬ ‫ﻓﺮاﺧﻮاﻧﻲ اﻳﻦ ﻣﺴﺎﻟﻪ ﻫﺴﺖ ﻛﻪ ﺑﺎﻳﺪ ﺑﻪ ﻛﺪام ﺗﻌﺮﻳﻒ ﻣﺮاﺟﻌﻪ ﺑﺸﻮد‪ .‬ﻣﺜﻼ اﮔﺮ ﻳﻚ ‪ int‬ﺑﺎ ﻧﺎم ‪ a‬در ﻓﻀﺎي ﻋﻤﻮﻣﻲ‬ ‫دو ﺗﺎ ‪ unit‬ﻣﺨﺘﻠﻒ ﺗﻌﺮﻳﻒ ﺑﺸﻮﻧﺪ و در ﺗﺎﺑﻌﻲ ﻧﻮﺷﺘﻪ ﺷﻮد ‪a‬؛ ﻣﻨﻈﻮر ﻛﺪام ‪ a‬اﺳﺖ و ﺑﺎﻳﺪ ﺑﻪ ﻛﺪام ‪ a‬ﻣﺮاﺟﻌﻪ ﻛﺮد؟‬ ‫‪ linkage‬در واﻗﻊ ﻓﺮاﻳﻨﺪ ﻣﺮاﺟﻌﻪ ﺑﻪ ﺗﻌﺮﻳﻒ ﻣﻨﺎﺳﺐ اﺳﺖ‪.‬‬ ‫ﻫﺮ ‪) identifier‬ﻣﺜﻼ ﻫﺮ ﺗﺎﺑﻊ ﻳﺎ ﻫﺮ ﻣﺘﻐﻴﺮ( ﻣﻤﻜﻦ اﺳﺖ ﻳﻜﻲ از دو روش ‪ linkage‬زﻳﺮ را داﺷﺘﻪ ﺑﺎﺷﺪ‪:‬‬ ‫‪ linkage (1‬دا> ‪8‬‬

‫در اﻳﻦ روش ‪ identifier‬در ﺳﺮ ﺗﺎ ﺳﺮ ﻳﻚ ‪ unit‬ﺗﻨﻬﺎ ﻧﻤﺎﻳﻨﺪهي ﻳﻚ ﭼﻴﺰ اﺳﺖ‪.‬‬ ‫‪ > linkage (2‬ر‪8E‬‬

‫در ا‪ 01‬روش ‪ X.[ Q1 ,% 1 3/ identifier‬در ه ‪unit‬ﻫﺎي ا‪.C4‬‬ ‫ ا ا روش ‪ linkage‬را ﻣﺸﺨﺺ ﻛﻨﻴﻢ از ﻛﻠﻤﺎت ﻛﻠﻴﺪي ‪ static‬ﺑﺮاي ‪ linkage‬داﺧﻠﻲ و‬ ‫‪ extern‬ﺑﺮاي ‪ linkage‬ﺧﺎرﺟﻲ اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫‪Console.cpp:‬‬ ‫>‪#include <conio.h‬‬ ‫"‪#include "unit1.h‬‬ ‫;)(‪static void f‬‬

‫‪318‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪f‬‬ ‫;)(‪_getch‬‬ ‫}‬ ‫)(‪void f‬‬ ‫{‬ ‫;"‪cout<< "f() in console.cpp\n‬‬ ‫}‬

‫‪Unit1.cpp:‬‬ ‫"‪#include "unit1.h‬‬ ‫)(‪void f‬‬ ‫{‬ ‫;"‪cout<< "f() in unit1.cpp\n‬‬ ‫}‬

‫‪Unit1.h:‬‬ ‫‪#ifndef Unit1H‬‬ ‫‪#define Unit1H‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪#endif‬‬

‫‪Output:‬‬ ‫‪f() in console.cpp‬‬

‫ﺗﺎﺑﻊ )(‪ f‬در ‪ console.cpp‬ﺑﻪ ﺻﻮرت ‪ static‬ﻣﻌﺮﻓﻲ ﺷﺪه و ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ روش ‪ linkage‬آن داﺧﻠﻲ اﺳﺖ‬ ‫و ‪ linker‬ﺑﺮاي ﺗﻌﺮﻳﻒ ﻛﺎﻣﻞ آن‪ ،‬ﺗﻨﻬﺎ ﻓﺎﻳﻞ ‪) console.cpp‬ﻳﺎ اﮔﺮ ﺑﺨﻮاﻫﻢ دﻗﻴﻖ ﺗﺮ ﺑﮕﻮﻳﻢ ﻓﺎﻳﻞ‬ ‫‪ (console.obj‬را ﻣﻲﮔﺮدد‪ .‬اﮔﺮ ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ static‬ﺣﺬف ﺷﻮد ﻳﺎ ﺑﻪ ﺟﺎي آن ‪ extern‬ﻗﺮار ﺑﮕﻴﺮد‬ ‫‪compiler‬ﻫﺎي ‪ Microsoft‬ﻳﻚ ‪ error‬از ﻃﺮف ‪ linker‬ﻣﻲﮔﻴﺮﻧﺪ‪ .‬ﭘﻴﺎم اﻳﻦ ‪ error‬اﻳﻦ اﺳﺖ ﻛﻪ )(‪ f‬در‬ ‫دو ﺟﺎ ﺗﻌﺮﻳﻒ ﺷﺪه‪ .‬در واﻗﻊ وﻗﺘﻲ ﻛﻠﻤﻪي ‪ static‬ﺣﺬف ﺑﺸﻮد ‪ linker‬ﻛﻞ ﻓﺎﻳﻞﻫﺎ را ﺑﺮاي ﭘﻴﺪا ﻛﺮدن‬ ‫ﺗﻌﺮﻳﻒ‪ ،‬ﻣﻲﮔﺮدد و دو ﺗﻌﺮﻳﻒ ﭘﻴﺪا ﻣﻲﻛﻨﺪ و ﭘﻴﺎم ﺧﻄﺎ ﺻﺎدر ﻣﻲﻛﻨﺪ‪ .‬اﻟﺒﺘﻪ ‪ BDS 2006‬ﻫﻴﭻ ‪error‬ي ﻧﻤﻲﮔﻴﺮد‬ ‫ﺷﺎﻳﺪ ﺑﻪ اﻳﻦ ﻋﻠﺖ ﻛﻪ ‪linker‬ﻫﺎي ‪ Borland‬ﺑﻪ ﻣﺤﺾ ﭘﻴﺪا ﻛﺮدن اوﻟﻴﻦ ﺗﻌﺮﻳﻒ‪ ،‬ﮔﺸﺘﻦ را ﻣﺘﻮﻗﻒ ﻣﻲﻛﻨﻨﺪ‪.‬‬ ‫ﺑﻪ اﻳﻦ ﺗﺮﺗﻴﺐ اﮔﺮ در ﻳﻚ ‪ unit‬ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;)(‪extern void f‬‬

‫ﻣﻲﺷﻮد ﺗﻌﺮﻳﻒ ِ )(‪ f‬را در ﻫﻤﺎن ‪ unit‬ﻳﺎ در ‪unit‬ﻫﺎي دﻳﮕﺮ اﻧﺠﺎم داد و اﮔﺮ در ﻳﻚ ‪ unit‬ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫;)(‪static void f‬‬

‫‪319‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺗﻌﺮﻳﻒ ِ)(‪ f‬را ﺑﺎﻳﺪ ﻓﻘﻂ در ﻫﻤﺎن ‪ unit‬ﻧﻮﺷﺖ‪.‬‬ ‫ﻧﻮﺷﺘﻦ ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪ extern‬ﺑﺮاي ﺗﺎﺑﻊﻫﺎ اﻟﺰاﻣﻲ ﻧﻴﺴﺖ‪ .‬ﺗﺎﺑﻊﻫﺎﻳﻲ ﻛﻪ ﺟﻠﻮي آنﻫﺎ ﻛﻠﻤﻪي ﻛﻠﻴﺪي ‪static‬‬

‫ﻧﻴﺴﺖ ﺑﻪ ﻃﻮر ‪ linkage ،default‬ﺧﺎرﺟﻲ دارﻧﺪ ﻳﻌﻨﻲ‬ ‫;)(‪extern void f‬‬

‫ﺑﺎ‬ ‫;)(‪void f‬‬

‫ﻓﺮﻗﻲ ﻧﺪارد‪.‬‬ ‫ﺣﺎﻻ ﻓﺎﻳﻞﻫﺎﻳﻲ را ﻣﻄﺎﺑﻖ ﺷﻜﻞﻫﺎي زﻳﺮ ﺑﻪ ‪ project‬ﺧﻮدﺗﺎن اﺿﺎﻓﻪ ﻛﻨﻴﺪ‪.‬‬ ‫ﺑﺮاي ‪:Visual C++ 2005‬‬

‫ﻛﻪ ﺗﻨﻬﺎ ﺑﺮاي دﺳﺘﻪ ﺑﻨﺪي دو ﻓﻮﻟﺪر ﺑﺎ ﻧﺎمﻫﺎي ‪ unit1‬و ‪ unit2‬ﺑﺮاي ﻓﺎﻳﻞﻫﺎ ﺳﺎﺧﺘﻪام )ﺑﻪ اﻳﻦ ﻓﻮﻟﺪرﻫﺎ ‪ filter‬ﻫﻢ‬ ‫ﻣﻲﮔﻮﻳﻨﺪ(‪.‬‬ ‫ﺑﺮاي ‪:BDS 2006‬‬

‫‪320‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

:‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ را در ﻓﺎﻳﻞﻫﺎي اﻳﺠﺎد ﺷﺪه ﺑﻨﻮﻳﺴﻴﺪ و اﺟﺮا ﻛﻨﻴﺪ‬ console.cpp: #include <conio.h> #include "unit1.h" extern A a; void f(); int main() { f(); _getch(); }

Unit1.h: #ifndef Unit1H #define Unit1H #include <iostream> using namespace std; class A { public: int a; A(int a) { cout<< "A initialized in Unit1\n"; A::a = a; } }; #endif

Unit1.cpp: #include "unit1.h"

321

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ A a = 123456;

Unit2.h: #ifndef Unit2H #define Unit2H #include <iostream> using namespace std; void f(); class A { public: int a; A(int a) { cout<< "A initialized in Unit2\n"; A::a = a; } }; #endif

Unit2.cpp: #include "Unit2.h" extern A a; void f() { cout<< a.a << endl; cout<<"f() in unit2.cpp\n"; }

Output: A initialized in Unit1 123456 f() in unit2.cpp

.‫ اﻧﺠﺎم ﺷﺪه‬Unit1.cpp ‫ ﻣﻌﺮﻓﻲ ﺷﺪه و ﺗﻌﺮﻳﻒ آن در‬a ‫ ﻣﺘﻐﻴﺮ ﻋﻤﻮﻣﻲ‬Unit2.cpp ‫ و در‬console.cpp ‫در‬ ‫ ﺑﻪ ﻫﻤﻴﻦ ﺧﺎﻃﺮ ﻧﻮﺷﺘﻦ‬.‫ ﻳﻚ ﭘﺎراﻣﺘﺮي دارد‬constructor ‫ ﺗﻨﻬﺎ ﻳﻚ‬A ‫ﻛﻼس‬ A a;

‫ اﻣﺎ ﻧﻮﺷﺘﻦ‬.‫ﺧﻄﺎ دارد‬ extern A a;

‫ اﺳﺖ( ﺑﻪ‬constructor ‫ﺧﻄﺎ ﻧﺪارد ﭼﻮن ﻓﻘﻂ ﻳﻚ ﻣﻌﺮﻓﻲ اﺳﺖ و دادن ﻣﻘﺪار اوﻟﻴﻪ )ﻛﻪ ﻫﻤﺎن ﭘﺎراﻣﺘﺮ‬ .‫ ﺳﭙﺮده ﺷﺪه‬Unit1.cpp

322

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻳﻚ ﻧﻜﺘﻪي ﻗﺎﺑﻞ ﻣﻼﺣﻈﻪ و ﻣﻬﻢ اﻳﻦ اﺳﺖ ﻛﻪ دو ﻛﻼس ﺑﺎ ﻧﺎم ‪ ،A‬ﺗﻌﺮﻳﻒ ﺷﺪه‪ .‬ﻛﻼس ‪ A‬در ‪ Unit2‬ﺑﺎ ﻛﻼس ‪A‬‬

‫در دو ‪ unit‬دﻳﮕﺮ ﻣﺘﻔﺎوت اﺳﺖ‪ .‬ﺗﻌﺮﻳﻒ ﻫﺮ دو ﻛﻼس ‪ A‬ﻳﻚ ﺟﻮر اﺳﺖ اﻣﺎ ﻣﻲﺷﺪ ﺗﻌﺮﻳﻒ ﻛﻼس ‪ A‬در‬ ‫‪ Unit2.h‬را ﻃﻮر دﻳﮕﺮي اﻧﺠﺎم داد‪ BDS 2006 .‬ﺣﺘﻲ اﺟﺎزه ﻣﻲدﻫﺪ ﺑﻪ ﺟﺎي ‪ ،A‬اﺳﻢ دﻳﮕﺮي اﻧﺘﺨﺎب ﺷﻮد‪ .‬اﻣﺎ‬ ‫در ﻫﺮ ﺣﺎل روﺷﻦ اﺳﺖ ﻛﻪ ﻧﻤﻲﺷﻮد ﻧﺎم ﻣﺘﻐﻴﺮ ‪ a‬را ﻋﻮض ﻛﺮد‬

‫‪ .‬در ‪ BDS 2006‬ﺣﺘﻲ ﻣﻲﺷﻮد ﺑﻪ ﺟﺎي‬ ‫;‪A a = 123456‬‬

‫ﻧﻮﺷﺖ‬ ‫;‪int a = 123456‬‬

‫اﻟﺒﺘﻪ در اﻳﻦ ﺻﻮرت دﻳﮕﺮ ‪ constructor‬ﻛﻼس ‪ A‬ﻓﺮاﺧﻮاﻧﺪه ﻧﻤﻲﺷﻮد‪.‬‬ ‫ﮔﻔﺘﻢ ﻛﻪ دو ﺗﺎ روش ﺑﺮاي ‪ linkage‬دارﻳﻢ‪ ،‬روش داﺧﻠﻲ ‪ linkage‬و روش ﺧﺎرﺟﻲ ‪ .linkage‬ﺣﺎﻻ ﺑﺎﻳﺪ ﺑﮕﻮﻳﻢ‬ ‫ﻛﻪ دو ﻧﻮع ‪ linkage‬ﺑﺮاي ﺗﺎﺑﻊﻫﺎ و ﻣﺘﻐﻴﺮﻫﺎ ﻫﺴﺖ‪ linkage .‬از ﻧﻮع ‪ C‬و ‪ linkage‬از ﻧﻮع ‪ .C++‬ﺑﺎ‬ ‫"‪extern "C‬‬

‫ﻧﻮع ‪ linkage‬را ‪ C‬و ﺑﺎ‬ ‫"‪extern "C++‬‬

‫ﻧﻮع ‪ linkage‬را ‪ C++‬ﻗﺮار ﻣﻲدﻫﻴﻢ‪ .‬وﻗﺘﻲ ﻧﻮع ‪ C ،linkage‬ﺑﺎﺷﺪ؛ ‪ linker‬ﻛﻤﻲ ﻣﺘﻔﺎوت ﻋﻤﻞ ﻣﻲﻛﻨﺪ‪ .‬اﻟﺒﺘﻪ‬ ‫اﻳﻦ ﺗﻨﻬﺎ در ﻣﻮرد ﺗﺎﺑﻊﻫﺎ اﻫﻤﻴﺖ دارد‪ .‬وﻗﺘﻲ ‪ ،compiler‬ﺑﺮﻧﺎﻣﻪي ‪C++‬ي را ‪ compile‬ﻣﻲﻛﻨﺪ در ﻛﻨﺎر اﺳﻢ‬ ‫ﺗﺎﺑﻊﻫﺎ‪ ،‬ﻧﻮع ﻣﺘﻐﻴﺮﻫﺎي آنﻫﺎ را ﻫﻢ ﻗﺮار ﻣﻲدﻫﺪ ﺗﺎ ‪ overload‬ﻛﺮدن ﺗﺎﺑﻊﻫﺎ ﻣﻤﻜﻦ ﺑﺎﺷﺪ‪ .‬ﺑﻪ اﻳﻦ ﻛﺎر ‪name‬‬ ‫‪ mangling‬ﻣﻲﮔﻮﻳﻨﺪ‪ .‬وﻗﺘﻲ ﻗﺮار اﺳﺖ ‪ linker‬ﺗﺎﺑﻌﻲ را ﺑﻪ ﻓﺎﻳﻞﻫﺎي ‪ C‬ارﺗﺒﺎط ﺑﺪﻫﺪ ﻧﺒﺎﻳﺪ آن ﺗﺎﺑﻊ ﺑﺎ ‪name‬‬ ‫‪ compile ،mangling‬ﺷﺪه ﺑﺎﺷﺪ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﺑﻪ ‪ compiler‬ﺑﮕﻮﻳﻴﻢ در ﻣﻮرد ﻳﻚ ﺗﺎﺑﻊ ‪name‬‬ ‫‪ mangling‬اﻧﺠﺎم ﻧﺪﻫﺪ ﺑﺎﻳﺪ ﻧﻮع ‪ linkage‬آن ﺗﺎﺑﻊ را ‪ C‬ﻗﺮار ﺑﺪﻫﻴﻢ‪ .‬ﻣﺜﺎلﻫﺎي زﻳﺮ ﻧﺸﺎن ﻣﻲدﻫﻨﺪ ﻛﻪ ﭼﻪ ﻃﻮر‬ ‫ﻣﻲﺷﻮد ﻧﻮع ‪ linkage‬ﻳﻚ ﻳﺎ ﭼﻨﺪ ﺗﺎﺑﻊ را ‪ C‬ﻗﺮار داد‪:‬‬ ‫;)‪extern "C" void f(int‬‬ ‫"‪extern "C‬‬ ‫{‬ ‫;)(‪int g‬‬ ‫;)‪void h(int,char‬‬ ‫}‬ ‫"‪extern "C‬‬ ‫{‬ ‫>‪#include <stdio.h‬‬ ‫}‬

‫‪323‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫اﻟﺒﺘﻪ اﮔﺮ ﺑﻪ ‪ stdio.h‬و ﺑﻘﻴﻪي ‪header file‬ﻫﺎي ﻣﻌﺮوف ‪ C‬ﻧﮕﺎه ﻛﻨﻴﺪ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ در آنﻫﺎ در ﺟﺎي ﻣﻨﺎﺳﺐ‬ ‫"‪extern "C‬‬

‫ﺑﻪ ﻛﺎر رﻓﺘﻪ و دﻳﮕﺮ ﻧﻴﺎزي ﻧﻴﺴﺖ ﻣﺎ اﻳﻦ ﻛﺎر را اﻧﺠﺎم ﺑﺪﻫﻴﻢ‪ .‬ﺑﻨﺎﺑﺮاﻳﻦ ﺑﺪون ﻫﻴﭻ ﻣﺸﻜﻠﻲ ﻣﻲﺷﻮد‬

‫آنﻫﺎ را در ﺑﺮﻧﺎﻣﻪﻫﺎي ‪ C++‬ﺑﻪ ﻛﺎر ﺑﺮد‪.‬‬ ‫ﺑﻴﺎﻳﻴﺪ ﻛﺎري ﺟﺎﻟﺐ اﻧﺠﺎم ﺑﺪﻫﻴﻢ‪ .‬ﻣﻲﺧﻮاﻫﻴﻢ ﻳﻚ ﻓﺎﻳﻞ ‪ .cpp‬را ‪ compile‬ﻛﻨﻴﻢ ﺗﺎ ﻳﻚ ﻓﺎﻳﻞ ‪ .obj‬ﺑﻪ وﺟﻮد آﻳﺪ و‬ ‫ﺑﻌﺪ از اﻳﻦ ﻓﺎﻳﻞ ‪ .obj‬در ﺑﺮﻧﺎﻣﻪاي دﻳﮕﺮ اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪.‬‬ ‫ﻓﺎﻳﻞﻫﺎﻳﻲ ﺑﺎ ﻧﺎمﻫﺎي ‪ object.cpp ،console.cpp‬و ‪ object.h‬ﺑﻪ ‪ project‬اﺿﺎﻓﻪ ﻛﻨﻴﺪ و ﺑﺮﻧﺎﻣﻪ زﻳﺮ را در‬ ‫آنﻫﺎ ﺑﻨﻮﻳﺴﻴﺪ و ‪ compile‬ﻛﻨﻴﺪ ﺗﺎ ﻓﺎﻳﻞ ‪ object.obj‬اﻳﺠﺎد ﺷﻮد‪:‬‬ ‫‪console.cpp:‬‬ ‫>‪#include <conio.h‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪object.h:‬‬ ‫‪#ifndef objectH‬‬ ‫‪#define objectH‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫;)(‪void DabaDee‬‬ ‫;)(‪void DabaDie‬‬ ‫‪#endif‬‬

‫‪object.cpp:‬‬ ‫"‪#include "object.h‬‬ ‫)(‪void DabaDee‬‬ ‫{‬ ‫;"‪cout<< "void DabaDee()\n‬‬ ‫}‬ ‫)(‪void DabaDie‬‬ ‫{‬ ‫;"‪cout<< "void DabaDie()\n‬‬ ‫}‬

‫‪Output: empty‬‬

‫ﺣﺎﻻ دو ﻓﺎﻳﻞ ‪ object.cpp‬و ‪ object.h‬را از ‪ project‬ﺣﺬف ﻛﻨﻴﺪ و ﻓﺎﻳﻞ ‪ object.obj‬اﻳﺠﺎد ﺷﺪه را ﺑﻪ ﻓﺎﻳﻞ‪-‬‬ ‫ﻫﺎي ‪ project‬اﺿﺎﻓﻪ ﻛﻨﻴﺪ‪ .‬ﺑﺎﻳﺪ ‪ project‬ﺷﻤﺎ ﺑﻪ اﻳﻦ ﺷﻜﻞ ﺑﺎﺷﺪ‪:‬‬

‫‪324‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ :BDS 2006 ‫در‬

:Visual C++ 2005 ‫و در‬

:‫ ﺑﻨﻮﻳﺴﻴﺪ و اﺟﺮا ﻛﻨﻴﺪ‬console.cpp ‫ﺑﺮﻧﺎﻣﻪ زﻳﺮ را در‬ #include <conio.h> #include <iostream> using namespace std; void DabaDee(); void DabaDie(); int main() { DabaDee(); DabaDie(); _getch(); }

Output: void DabaDee() void DabaDie()

325

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ﺗﻌﺮﻳﻒ ﺗﺎﺑﻊﻫﺎي‬linker ‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ‬ void DabaDee(); void DabaDie();

.‫ ﺑﻪ ﻛﺎر ﻣﻲﺑﺮد‬console.exe ‫ ﭘﻴﺪا ﻣﻲﻛﻨﺪ و آنﻫﺎ را در اﻳﺠﺎد‬object.obj ‫را در‬ ‫ ﻣﻲﺷﻮد ﺧﻂ زﻳﺮ‬project ‫ ﺑﻪ‬object.obj ‫ ﺑﻪ ﺟﺎي اﺿﺎﻓﻪ ﻛﺮدن‬BDS 2006 ‫در‬ #pragma link "object.obj"

‫ ﺑﻌﺪ از‬console.cpp ‫را در‬ void DabaDee(); void DabaDie();

‫ در اﻳﻦ ﺻﻮرت ﺑﺮﻧﺎﻣﻪ ﺑﻪ ﺷﻜﻞ‬.‫اﺿﺎﻓﻪ ﻛﺮد‬ #include <conio.h> #include <iostream> using namespace std; void DabaDee(); void DabaDie(); #pragma link "object.obj" int main() { DabaDee(); DabaDie(); _getch(); }

‫" در‬object.obj" ‫ ﺑﻪ ﺟﺎي‬.‫ ﻧﻴﺴﺖ‬project ‫ ﺑﻪ‬object.obj ‫در ﻣﻲآﻳﺪ و دﻳﮕﺮ ﻧﻴﺎزي ﺑﻪ اﺿﺎﻓﻪ ﻛﺮدن‬ #pragma link "object.obj"

.‫ روي ﻫﺎرد ﻛﺎﻣﭙﻴﻮﺗﺮ را ﻗﺮار داد‬object.obj ‫ﻣﻲﺷﻮد آدرس ﻛﺎﻣﻞ‬ ‫ ﺳﺎﺧﺘﻪاﻳﻢ ﺑﻪ ﺟﺎي‬C++ ِ compiler ‫ را ﺑﺎ‬object.obj ‫ﭼﻮن‬ void DabaDee(); void DabaDie();

:‫ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‬ extern "C++" { void DabaDee(); void DabaDie(); }

:‫وﻟﻲ ﻧﻤﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‬ extern "C" { void DabaDee(); void DabaDie();

326

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫}‬

‫ﺣﺎﻻ اﮔﺮ اﻳﻦ ﻓﺎﻳﻞ ‪ object.obj‬ﺗﻮﺳﻂ ﻳﻚ ‪ C ِ compiler‬ﺳﺎﺧﺘﻪ ﺷﺪه ﺑﻮد ﺑﻪ ﺟﺎي‬ ‫;)(‪void DabaDee‬‬ ‫;)(‪void DabaDie‬‬

‫در ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ ﻣﻲﻧﻮﺷﺘﻴﻢ‪:‬‬ ‫"‪extern "C‬‬ ‫{‬ ‫;)(‪void DabaDee‬‬ ‫;)(‪void DabaDie‬‬ ‫}‬

‫در ﭘﺎﻳﺎن اﻳﻦ ﺑﺨﺶ ﻣﻲﮔﻮﻳﻢ ﻛﻪ ‪ extern‬را ﻣﻲﺷﻮد درون ﻳﻚ ﺗﺎﺑﻊ ﻫﻢ ﺑﻪ ﻛﺎر ﺑﺮد‪ .‬ﺑﻪ ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻛﻪ در ﻓﻘﻂ‬ ‫ﻳﻚ ‪ unit‬ﻧﻮﺷﺘﻪ ﺷﺪه دﻗﺖ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪extern int a‬‬ ‫;‪cout<< a‬‬ ‫;)(‪_getch‬‬ ‫}‬ ‫;‪int a = 123456‬‬

‫‪Output:‬‬ ‫‪123456‬‬

‫در ﺗﺎﺑﻊ )(‪ main‬ﻣﺘﻐﻴﺮ ‪ a‬ﻫﻤﺎن ﻣﺘﻐﻴﺮ ‪ a‬ﻋﻤﻮﻣﻲ اﺳﺖ ﻛﻪ ﺑﻌﺪ از )(‪ main‬ﺗﻌﺮﻳﻒ ﺷﺪه‪ .‬اﺣﺘﻤﺎﻻ ‪ linker‬ﺑﻌﺪ از‬ ‫رﺳﻴﺪن ﺑﻪ‬ ‫;‪extern int a‬‬

‫ﺷﺮوع ﺑﻪ ﮔﺸﺘﻦ ﺑﺮاي ﺗﻌﺮﻳﻒ ﻣﻲﻛﻨﺪ و ﺑﻪ‬ ‫;‪int a = 123456‬‬

‫ﻣﻲرﺳﺪ و آن را ﺑﻪ ﻋﻨﻮان ﺗﻌﺮﻳﻒ اﻧﺘﺨﺎب ﻣﻲﻛﻨﺪ‪ .‬ﺑﺮﻧﺎﻣﻪ را ﺑﻪ ﺻﻮرت زﻳﺮ ﺗﻐﻴﻴﺮ ﻣﻲدﻫﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a = 5‬‬

‫‪327‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { extern int a; cout<< a; } _getch(); } int a = 123456;

Output: 123456 main() ‫ را ﻗﺒﻞ از‬a ‫ اﮔﺮ‬.‫ در ﻓﻀﺎي ﻋﻤﻮﻣﻲ ﺑﻪ دﻧﺒﺎل ﺗﻌﺮﻳﻒ ﻣﻲﮔﺮدد ﻧﻪ داﺧﻞ ﺗﺎﺑﻊﻫﺎ‬linker ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ‬

.‫ ﻣﻌﺮﻓﻲ ﺷﻮد‬extern ‫ ﺑﺎ‬main() ‫ﺗﻌﺮﻳﻒ ﻣﻲﻛﺮدم دﻳﮕﺮ ﻻزم ﻧﺒﻮد در‬

6 ?@ ‫ و در‬#define

:‫ ﻣﺜﺎل زﻳﺮ اﻳﻦ را ﻧﺸﺎن ﻣﻲدﻫﺪ‬.‫ ﻣﻌﺘﺒﺮ اﺳﺖ‬unit ‫ ﺷﻮد ﺗﻨﻬﺎ در ﻫﻤﺎن‬#define ‫ ﭼﻴﺰي‬unit ‫اﮔﺮ در ﻳﻚ‬ console.cpp: #include "Unit1.h" void f(); int main() { #if defined BLUE_AND_FRIENDS cout<<"BLUE_AND_FRIENDS #defined in Console.cpp\n"; #endif #undef BLUE_AND_FRIENDS f(); _getch(); } #undef BLUE_AND_FRIENDS

Unit1.h: #define BLUE_AND_FRIENDS #include <conio.h> #include <iostream> using namespace std;

Unit1.cpp: #include "Unit1.h" void f() { #if defined BLUE_AND_FRIENDS cout<<"BLUE_AND_FRIENDS #defined in Unit1.cpp\n";

328

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪#endif‬‬ ‫‪#undef BLUE_AND_FRIENDS‬‬ ‫}‬ ‫‪#undef BLUE_AND_FRIENDS‬‬

‫‪Output:‬‬ ‫‪BLUE_AND_FRIENDS #defined in Console.cpp‬‬ ‫‪BLUE_AND_FRIENDS #defined in Unit1.cpp‬‬

‫‪ Unit1.h‬ﺑﻴﻦ دو ‪ unit‬ﺑﺮﻧﺎﻣﻪ ﻣﺸﺘﺮك اﺳﺖ‪ .‬در ﭘﺎﻳﺎن ِ ﻫﺮ ‪ #undef ،BLUE_AND_FRIENDS ،unit‬ﺷﺪه‬ ‫وﻟﻲ اﻳﻦ ﻛﺎر‪ BLUE_AND_FRIENDS ،‬را در ‪ unit‬دﻳﮕﺮ ‪ #undef‬ﻧﻜﺮده اﺳﺖ‪ .‬ﻫﻤﻴﻦ در ﻣﻮرد‬ ‫‪ #include‬ﻫﻢ درﺳﺖ اﺳﺖ‪.‬‬

‫از اﻳﻦ ﺑﻪ ﺑﻌﺪ ﻣﺎﻧﻨﺪ ﻓﺼﻞﻫﺎي ﻗﺒﻞ ﺑﺮﻧﺎﻣﻪﻫﺎ را در ﻓﻘﻂ ﻳﻚ ‪ unit‬ﻣﻲﻧﻮﻳﺴﻴﻢ‪.‬‬

‫ ‪6T‬ه ‪ R ; "A‬ا اد‬

‫‪ ] Q1‬د '‪ \.‬را در ‪) Editor‬ﺟﺎﻳﻲ ﻛﻪ ﺑﺮﻧﺎﻣﻪ را ﺗﺎﻳﭗ ﻣﻲﻛﻨﻴﻢ( ﻣﻲﺷﻮد ﺑﻪ ﺳﻪ ﺷﻜﻞ ﻧﺸﺎن داد‪:‬‬ ‫‪ (1‬در ﻣﺒﻨﺎي ‪ :10‬ﻣﺜﻼ ‪1364‬‬

‫‪ (2‬در ﻣﺒﻨﺎي ‪ :8‬ﻣﺜﻼ ‪) 02524‬ﺻﻔﺮ ﻃﺮف ﭼﭗ ﻧﺸﺎﻧﻪي ﻣﺒﻨﺎي ‪ 8‬اﺳﺖ(‬ ‫‪ (3‬در ﻣﺒﻨﺎي ‪ :16‬ﻣﺜﻼ ‪) 0x554 ( 0x‬ﺻﻔﺮ اﻛﺲ( در ﻃﺮف ﭼﭗ ﻧﺸﺎﻧﻪي ﻣﺒﻨﺎي ‪ 16‬اﺳﺖ(‬ ‫رﻗﻢﻫﺎﻳﻲ ﻛﻪ در ﻣﺒﻨﺎي ‪ 8‬ﻣﻲﺷﻮد ﻧﻮﺷﺖ ‪ 0,1,2,3,4,5,6,7‬ﻫﺴﺘﻨﺪ و رﻗﻢﻫﺎﻳﻲ ﻛﻪ در ﻣﺒﻨﺎي ‪ 16‬ﻣﻲﺷﻮد‬ ‫ﻧﻮﺷﺖ ﻋﺒﺎرﺗﻨﺪ از ‪ .0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f‬ﺑﻪ ﺟﺎي ‪ a,b,c,d,e,f‬ﻣﻲﺷﻮد از‬ ‫‪ A,B,C,D,E,F‬ﻫﻢ اﺳﺘﻔﺎده ﻛﺮد‪.‬‬ ‫ﺑﺮاي ﭼﺎپ ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ در ﻣﺒﻨﺎي ‪ 8‬از ‪ oct‬و ﺑﺮاي ﭼﺎپ در ﻣﺒﻨﺎي ‪ 16‬از ‪ hex‬اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int a = 1364‬‬ ‫;‪cout<< oct << a << endl‬‬

‫‪329‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ cout<< hex << a; _getch(); }

Output: 2524 554

:‫ﺣﺎﻻ اﻳﻦ ﺑﺮﻧﺎﻣﻪ را ﺑﺒﻴﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; int main() { cout<< 25L << endl; cout<< typeid(25L).name(); _getch(); }

Output: 25 long

‫ در‬long ‫ اﺳﺖ اﻣﺎ ﭼﻮن اﻧﺪازهي‬long ‫ وﻟﻲ از ﻧﻮع‬25 ‫ اﺳﺘﻔﺎده ﺷﺪه ﻛﻪ ﻫﻤﺎن ﻋﺪد‬25L ‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ از‬ .‫ ﮔﺮﻓﺖ‬25 ‫ را ﻣﻲﺷﻮد ﻫﻤﺎن‬25L ،‫ ﻳﻜﻲ اﺳﺖ‬int ‫ﻫﺎي اﻣﺮوزي ﺑﺎ‬compiler ‫ اﻳﻦ‬.25LL ‫ ﻣﺜﻼ‬.‫ ﻣﻲﮔﺬارﻳﻢ‬LL ‫__ در آﺧﺮ ﻋﺪد‬int64 ‫ ﻳﺎ ﻫﻤﺎن‬long long ‫ﺑﺮاي ﻣﺸﺨﺺ ﺷﺪن ﻧﻮع‬ :‫ﺑﺮﻧﺎﻣﻪ را ﺑﺒﻴﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; int main() { cout<< typeid(25).name() << endl; // output: int cout<< typeid(25LL).name() << endl; // output: __int64 cout<< typeid((long long)25).name() << endl; // output: __int64 cout<< typeid(0xffffffffffff).name() << endl; // output: __int64 _getch(); }

Output: int __int64 __int64

330

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ __int64

‫ ﺧﻮد ﺑﻪ ﺧﻮد‬compiler ،‫ ﺟﺎ ﺑﺸﻮد‬int ‫ ﭼﻮن ﻃﻮﻻﻧﻲ ﺗﺮ از آن اﺳﺖ ﻛﻪ در‬0xffffffffffff ‫در ﻣﻮرد‬ .‫__ در ﻧﻈﺮ ﻣﻲﮔﻴﺮد‬int64 ‫آن را‬

‫ ر

ه‬

2 ‫ ﺣﺎﻻ اﮔﺮ ﺑﺨﻮاﻫﻴﻢ ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﻛﻪ ﺗﻨﻬﺎ‬.‫ ﺑﻴﺖ دارد‬32 ‫ ﺑﺎﻳﺖ ﻳﺎ ﺑﻪ ﻋـﺒﺎرت دﻳﮕﺮ‬4 int n\ ‫ﺑﻴﺖ داﺷﺘﻪ ﺑﺎﺷﺪ ﺑﺎﻳﺪ ﭼﻪ ﻛﻨﻴﻢ؟‬ #include <conio.h> #include <iostream> using namespace std; struct A { unsigned d : 1; } ; int main() { A a; cout<< typeid(a.d).name() << endl; a.d = 0; for(int i = 0; i < 10; i++) { a.d++; cout<< a.d << endl; } _getch(); }

Output: unsigned int 1 0 1 0 1 0 1 0 1 0

331

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫در اﻳﻦ ﻣﺜﺎل ‪ A::d‬ﻧﻮع ‪ unsigned‬دارد وﻟﻲ ﺑﻴﺶ از ﻳﻚ ﺑﻴﺖ ﻧﺪارد ﺑﺮاي ﻫﻤﻴﻦ ﻳﺎ ﻣﻘﺪار ﺻﻔﺮ دارد ﻳﺎ ﻳﻚ و‬ ‫ﻏﻴﺮ از اﻳﻦ دو ﻣﻘﺪار‪ ،‬ﻣﻘﺪار دﻳﮕﺮي ﻧﻤﻲﺗﻮاﻧﺪ ﺑﮕﻴﺮد‪ .‬در‬ ‫‪struct A‬‬ ‫{‬ ‫;‪unsigned d : 1‬‬ ‫; }‬

‫»‪ «: 1‬ﻳﻌﻨﻲ ‪ d‬ﻓﻘﻂ ﻳﻚ ﺑﻴﺖ ﺣﺎﻓﻈﻪ داﺷﺘﻪ ﺑﺎﺷﺪ‪ .‬ﺑﻪ اﻋﻀﺎﻳﻲ از ﻳﻚ ﻛﻼس ﻛﻪ ﺗﻌﺪاد ﺑﻴﺖﻫﺎي آنﻫﺎ را ﺧﻮدﻣﺎن‬ ‫ﻣﺸﺨﺺ ﻣﻲﻛﻨﻴﻢ ‪ bit field‬ﻣﻲﮔﻮﻳﻨﺪ‪ .‬در ﺑﺎﻻ ‪ d‬ﻳﻚ ‪ bit field‬اﺳﺖ‪.‬‬ ‫ﺑﻪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪struct A‬‬ ‫{‬ ‫;‪int a : 1‬‬ ‫;‪int b : 3‬‬ ‫;}‬

‫‪// output: 4‬‬

‫)(‪int main‬‬ ‫{‬ ‫;}‪A u = {1,2‬‬ ‫;)‪cout<< sizeof(A‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪4‬‬

‫ﺑﻪ اﻳﻦ دو ﻧﻜﺘﻪ ﺑﺎﻳﺪ دﻗﺖ ﻛﺮد‪:‬‬ ‫‪ (1‬روش ﻣﻘﺪار اوﻟﻴﻪ دادن ﺑﻪ ‪bit field‬ﻫﺎ‬ ‫‪ (2‬اﻧﺪازهي ‪ A‬ﺗﻨﻬﺎ ‪ 4‬ﺑﺎﻳﺖ اﺳﺖ ﺑﺎ اﻳﻦ ﻛﻪ دو ﻣﺘﻐﻴﺮ ﺑﺎ ﻧﻮع ‪ int‬دارد‪ .‬ﻋﻠﺖ اﻳﻦ اﺳﺖ ﻛﻪ ‪ a‬و ‪ b‬روي ﻫﻢ‬ ‫رﻓﺘﻪ ﺑﺎ ‪ 4‬ﺑﻴﺖ ﺑﻴﺶ ﺗﺮ ﻧﻴﺎز ﻧﺪارﻧﺪ و در \‪ int n‬ﺟﺎ ﻣﻲﺷﻮﻧﺪ‪.‬‬ ‫‪bit field‬ﻫﺎ ﺗﻨﻬﺎ ﺑﺎﻳﺪ از اﻧﻮاع ‪ integral‬ﻳﻌﻨﻲ ‪،short ،unsigned ،int ،unsigned char ،char‬‬ ‫‪ __int64 ،unsigned short‬و ‪ unsigned __int64‬ﺑﺎﺷﺪ‪ integral .‬ﻳﻌﻨﻲ »ﻋﺪد ﺻﺤﻴﺤﻲ« )و‬ ‫رﺑﻄﻲ ﺑﻪ اﻧﺘﮕﺮال در رﻳﺎﺿﻲ ﻧﺪارد(‪ .‬در ‪ __int128 ،Visual C++ 2005‬ﻫﻢ دارﻳﻢ ﻛﻪ ﻫﻨﻮز وﻳﮋﮔﻲﻫﺎي‬

‫‪332‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻛﺎﻣﻞ دﻳﮕﺮ اﻧﻮاع ‪ integral‬ﺑﻪ آن داده ﻧﺸﺪه و ﺣﺘﻲ ﻋﻀﻮ ﻣﻌﻤﻮﻟﻲ ﻛﻼس ﻫﻢ ﻧﻤﻲﺗﻮاﻧﺪ ﺑﺎﺷﺪ ﭼﻪ ﺑﺮﺳﺪ ﺑﻪ ‪bit‬‬ ‫‪.field‬‬ ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ در ‪ BDS 2006‬و ‪ Visual C++ 2005‬ﺧﺮوﺟﻲ ﻣﺘﻔﺎوت دارد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪struct A‬‬ ‫{‬ ‫;‪unsigned __int64 a : 1‬‬ ‫;‪short b : 3‬‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪cout<< sizeof(A‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪8‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫‪16‬‬

‫ﻣﻲداﻧﻴﻢ در ﻳﻚ ‪ int‬ﻳﻚ ﺑﻴﺖ ﺑﺮاي ﻋﻼﻣﺖ ﻣﺜﺒﺖ ﻳﺎ ﻣﻨﻔﻲ ﻛﻨﺎر ﮔﺬاﺷﺘﻪ ﻣﻲﺷﻮد‪ .‬ﺣﺎﻻ اﮔﺮ ﻳﻚ ‪ int‬درﺳﺖ‬ ‫ﻛﻨﻴﻢ ﻛﻪ ﻳﻚ ﺑﻴﺖ ﺑﻴﺶ ﺗﺮ ﻧﺪارد ﺑﺎﻳﺪ آن ﺑﻴﺖ ﺑﺮاي ﻋﻼﻣﺖ اﺳﺘﻔﺎده ﺑﺸﻮد وﻟﻲ در اﻳﻦ ﺣﺎﻟﺖ ﺑﻴﺘﻲ ﺑﺮاي ﺧﻮد ﻋﺪد‬ ‫ﺑﺎﻗﻲ ﻧﻤﻲﻣﺎﻧﺪ‪ .‬در اﻳﻦ ﺣﺎﻟﺖ ﻣﻌﻨﻲ آن ﭼﻴﺴﺖ؟‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪struct A‬‬ ‫{‬ ‫;‪int a : 1‬‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪A u‬‬ ‫;‪u.a = 0‬‬ ‫‪cout<< u.a << endl; // output: 0‬‬ ‫;‪u.a = 1‬‬ ‫‪cout<< u.a << endl; // output : -1‬‬ ‫;‪int x = u.a‬‬

‫‪333‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪cout<< x‬‬ ‫;)(‪_getch‬‬

‫‪// output : -1‬‬

‫}‬

‫‪Output:‬‬ ‫‪0‬‬ ‫‪-1‬‬ ‫‪-1‬‬

‫ﭘﺲ ﻣﻘﺪار ‪ 1‬ﺑﺮاي ‪ A::a‬ﻣﻌﻨﻲ ‪ -1‬و ﻣﻘﺪار ‪ 0‬ﻣﻌﻨﻲ ‪ 0‬دارد‪ .‬ﺑﺒﻴﻨﻴﺪ ﻛﻪ وﻗﺘﻲ ﻣﻘﺪار ‪ u.a‬در ‪ x‬ﻗﺮار ﮔﺮﻓﺘﻪ‪ ،‬ﻣﻘﺪار‬ ‫‪ -1 ،x‬ﺷﺪه ﻧﻪ ‪ 0‬ﻳﺎ ‪.1‬‬ ‫اﮔﺮ ﺗﻌﺪاد ﺑﻴﺖﻫﺎ را ﻣﺜﻼ ﺑﺮاي ﻳﻚ ‪ 50 int‬ﺑﮕﻴﺮﻳﻢ‪ ،‬در ‪ BDS 2006‬ﺗﻨﻬﺎ ‪ 32‬ﺑﻴﺖ ﻳﻌﻨﻲ ﺣﺪاﻛﺜﺮ ﻃﻮل در ﻧﻈﺮ‬ ‫ﮔﺮﻓﺘﻪ ﻣﻲﺷﻮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫‪struct A‬‬ ‫{‬ ‫;‪unsigned char a : 9‬‬ ‫;}‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪A u‬‬ ‫‪cout<< sizeof(A) << endl; // output: 1‬‬ ‫;‪u.a = 0xff‬‬ ‫‪cout<< (int) u.a << endl; // output: 255‬‬ ‫;‪u.a++‬‬ ‫‪cout<< (int) u.a << endl; // output: 0‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪1‬‬ ‫‪255‬‬ ‫‪0‬‬

‫‪ Visual C++ 2005‬اﻳﻦ ﺑﺮﻧﺎﻣﻪ را اﺟﺮا ﻧﻤﻲﻛﻨﺪ‪ .‬ﻣﻘﺪار ‪ 0xff‬ﻛﻪ ﻫﻤﺎن ‪ 255‬اﺳﺖ ﺑﻪ ‪ u.a‬داده ﺷﺪه‪ .‬اﻳﻦ‬ ‫ﺑﺰرگ ﺗﺮﻳﻦ ﻋﺪدي اﺳﺖ ﻛﻪ ﻣﻲﺷﻮد ﺑﻪ ‪ u.a‬داد‪ .‬وﻗﺘﻲ ﺑﺎ ‪ ++‬ﻳﻜﻲ ﺑﻪ آن اﺿﺎﻓﻪ ﻛﺮدهاﻳﻢ ﻣﻘﺪارش ﺻﻔﺮ ﺷﺪه‪.‬‬ ‫اﮔﺮ ﺑﻪ ﺟﺎي ‪ 9‬ﺟﻠﻮي ‪ a‬ﻋﺪد ‪ -6‬ﺑﮕﺬارﻳﻢ ﺑﺮﻧﺎﻣﻪ در ‪ BDS 2006‬ﻫﻢ اﺟﺮا ﻧﻤﻲﺷﻮد‪.‬‬ ‫‪ sizeof‬در ﻣﻮرد ‪bit field‬ﻫﺎ ﻗﺎﺑﻞ اﺳﺘﻔﺎده ﻧﻴﺴﺖ‪.‬‬

‫‪334‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ :‫ﻫﺎ در ﻳﻚ ﻛﻼس ﻛﺎﻣﻞ ﻫﻢ ﻗﺎﺑﻞ اﺳﺘﻔﺎدهاﻧﺪ‬bit field #include <conio.h> #include <iostream> using namespace std; class A { private: unsigned a : 15;

// use 15 bits only

public: A(): a(1387) { cout<< a << endl; } ~A() { cout<< "~A()" << endl; _getch(); } }; int main() { A u; }

Output: 1387 ~A()

.‫ ﻣﻘﺪار اوﻟﻴﻪ داده ﺷﺪه ﻫﻢ دﻗﺖ ﻛﻨﻴﺪ‬constructor ‫ ﭼﻪ ﻃﻮر در‬a ‫ﺑﻪ اﻳﻦ ﻛﻪ‬ :‫ ﻧﻜﺘﻪﻫﺎي دﻳﮕﺮي ﻫﻢ ﻫﺴﺖ‬union ‫ اﻣﺎ در ﻣﻮرد‬.union ‫ ﻣﻲﺷﻮد ﻧﻮﺷﺖ‬class ‫در ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ ﺑﻪ ﺟﺎي‬ #include <conio.h> #include <iostream> using namespace std; union A { int a : 4; int b : 4; }; int main() { A u = {3}; cout<< u.b << "\n"; u.a = 5; cout<< u.b << "\n"; _getch(); }

Output:

335

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪3‬‬ ‫‪5‬‬

‫ﺑﻪ ‪ u.a‬ﻣﻘﺪار ‪ 5‬دادهاﻳﻢ‪ .‬ﻣﻲﺑﻴﻨﻴﻢ ﻛﻪ ‪ u.b‬ﻫﻢ ﻣﻘﺪار ‪ 5‬ﮔﺮﻓﺘﻪ‪ .‬ﻣﻤﻜﻦ اﺳﺖ ﺑﺨﻮاﻫﻴﻢ آدرس ‪ u.a‬و ‪) u.b‬ﻳﻌﻨﻲ‬ ‫‪ &u.a‬و ‪ (&u.b‬را ﭼﻚ ﻛﻨﻴﻢ و ﺑﺒﻴﻨﻴﻢ آﻳﺎ آدرس ﻳﻜﻲ اﺳﺖ ﻳﺎ ﻧﻪ‪ .‬اﻣﺎ & ﺑﺮاي ‪bit field‬ﻫﺎ ﻗﺎﺑﻞ اﺳﺘﻔﺎده ﻧﻴﺴﺖ‬ ‫ﻳﻌﻨﻲ ‪ &u.a error‬دارد‪.‬‬

‫ ه

"‪8‬‬

‫]‪ ^J3‬ه ‪ & ،| ,‬و ^ ﻋﻤﻠﮕﺮﻫﺎي ﺑﻴﺘﻲ ﮔﻔﺘﻪ ﻣﻲﺷﻮﻧﺪ‪ .‬اﮔﺮ ‪ a‬و ‪ b‬دو ﻣﻘﺪار ‪ integral‬ﺑﺎﺷﻨﺪ ﺑﻪ اﻳﻦ ﺷﻜﻞ‬ ‫‪a:‬‬ ‫‪0 0 1 0 1 1 1 1 0 1 0 0 1 0 1 0 1 0 0 1 1 1 1 1 1 1 0 1 0 0 0 1‬‬ ‫‪b:‬‬ ‫‪0 1 0 0 1 0 1 0 1 0 1 0 1 0 1 0 0 0 0 1 0 1 1 0 1 1 0 1 0 0 1 0‬‬

‫در اﻳﻦ ﺻﻮرت ‪ a|b ،a&b‬و ‪ a^b‬ﺑﻪ اﻳﻦ ﺷﻜﻞ ﻫﺴﺘﻨﺪ‪:‬‬ ‫‪b:‬‬ ‫‪0 0 1 0 1 0 0 0 0 0 1 0 1 0 0 0 0 1 0 1 1 0 1 1 0 1 0 0 0 0‬‬ ‫‪b:‬‬ ‫‪1 0 1 1 1 1 1 1 1 0 1 0 1 0 1 0 0 1 1 1 1 1 1 1 0 1 0 0 1 1‬‬ ‫‪b:‬‬ ‫‪1 0 0 1 0 1 1 1 1 0 0 0 0 0 1 0 0 0 1 0 0 1 0 0 0 0 0 0 1 1‬‬

‫&‬ ‫‪0‬‬ ‫|‬ ‫‪1‬‬ ‫^‬ ‫‪1‬‬

‫‪a‬‬ ‫‪0‬‬ ‫‪a‬‬ ‫‪0‬‬ ‫‪a‬‬ ‫‪0‬‬

‫• ﻳﻚ ﺑﻴﺖ در ‪ a&b‬ﻳﻚ اﺳﺖ ﻓﻘﻂ اﮔﺮ ﺑﻴﺖﻫﺎي ﻣﺘﻨﺎﻇﺮ در ‪ a‬و ‪ b‬ﻫﺮ دو ﻳﻚ ﺑﺎﺷﻨﺪ‪.‬‬ ‫• ﻳﻚ ﺑﻴﺖ در ‪ a&b‬ﺻﻔﺮ اﺳﺖ ﻓﻘﻂ اﮔﺮ ﺑﻴﺖﻫﺎي ﻣﺘﻨﺎﻇﺮ در ‪ a‬و ‪ b‬ﻫﺮ دو ﺻﻔﺮ ﺑﺎﺷﻨﺪ‪.‬‬ ‫• ﻳﻚ ﺑﻴﺖ در ‪ a^b‬ﺻﻔﺮ اﺳﺖ ﻓﻘﻂ اﮔﺮ ﺑﻴﺖﻫﺎي ﻣﺘﻨﺎﻇﺮ در ‪ a‬و ‪ b‬ﻣﺴﺎوي ﺑﺎﺷﻨﺪ‪.‬‬ ‫ﺷﻜﻞﻫﺎي ﺑﺎﻻ را ﺑﺒﻴﻨﻴﺪ‪ .‬در اﻳﻦ ﺷﻜﻞ ﺑﻴﺖﻫﺎي آﺑﻲ ﺑﺎ ﻫﻢ ﻣﺘﻨﺎﻇﺮﻧﺪ ﻫﻤﻴﻦ ﻃﻮر در ﻣﻮرد ﺑﻴﺖﻫﺎي ﻧﺎرﻧﺠﻲ‪ ،‬ﺑﻨﻔﺶ و‬ ‫ﺳﺒﺰ‪ .‬ﻣﺜﻼ ﺑﻴﺖﻫﺎي ﻧﺎرﻧﺠﻲ را در ﻧﻈﺮ ﺑﮕﻴﺮﻳﺪ‪:‬‬ ‫• ﺑﻴﺖ ﻧﺎرﻧﺠﻲ در ‪ a&b‬ﺻﻔﺮ اﺳﺖ ﭼﻮن ﻫﺮ دو ﺑﻴﺖ ﻧﺎرﻧﺠﻲ در ‪ a‬و ‪ b‬ﻳﻚ ﻧﻴﺴﺘﻨﺪ‪.‬‬ ‫• ﺑﻴﺖ ﻧﺎرﻧﺠﻲ در ‪ a|b‬ﻳﻚ اﺳﺖ ﭼﻮن ﻫﺮ دو ﺑﻴﺖ ﻧﺎرﻧﺠﻲ در ‪ a‬و ‪ b‬ﺻﻔﺮ ﻧﻴﺴﺘﻨﺪ‪.‬‬ ‫• ﺑﻴﺖ ﻧﺎرﻧﺠﻲ در ‪ a^b‬ﻳﻚ اﺳﺖ ﭼﻮن ﺑﻴﺖﻫﺎي ﻧﺎرﻧﺠﻲ در ‪ a‬و ‪ b‬ﻣﺴﺎوي ﻧﻴﺴﺘﻨﺪ‪.‬‬ ‫ﺑﻪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪:‬‬

‫‪336‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <conio.h> #include <iostream> using namespace std; int main() { int a = 0xff0f0fff; int b = 0x0f0ff0f0; cout<< hex << (a & b) << endl; // output: 0x0f0f00f0; cout<< hex << (a | b) << endl; // output: 0xff0fffff; cout<< hex << (a ^ b) << endl; // output: 0xf000ff0f; _getch(); }

Output: f0f00f0 ff0fffff f000ff0f

‫ ﻧﻤﺎﻳﻨﺪهي ﭼﻬﺎر ﺑﻴﺖ ﭘﺸﺖ ﺳﺮ ﻫﻢ ﺷﺎﻣﻞ ﻳﻚ اﺳﺖ و ﻫﺮ ﺻﻔﺮ ﻧﻤﺎﻳﻨﺪهي ﭼﻬﺎر ﺑﻴﺖ‬f ‫ ﻫﺮ‬0xff0f0fff ‫در‬ .‫ ﺧﺮوﺟﻲ ﺗﻮﺿﻴﺤﺎت ﻗﺒﻠﻲ را ﺗﺄﻳﻴﺪ ﻣﻲﻛﻨﺪ‬.‫ﭘﺸﺖ ﺳﺮﻫﻢ ﺷﺎﻣﻞ ﺻﻔﺮ اﺳﺖ‬ :‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﺟﺎﻟﺐ اﺳﺖ‬ #include <conio.h> #include <iostream> using namespace std; union A { char a; struct { unsigned b1 : 1; unsigned b2 : 1; unsigned b3 : 1; unsigned b4 : 1; unsigned b5 : 1; unsigned b6 : 1; unsigned b7 : 1; unsigned b8 : 1; }; A(char x): a(x) { cout << b8 << b7 << b6 << b5 << b4 << b3 << b2 << b1 << endl; } }; int main() { char ch1 = 101;

337

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪01100101‬‬ ‫‪11001010‬‬ ‫‪01000000‬‬ ‫‪11101111‬‬ ‫‪10101111‬‬

‫‪//‬‬ ‫‪//‬‬ ‫‪//‬‬ ‫‪//‬‬ ‫‪//‬‬

‫;‪char ch2 = 202‬‬ ‫;)‪A a(ch1‬‬ ‫;)‪A b(ch2‬‬ ‫;)‪A c(ch1 & ch2‬‬ ‫;)‪A d(ch1 | ch2‬‬ ‫;)‪A e(ch1 ^ ch2‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪01100101‬‬ ‫‪11001010‬‬ ‫‪01000000‬‬ ‫‪11101111‬‬ ‫‪10101111‬‬

‫ﻛﻼس ‪ A‬ﺑﻴﺖﻫﺎي ﻳﻚ ﻛﺎراﻛﺘﺮ را ﭼﺎپ ﻣﻲﻛﻨﺪ‪.‬‬ ‫دو ﻋﻤﻠﮕﺮ دﻳﮕﺮ ﻫﻢ ﺑﺮاي ﻛﺎر ﺑﺎ ﺑﻴﺖﻫﺎ دارﻳﻢ ﻳﻌﻨﻲ << و >>‪ .‬اﮔﺮ ‪ a‬ﻋﺪدي ﺻﻴﺢ ﺑﺎﺷﺪ‪ a<<6 ،‬ﻫﻤﺎن ‪ a‬اﺳﺖ‬ ‫ﻛﻪ ﺑﻴﺖﻫﺎي آن ‪ 6‬واﺣﺪ ﺑﻪ ﺳﻤﺖ ﭼﭗ رﻓﺘﻪاﻧﺪ و ‪ a>>4‬ﻫﻤﺎن ‪ a‬اﺳﺖ ﻛﻪ ﺑﻴﺖﻫﺎي آن ﭼﻬﺎر واﺣﺪ ﺑﻪ ﺳﻤﺖ ﭼﭗ‬ ‫رﻓﺘﻪاﻧﺪ‪ .‬ﻳﻌﻨﻲ اﮔﺮ ﺑﻪ اﻳﻦ ﺻﻮرت ﺑﺎﺷﺪ‪:‬‬ ‫‪a:‬‬ ‫‪0 0 1 0 1 1 1 1 0 1 0 0 1 0 1 0 1 0 0 1 1 1 1 1 1 1 0 1 0 0 0 1‬‬

‫آن وﻗﺖ‬ ‫‪a<<6:‬‬ ‫‪1 1 0 1 0 0 1 0 1 0 1 0 0 1 1 1 1 1 1 1 0 1 0 0 0 1 0 0 0 0 0 0‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ‪ 6‬ﺑﻴﺖ ﻛﻪ آنﻫﺎ را ﺑﺎ رﻧﮓ آﺑﻲ ﻧﺸﺎن دادهام از ﺳﻤﺖ ﭼﭗ ﺣﺬف ﺷﺪهاﻧﺪ و ‪ 6‬ﺑﻴﺖ ﺻﻔﺮ ﻛﻪ ﺑﺎ رﻧﮓ‬ ‫ﻧﺎرﻧﺠﻲ ﻧﺸﺎن دادهام ﺑﻪ ﺳﻤﺖ راﺳﺖ اﺿﺎﻓﻪ ﺷﺪهاﻧﺪ‪ .‬اﻧﮕﺎر ﺑﻴﺖﻫﺎ ‪ 6‬واﺣﺪ ﺑﻪ ﭼﭗ رﻓﺘﻪ ﺑﺎﺷﻨﺪ‪ .‬و‬ ‫‪a:‬‬ ‫‪0 0 1 0 1 1 1 1 0 1 0 0 1 0 1 0 1 0 0 1 1 1 1 1 1 1 0 1 0 0 0 1‬‬ ‫‪a>>4:‬‬ ‫‪0 0 0 0 0 0 1 0 1 1 1 1 0 1 0 0 1 0 1 0 1 0 0 1 1 1 1 1 1 1 0 1‬‬

‫در اﻳﻦ ﺟﺎ ﻫﻢ‪ ،‬ﺧﺎﻧﻪﻫﺎي آﺑﻲ ﺣﺬف ﺷﺪهاﻧﺪ و ﺧﺎﻧﻪﻫﺎي ﻧﺎرﻧﺠﻲ اﺿﺎﻓﻪ ﺷﺪهاﻧﺪ‪ .‬اﻧﮕﺎر ﺑﻴﺖﻫﺎ ‪ 4‬واﺣﺪ ﺑﻪ ﺳﻤﺖ راﺳﺖ‬ ‫رﻓﺘﻪ ﺑﺎﺷﻨﺪ‪ .‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ‪ a>>4‬ﻳﺎ ‪ a<<6‬ﻣﻘﺪار ‪ a‬را ﺗﻐﻴﻴﺮ ﻧﻤﻲدﻫﻨﺪ‪.‬‬

‫‪338‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ :‫ﺑﻪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺗﻮﺟﻪ ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; int main() { int a = 0xfffffff << 4; cout<< hex << a; _getch(); }

Output: fffffff0

‫ و‬.‫ ﭼﻬﺎر واﺣﺪ ﺑﻪ ﺳﻤﺖ ﭼﭗ رﻓﺘﻪاﻧﺪ‬0xfffffff ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺑﻴﺖﻫﺎي‬ #include <conio.h> #include <iostream> using namespace std; int main() { cout<< hex << (0xffffffff >> -16) << endl; cout<< hex << (0xffffffff >> 16) << endl; _getch(); }

Output (BDS 2006): ffff ffff Output (Visual C++): 0 ffff

.‫ ﻫﻢ ﻓﺮﻗﻲ ﻧﺪارﻧﺪ‬Dev C++ ‫ در‬.‫ ﻓﺮﻗﻲ ﻧﺪارﻧﺪ‬16 ‫ و‬-16 ،BDS 2006 ‫ در‬. .

:‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﺑﺮاي ﺷﻨﺎﺧﺘﻦ ﻧﻮعﻫﺎ ﻻزم اﺳﺖ‬ #include <conio.h> #include <iostream> using namespace std; int main() { char

ch = 1;

339

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ int in = 2; long lo = 3L; __int64 ll = 4LL; cout<< typeid(ch cout<< typeid(in cout<< typeid(lo cout<< typeid(ll cout<< typeid(ll cout<< typeid(ll cout<< typeid(ll _getch();

<< << << << << << &

ch).name() in).name() lo).name() ll).name() in).name() lo).name() in).name()

<< << << << << << <<

endl; endl; endl; endl; endl; endl; endl;

// // // // // // //

int int long __int64 __int64 __int64 __int64

}

Output: int int long __int64 __int64 __int64 __int64

.‫ را ﻫﻢ ﺑﺮرﺳﻲ ﻛﺮد‬++ ‫ ﻳﺎ‬+ ‫اﻟﺒﺘﻪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ را ﻣﻲﺷﻮد ﺧﻴﻠﻲ ﻛﺎﻣﻞ ﺗﺮ از اﻳﻦ ﻧﻮﺷﺖ و ﻋﻤﻠﮕﺮﻫﺎي دﻳﮕﺮ ﻣﺜﻞ‬

:‫ را ﭼﺎپ ﻣﻲﻛﻨﺪ‬long long n\ ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻧﻤﺎﻳﺶ ﺑﻴﺘﻲ‬ #include <conio.h> #include <iostream> using namespace std; int main() { long long

a = 0xf0f0f0f0f0f0f0fLL;

for(int i = 8 * sizeof(long long); 0 <= i; i--) { __int64 one = (1LL << i); bool bit = (a & one) >> i; cout<< bit; } _getch(); }

Output:

0000011110000111100001111000011110000111100001111000011 1100001111

340

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ __int64 ‫ ﻣﻲداﻧﻴﺪ ﻛﻪ‬.‫اﻣﻴﻦ ﺑﻴﺖ ﺻﻔﺮﻧﺪ‬i ‫ اﺳﺖ ﻛﻪ ﻫﻤﻪي ﺑﻴﺖﻫﺎي آن ﺑﻪ ﺟﺰ‬long long n\ one

‫ اﺳﺖ و‬a ‫ام‬i ‫ام آن ﺑﺮاﺑﺮ ﺑﺎ ﺑﻴﺖ‬i ‫ اﺳﺖ ﻛﻪ ﺑﻴﺖ‬long long n\ a&one .‫ اﺳﺖ‬long long ‫ﻫﻤﺎن‬ ‫ ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ در‬.‫ اﺳﺖ‬a ‫اﻣﻴﻦ ﺑﻴﺖ‬i ‫ ﺑﺮاﺑﺮ ﺑﺎ ﻣﻘﺪار‬bit ‫ ﻣﻘﺪار‬.‫ﺑﻘﻴﻪي ﺑﻴﺖﻫﺎﻳﺶ ﺻﻔﺮﻧﺪ‬ .‫ دارد‬long long ‫ ﻧﻮع‬،‫ ﻧﺸﺎن دﻫﻨﺪه اﻳﻦ اﺳﺖ ﻛﻪ ﻋﺪد‬LL ،0xf0f0f0f0f0f0f0fLL

calling convention

calling ‫ ﺑﻪ ﻫﺮ ﻛﺪام از اﻳﻦ روشﻫﺎ ﻳﻚ‬.‫ﻳﻚ ﺗﺎﺑﻊ ﺑﻪ روشﻫﺎي ﻣﺨﺘﻠﻔﻲ ﻣﻲﺗﻮاﻧﺪ ﻳﻚ ﺗﺎﺑﻊ دﻳﮕﺮ را ﻓﺮا ﺑﺨﻮاﻧﺪ‬ :‫ﻫﺎ را در ﭘﺎﻳﻴﻦ ﻣﻲﺑﻴﻨﻴﺪ‬calling convention ‫ ﺑﻌﻀﻲ از‬.‫ ﻣﻲﮔﻮﻳﻨﺪ‬convention cdecl //not keyword in Visual C++ 2005 _cdecl __cdecl _stdcall __stdcall _fastcall __fastcall __thiscall // not keyword in BDS 2006 pascal _pascal __pascal _fortran //not keyword in Visual C++ 2005 __fortran //not keyword in Visual C++ 2005

‫ اول ﺑﮕﺬارﻳﺪ ﻧﺤﻮهي ﺑﻪ ﻛﺎر ﮔﺮﻓﺘﻦ آنﻫﺎ را‬.‫آﻣﻮﺧﺘﻦ اﻳﻦ ﻛﻪ دﻗﻴﻘﺎ ﻫﺮ ﻛﺪام از اﻳﻦﻫﺎ ﭼﻪ ﻛﺎر ﻣﻲﻛﻨﻨﺪ ﻧﻴﺎز ﻧﻴﺴﺖ‬ :‫ را ﻧﺸﺎن ﻣﻲدﻫﺪ‬calling convention ‫ اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻧﺤﻮهي ﻣﺸﺨﺺ ﻛﺮدن‬.‫ﺑﺒﻴﻨﻴﻢ‬ #include <conio.h> #include <iostream> using namespace std; int __stdcall f(int a); int main() { cout<< f(5) << endl; cout<< typeid(f).name(); _getch(); } int __stdcall f(int a) { return a * a;

341

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ }

Output (BDS 2006): 25 int (__stdcall *)(int) Output (Visual C++ 2005): 25 int __stdcall(int)

‫__ ﻣﻲﺷﻮد‬stdcall ‫ ﺑﻪ ﺟﺎي‬.‫ ﺑﻪ ﻛﺎر ﻣﻲرود‬Windows ‫__ ﺑﻴﺶ ﺗﺮ ﺑﺮاي ﺑﺮﻧﺎﻣﻪﻫﺎي‬stdcall .‫_ ﻫﻢ ﻧﻮﺷﺖ و ﺧﺮوﺟﻲ ﻓﺮﻗﻲ ﻧﻤﻲﻛﻨﺪ‬stdcall :‫ﺣﺎﻻ ﺑﻪ اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻧﮕﺎه ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; int __cdecl f(int a); int main() { cout<< f(5) << endl; cout<< typeid(f).name(); _getch(); } int _cdecl f(int a) { return a * a; }

Output (BDS 2006): 25 int (*)(int) Output (Visual C++ 2005): 25 int __cdecl(int)

.‫_ ﻳﺎ ﻫﺮ دو را ﺣﺬف ﻛﻨﻴﻢ ﺧﺮوﺟﻲ ﻫﻴﭻ ﺗﻐﻴﻴﺮي ﻧﻤﻲﻛﻨﺪ‬cdecl ‫__ ﻳﺎ‬cdecl ‫در اﻳﻦ ﺟﺎ اﮔﺮ‬ ‫ در اﻳﻦ روش ﻗﺒﻞ از اﺳﻢ ﻳﻚ‬.‫ اﺳﺘﻔﺎده ﻛﻨﺪ‬C ‫ از روش اﺳﻢ ﮔﺬاري‬compiler ‫__ ﺑﺎﻋـﺚ ﻣﻲﺷﻮد ﻛﻪ‬cdecl .‫ ﮔﺬاﺷﺘﻪ ﻣﻲﺷﻮﻧﺪ‬stack ‫ ﭘﺎراﻣﺘﺮﻫﺎ از راﺳﺖ ﺑﻪ ﭼﭗ روي‬.‫ اﺿﺎﻓﻪ ﻣﻲﺷﻮد‬underscore .‫ ﮔﺬاﺷﺘﻪ ﻣﻲﺷﻮﻧﺪ‬stack ‫ ﭘﺎراﻣﺘﺮﻫﺎ از راﺳﺖ ﺑﻪ ﭼﭗ روي‬.‫ ِ اﺳﺘﺎﻧﺪارد اﺳﺖ‬call convention ،__stdcall

342

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺑﺮاي اﻃﻼﻋﺎت ﺑﻴﺶ ﺑﻪ ‪ help‬در ‪compiler‬ﺗﺎن ﻧﮕﺎه ﻛﻨﻴﺪ‪.‬‬

‫در ﺑﺨﺶﻫﺎي ﺑﻌﺪي ﺑﺎ ﺑﻌﻀﻲ ﺗﻮاﺑﻊ و ﻛﻼسﻫﺎي ﻣﻮﺟﻮد در ﭼﻨﺪ ‪ header file‬ﭘﺮﻛﺎرﺑﺮد آﺷﻨﺎ ﻣﻲﺷﻮﻳﻢ‪.‬‬

‫‪stdio.h‬‬

‫ﺷﺎﻳﺪ ﻣﻬﻢ ﺗﺮﻳﻦ ﺗﺎﺑﻊ در ‪ stdio.h‬ﺗﺎﺑﻊ ‪ printf‬ﺑﺎﺷﺪ‪ printf .‬ﺗﺎﺑﻌﻲ اﺳﺖ ﺑﺎ ﺣﺪاﻗﻞ ﻳﻚ ﭘﺎراﻣﺘﺮ‪ .‬در واﻗﻊ‬ ‫ﺗﻌﺪاد آرﮔﻮﻣﺎنﻫﺎي آن ﻣﻲﺗﻮاﻧﺪ ﻫﺮ ﻋﺪدي ﺑﺎﺷﺪ‪ .‬ﺳﺎده ﺗﺮﻳﻦ ﻛﺎرﺑﺮد آن ﭼﺎپ ﻳﻚ رﺷﺘﻪ اﺳﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <stdio.h‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)"‪printf("hello‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪hello‬‬ ‫ﺑﺮاي اﻳﻦ ﻛﻪ ﻳﻚ ﻳﺎ ﭼﻨﺪ ‪ int‬را ﺑﺎ ‪ printf‬ﭼﺎپ ﻛﻨﻴﻢ در رﺷﺘﻪاي ﻛﻪ ﺑﻪ ﻋﻨﻮان آرﮔﻮﻣﺎن اول ﺑﻪ ‪printf‬‬

‫داده ﻣﻲﺷﻮد در ﻣﻜﺎن ﻣﻮرد ﻧﻈﺮ ﻣﻲﻧﻮﻳﺴﻴﻢ ‪ %i‬و ﺑﻌﺪ اﻋﺪادي را ﻛﻪ ﺑﺎﻳﺪ ﭼﺎپ ﺑﺸﻮﻧﺪ ﺑﻪ ﻋﻨﻮان آرﮔﻮﻣﺎنﻫﺎي ﺑﻌﺪي‬ ‫ﺑﻪ ‪ printf‬ﻣﻲدﻫﻴﻢ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <stdio.h‬‬ ‫)(‪int main‬‬ ‫{‬ ‫‪int year‬‬ ‫;‪= 2008‬‬ ‫; ‪int month = 12‬‬ ‫‪int day‬‬ ‫‪= 5‬‬ ‫;‬ ‫;)‪printf("year: %i \nmonth: %i \nday: %i",year,month, day‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪year: 2008‬‬ ‫‪month: 12‬‬

‫‪343‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪day: 5‬‬

‫ﺑﻪ ﻃﻮر ﻛﻠﻲ اﻳﻦ ﺟﺪول را دارﻳﻢ‪:‬‬ ‫ﭼﻴﺰي ﻛﻪ ﭼﺎپ ﻣﻲﺷﻮد‬

‫‪1387‬‬ ‫‪2008‬‬ ‫‪2008‬‬ ‫‪4294967295‬‬ ‫‪2524‬‬ ‫‪aab4‬‬ ‫‪AAB4‬‬ ‫‪Hello‬‬ ‫‪1.234500e+01‬‬ ‫‪1.234500E+01‬‬ ‫‪12.345000‬‬ ‫‪1234567.89000000‬‬ ‫‪12.345‬‬ ‫‪12.345‬‬

‫ﻣﻘﺪار‬

‫ﻧﻤﺎد در آرﮔﻮﻣﺎن اول‬

‫‪1387‬‬ ‫‪2008‬‬ ‫‪2008‬‬ ‫‪-1‬‬ ‫‪1364‬‬ ‫‪43700‬‬ ‫‪43700‬‬ ‫"‪"hello‬‬ ‫‪12.345‬‬ ‫‪12.345‬‬ ‫‪12.345‬‬ ‫‪134567.89‬‬ ‫‪12.345‬‬ ‫‪12.345‬‬

‫‪%i‬‬ ‫‪%d‬‬ ‫‪%10d‬‬ ‫‪%u‬‬ ‫‪%o‬‬ ‫‪%x‬‬ ‫‪%X‬‬ ‫‪%s‬‬ ‫‪%e‬‬ ‫‪%E‬‬ ‫‪%f‬‬ ‫‪%6.8f‬‬ ‫‪%g‬‬ ‫‪%G‬‬

‫در اﻳﻦ ﺟﺪول‪ %10d ،‬اﺑﺘﺪا ﺑﻪ اﻧﺪازهي ‪ 10‬ﻛﺎراﻛﺘﺮ ﺟﺎ ﺑﺎز ﻣﻲﻛﻨﺪ و ﺑﻌﺪ ﻋﺪد را در آن ﻣﻲﻧﻮﻳﺴﺪ‪ .‬ﺑﻪ ﺟﺎي ‪10‬‬

‫ﻣﻲﺷﻮد ﻫﺮ ﻋﺪد دﻳﮕﺮي ﻫﻢ ﻗﺮار داد‪ .‬در ‪ ،8 %6.8f‬ﺗﻌﺪاد اﻋﺸﺎر را ﻣﺸﺨﺺ ﻣﻲﻛﻨﺪ‪ %u .‬ﺑﺮاي ﭼﺎپ ﻋﺪد ﺑﻪ‬ ‫ﺻﻮرت ‪ unsigned‬اﺳﺖ‪ %o .‬ﺑﺮاي ﻣﺒﻨﺎي ‪ 8‬و ‪ %x‬ﺑﺮاي ﻣﺒﻨﺎي ‪ 16‬اﺳﺖ‪ .‬ﻣﻨﻈﻮر از ‪ 1.234500e+01‬و‬ ‫‪ ،1.234500E+01‬ﻋﺪد ‪ .‬اﺳﺖ‪.‬‬ ‫ﺣﺎﻻ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <stdio.h‬‬ ‫)(‪int main‬‬ ‫{‬ ‫"‪printf("this is a string: %s\n‬‬ ‫;)‪"this is an int: %d\n","hello", 123‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪this is a string: hello‬‬ ‫‪this is an int: 123‬‬

‫اوﻟﻴﻦ آرﮔﻮﻣﺎن ‪ printf‬در اﻳﻦ ﺑﺮﻧﺎﻣﻪ اﻳﻦ اﺳﺖ‪:‬‬ ‫"‪"this is an int: %d\n","hello‬‬

‫ﻛﻪ ‪ compiler‬آن را ﺑﻪ‬

‫‪344‬‬

‫‪www.pupuol.com‬‬

‫"‪"this is a string: %s\n‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫"‪"this is a string: %s\nthis is an int: %d\n","hello‬‬

‫ﺗﺒﺪﻳﻞ ﻣﻲﻛﻨﺪ‪ .‬ﺑﻪ ﻃﻮر ﻛﻠﻲ وﻗﺘﻲ دو رﺷﺘﻪي ﺛﺎﺑﺖ ِ ‪ literal‬را ﻛﻨﺎر ﻫﻢ ﺑﻨﻮﻳﺴﻴﻢ ‪ compiler‬ﺣﻴﻦ ‪compile‬‬ ‫ﻛﺮدن‪ ،‬آنﻫﺎ را ﺑﻪ ﻫﻢ ﻣﻲﭼﺴﺒﺎﻧﺪ‪ .‬ﻣﺜﻼ "‪"bye‬‬

‫"‪ "hello‬ﺑﺎ "‪ "hellobye‬ﻣﻌﺎدل اﺳﺖ‪.‬‬

‫دوﻣﻴﻦ آرﮔﻮﻣﺎن ‪ "hello" ،printf‬اﺳﺖ ﻛﻪ ﺑﻪ ﺟﺎي ‪ %s‬در رﺷﺘﻪ آرﮔﻮﻣﺎن اول ﻗﺮار ﻣﻲﮔﻴﺮد‪ .‬آرﮔﻮﻣﺎن‬ ‫ﺳﻮم ﻫﻢ ﺑﻪ ﺟﺎي ‪ %d‬ﻗﺮار ﻣﻲﮔﻴﺮد‪.‬‬ ‫ﺑﺮاي اﻳﻦ ﻛﻪ ﺧﻮد ‪ %‬ﭼﺎپ ﻣﻲﺷﻮد ﻣﻲﺷﻮد در آرﮔﻮﻣﺎن اول ‪ ،printf‬از ‪ %%‬اﺳﺘﻔﺎده ﻛﺮد‪.‬‬ ‫ﻣﺜﺎل زﻳﺮ ﺟﺎﻟﺐ اﺳﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <stdio.h‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪int i‬‬ ‫)‪for(i = 3; i < 20; i+=2‬‬ ‫;)‪printf("%*d\n",i,123‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪123‬‬ ‫‪123‬‬ ‫‪123‬‬ ‫‪123‬‬ ‫‪123‬‬ ‫‪123‬‬ ‫‪123‬‬ ‫‪123‬‬ ‫‪123‬‬

‫در ;)‪ V printf("%*d\n",i,123‬ار ‪ i‬ﺑﻪ ﺟﺎي * ﻗﺮار ﻣﻲﮔﻴﺮد‪ .‬ﻣﺜﻼ اﮔﺮ ﻣﻘﺪار ‪ 10 ،i‬ﺑﺎﺷﺪ اﻧﮕﺎر‬ ‫ﻧﻮﺷﺘﻪاﻳﻢ ;)‪.printf("%10d\n",123‬‬ ‫ﺑﺎ وﺟﻮد ‪ cout‬در ‪ C++‬ﻧﻴﺎز زﻳﺎدي ﺑﻪ ‪ printf‬اﺣﺴﺎس ﻧﻤﻲﺷﻮد‪ .‬ﺗﺎﺑﻊ دﻳﮕﺮي در ‪ stdio.h‬ﻫﺴﺖ ﺑﺎ ﻧﺎم‬ ‫‪ sprintf‬ﻛﻪ ﻣﺜﻞ ‪ printf‬ﻋﻤﻞ ﻣﻲﻛﻨﺪ وﻟﻲ ﭼﻴﺰي را ﻛﻪ ﻗﺮار اﺳﺖ ﭼﺎپ ﻛﻨﺪ در ﻳﻚ رﺷﺘﻪ ﻣﻲﮔﺬارد‪ .‬ﻣﺜﺎل‬ ‫زﻳﺮ ﻫﻤﻪ ﭼﻴﺰ را روﺷﻦ ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪#include <stdio.h‬‬

‫‪345‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)(‪int main‬‬ ‫{‬ ‫;]‪char c[100‬‬ ‫"‪sprintf(c, "this is a string: %s\n‬‬ ‫;)‪"this is an int: %d\n","hello", 123‬‬ ‫;‪cout<< c‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪this is a string: hello‬‬ ‫‪this is an int: 123‬‬

‫ﭼﻴﺰي را ﻛﻪ ‪ printf‬ﭼﺎپ ﻣﻲﻛﻨﺪ‪ sprintf ،‬در ‪ c‬ﻣﻲرﻳﺰد‪ c cout .‬ﭼﺎپ ﺷﺪه‪ .‬در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻣﻲﺷﻮد‬ ‫>‪#include <stdio.h‬‬

‫را ﺣﺬف ﻛﺮد ﭼﻮن وﻗﺘﻲ ‪ iostream #include‬ﺷﻮد ﻧﻴﺎزي ﺑﻪ ‪ #include‬ﻛﺮدن ‪ stdio.h‬ﻧﻴﺴﺖ‪.‬‬ ‫‪ sprintf‬ﻛﺎرﺑﺮد زﻳﺎدي دارد ﭼﻮن ﺗﻮاﻧﺎﻳﻲ ﺑﻲ ﻧﻈﻴﺮي در ﺳﺎﺧﺘﻦ رﺷﺘﻪ دارد و ﺑﻪ راﺣﺘﻲ ﻣﻲﺗﻮاﻧﺪ رﺷﺘﻪﻫﺎي‬ ‫ﭘﻴﭽﻴﺪهاي ﺑﺴﺎزد )‪ sprint‬ﻳﻌﻨﻲ »ﺑﻪ ﺳﺮﻋﺖ دوﻳﺪن«‬

‫وﻟﻲ ﻫﻴﭻ رﺑﻄﻲ ﺑﻪ ‪ sprintf‬ﻧﺪارد‬

‫(‪.‬‬

‫‪stdlib.h‬‬

‫ﻣﻬﻢ ﺗﺮﻳﻦ ﺗﺎﺑﻊ در ‪ ،stdlib.h‬ﺗﺎﺑﻊ‬ ‫;)*‪int system(const char‬‬

‫اﺳﺖ‪ .‬اﻳﻦ ﺗﺎﺑﻊ ﺑﺎﻋﺚ اﺟﺮاي دﺳﺘﻮرات ‪ command‬در ﺳﻴﺴﺘﻢ ﻋﺎﻣﻞ ﻣﻲﺷﻮد‪ .‬اﮔﺮ ﻧﻤﻲداﻧﻴﺪ دﺳﺘﻮرات‬ ‫‪ command‬ﭼﻪ ﻫﺴﺘﻨﺪ ﺑﺎﻳﺪ ﺑﮕﻮﻳﻢ ﻫﻤﺎن دﺳﺘﻮرات ﺳﻴﺴﺘﻢ ﻋﺎﻣﻞ ‪ DOS‬ﻫﺴﺘﻨﺪ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﺑﺎ آنﻫﺎ آﺷﻨﺎ ﺑﺸﻮﻳﺪ‬ ‫در وﻳﻨﺪوز ‪ XP‬اﻳﻦ ﻣﺴﻴﺮ را ﻃﻲ ﻛﻨﻴﺪ‪:‬‬ ‫‪Start | All Programs | Accessories | Command Prompt‬‬

‫‪346‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫اﻳﻦ ﭘﻨﺠﺮه ﺑﺎز ﻣﻲﺷﻮد‪:‬‬

‫‪347‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

dir ‫ ﺗﺎﻳﭗ ﻛﻨﻴﺪ‬.‫ را ﻓﺸﺎر ﺑﺪﻫﻴﺪ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻧﻮﺷﺘﻪﻫﺎي ﭘﻨﺠﺮه ﭘﺎك ﻣﻲﺷﻮﻧﺪ‬Enter ‫ و‬CLS ‫در آن ﺗﺎﻳﭗ ﻛﻨﻴﺪ‬

‫ اﻳﻦﻫﺎ ﻫﻤﺎن ﻓﺎﻳﻞﻫﺎﻳﻲ ﻫﺴﺘﻨﺪ ﻛﻪ در ﻣﻜﺎﻧﻲ‬.‫ را ﻓﺸﺎر ﺑﺪﻫﻴﺪ ﻣﻲﺑﻴﻨﻴﺪ اﺳﻢ ﻳﻚ ﺳﺮي ﻓﺎﻳﻞ ﻇﺎﻫﺮ ﻣﻲﺷﻮد‬Enter ‫و‬ .‫ ﻫﺴﺘﻨﺪ‬command ‫ دﺳﺘﻮرﻫﺎي‬dir ‫ و‬cls .‫ﻛﻪ »ﻣﻜﺎن ﺟﺎري« ﮔﻔﺘﻪ ﻣﻲﺷﻮد ﻗﺮار دارﻧﺪ‬ :‫ اﻳﻦ ﻣﺜﺎل را ﺑﺒﻴﻨﻴﺪ‬.‫ ﻣﻲﺗﻮاﻧﻴﻢ اﻳﻦ دﺳﺘﻮرﻫﺎ را در ﺑﺮﻧﺎﻣﻪي ﺧﻮدﻣﺎن ﺑﻪ ﻛﺎر ﺑﮕﻴﺮﻳﻢ‬system ‫ﺑﺎ ﺗﺎﺑﻊ‬ #include <stdlib.h> int main() { system("dir"); system("Pause"); }

Output (BDS 2006): Volume in drive G has no label. Volume Serial Number is ACBD-7F35 Directory of G:\Important Files\My Documents\Borland Studio Projects\Console\De bug_Build 02/28/2009 02/28/2009 02/28/2009 02/28/2009 02/13/2009 02/28/2009

04:25 04:25 04:25 04:25 04:01 04:25

AM AM AM AM AM AM

<DIR> <DIR> 12,288 2,568 5,788 196,608

348

www.pupuol.com

. .. Console.exe Console.obj Console.res Console.tds


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ 12/09/2008 12/05/2008 12/05/2008 12/05/2008

05:06 PM 0 hello.txt 01:12 PM 58,119 object.obj 08:09 PM 57,881 Unit1.obj 02:47 AM 154,408 Unit2.obj 8 File(s) 487,660 bytes 2 Dir(s) 13,251,207,168 bytes free Press any key to continue . . . Output (Visual C++ 2005): Volume in drive C has no label. Volume Serial Number is 0061-53EB Directory of c:\Documents and Settings\Administrator\My Documents\Visual Studio 2005\Projects\console\console 02/28/2009 04:27 AM <DIR> . 02/28/2009 04:27 AM <DIR> .. 02/28/2009 04:27 AM 154 console.cpp 11/20/2008 02:48 PM 663,806 console.i 02/22/2009 05:57 AM 3,581 console.vcproj 02/28/2009 04:28 AM 1,424 console.vcproj.CPPBUILDER.Administrator.u ser 02/28/2009 04:27 AM <DIR> Debug 12/05/2008 01:16 PM 123 object.cpp 12/05/2008 01:38 PM 123 object.h 02/05/2009 12:58 AM 51 Resource.rc 12/30/2008 01:54 PM 3 stdout 12/05/2008 08:16 PM 180 unit1.cpp 12/05/2008 08:16 PM 89 unit1.h 11/20/2008 02:49 PM 652,339 unit1.i 12/05/2008 02:56 AM 103 unit2.cpp 12/05/2008 11:53 AM 138 unit2.h 13 File(s) 1,322,114 bytes 3 Dir(s) 13,482,811,392 bytes free Press any key to continue . . .

‫ دﺳﺘﻮرات‬.‫_ را اﻧﺠﺎم ﻣﻲدﻫﺪ‬getch() ‫ ﺑﺎﻋـﺚ ﺗﻮﻗﻒ ﺑﺮﻧﺎﻣﻪ ﻣﻲﺷﻮد و در واﻗﻊ ﻫﻤﺎن ﻛﺎر‬pause ‫دﺳﺘﻮر‬ .‫ را ﻣﻲﺷﻮد ﺑﺎ ﺣﺮوف ﻛﻮﭼﻚ ﻳﺎ ﺑﺰرگ ﻧﻮﺷﺖ‬command :‫ ﻣﻲﺳﺎزد‬Command Prompt ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﭼﻴﺰي ﺷﺒﻴﻪ ﺑﻪ‬ #include <iostream> using namespace std;

349

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫)(‪int main‬‬ ‫{‬ ‫;"‪char a[200] = "CLS‬‬ ‫)‪while(true‬‬ ‫{‬ ‫;)‪system(a‬‬ ‫;‪cin>> a‬‬ ‫(‪if‬‬ ‫&& '‪a[0] == 'e' && a[1] == 'x‬‬ ‫)'‪a[2] == 'i' && a[3] == 't‬‬ ‫;‪break‬‬ ‫}‬ ‫}‬

‫‪Output:‬‬ ‫‪pause‬‬ ‫‪Press any key to continue . . .‬‬ ‫‪exit‬‬

‫‪ Pause‬را ﺧﻮد ﻣﻦ ﻧﻮﺷﺘﻪام و ‪ Enter‬را ﻓﺸﺎر دادهام‪ exit , 3J 08=!/ .‬و ﺑﻌﺪ ﻓﺸﺎر ‪ Enter‬اﺟﺮاي‬ ‫ﺑﺮﻧﺎﻣﻪ ﺗﻤﺎم ﻣﻲﺷﻮد‪ .‬وﻗﺘﻲ ‪ #include ،iostream‬ﻣﻲﺷﻮد‪ ،‬دﻳﮕﺮ ﻧﻴﺎزي ﺑﻪ ‪ stdlib.h‬ﻧﻴﺴﺖ‪.‬‬

‫)ر! نه ' & )(‪main‬‬

‫ﺗﺎﺑﻊ )(‪ main‬ﻣﻲﺗﻮاﻧﺪ دو ﭘﺎراﻣﺘﺮ داﺷﺘﻪ ﺑﺎﺷﺪ‪:‬‬ ‫;)][‪int main(int a, char* c‬‬

‫ﻣﻲﺷﻮد ﻣﻮﻗﻊ اﺟﺮاي ﻳﻚ ﺑﺮﻧﺎﻣﻪ ﺑﻪ آن آرﮔﻮﻣﺎن داد‪ .‬ﻣﺜﻼ اﮔﺮ ‪ bc.exe‬ﻳﻚ ﺑﺮﻧﺎﻣﻪ در دراﻳﻮ ‪ C:‬ﺑﺎﺷﺪ ﺑﺮاي اﺟﺮاي‬ ‫آن در ‪) Command Prompt‬ﻛﻪ در ﺑﺨﺶ ﻗﺒﻞ ﮔﻔﺘﻢ ﭼﻪ ﻃﻮر آن را ﺑﺎز ﻛﻨﻴﺪ( ﻣﻲﺷﻮد ﻧﻮﺷﺖ‪:‬‬ ‫‪c:\bc.exe hello bye‬‬

‫اﻳﻦ ﺧﻂ ﺑﺎﻋﺚ اﺟﺮاي ﺑﺮﻧﺎﻣﻪي ‪ bc.exe‬ﻣﻲﺷﻮد و ‪ hello‬و ‪ bye‬دو آرﮔﻮﻣﺎن ﺑﺮاي ﺑﺮﻧﺎﻣﻪي ‪ bc.exe‬ﻫﺴﺘﻨﺪ‬ ‫ﻛﻪ ﻣﻮﻗﻊ اﺟﺮا ﺑﻪ آن داده ﻣﻲﺷﻮﻧﺪ‪ .‬در واﻗﻊ اﻳﻦ آرﮔﻮﻣﺎن ﺑﻪ ﭘﺎراﻣﺘﺮﻫﺎي ﺗﺎﺑﻊ )(‪ main‬داده ﻣﻲﺷﻮﻧﺪ‪.‬‬ ‫در ‪compiler‬ﺗﺎن ﺑﺮﻧﺎﻣﻪي زﻳﺮ را اﺟﺮا ﻛﻨﻴﺪ ﺗﺎ از آن ﻓﺎﻳﻞ ‪ console.exe‬درﺳﺖ ﺑﺸﻮد‪:‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)][‪int main(int a, char* c‬‬ ‫{‬

‫‪350‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;)"‪system("cls‬‬ ‫‪cout<< a‬‬ ‫;‪<< endl‬‬ ‫;‪cout<< c[0] << endl‬‬ ‫;‪cout<< c[1] << endl‬‬ ‫;‪cout<< c[2] << endl‬‬ ‫;‪cout<< c[3] << endl‬‬ ‫;"‪cout<< "bye\n‬‬ ‫;)"‪system("pause‬‬ ‫}‬

‫در ‪ BDS 2006‬و در ‪ Visual C++ 2005‬اﺟﺮاي آن ﻳﻚ ‪ exception‬ﺑﻪ وﺟﻮد ﻣﻲآورد‪ .‬آن را ﻧﺎدﻳﺪه‬ ‫ﺑﮕﻴﺮﻳﺪ‪ .‬ﭼﻮن ﻗﺼﺪ ﻣﺎ ﻓﻘﻂ اﻳﺠﺎد ﻓﺎﻳﻞ ‪ console.exe‬از ﺑﺮﻧﺎﻣﻪ اﺳﺖ‪.‬‬ ‫ﻓﺎﻳﻞ ‪ console.exe‬را ﻣﺴﺘﻘﻴﻤﺎ در دراﻳﻮ ‪ C‬ﻳﻌﻨﻲ در آدرس \‪ C:‬ﻛﭙﻲ ﻛﻨﻴﺪ‪ .‬ﺣﺎﻻ ‪ Command Prompt‬را‬ ‫ﺑﺎز ﻛﻨﻴﺪ و در آن اﻳﻦ را ﺑﻨﻮﻳﺴﻴﺪ‪:‬‬ ‫‪c:\console.exe yek do se‬‬

‫و ‪ Enter‬را ﻓﺸﺎر ﺑﺪﻫﻴﺪ‪ .‬ﭘﻨﺠﺮهي ‪ Command Prompt‬ﺑﻪ اﻳﻦ ﺷﻜﻞ ﻣﻲﺷﻮد‪:‬‬

‫ﭘﺲ در‬ ‫;)][‪int main(int a, char* c‬‬

‫‪ yek‬آرﮔﻮﻣﺎن اول اﺳﺖ‪ do ،‬آرﮔﻮﻣﺎن دوم اﺳﺖ و ‪ se‬آرﮔﻮﻣﺎن ﺳﻮم‪ c[1] .‬ﺑﻪ آرﮔﻮﻣﺎن اول‪ c[2] ،‬ﺑﻪ‬ ‫آرﮔﻮﻣﺎن دوم و ]‪ c[3‬ﺑﻪ آرﮔﻮﻣﺎن ﺳﻮم اﺷﺎره دارد‪ c[0] .‬اﺳﻢ و آدرس ﻓﺎﻳﻞ اﺟﺮاﻳﻲ ﻳﻌﻨﻲ ‪ console.exe‬را‬ ‫دارد‪ .‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ]‪c[i‬ﻫﺎ رﺷﺘﻪ ﻫﺴﺘﻨﺪ‪ a .‬ﻣﻘﺪار ‪ 4‬دارد ﻛﻪ ﻳﻜﻲ ﺑﻴﺶ ﺗﺮ ﺗﻌﺪاد آرﮔﻮﻣﺎنﻫﺎﺳﺖ‪.‬‬ ‫‪351‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫در ‪ BDS 2006‬ﻣﻲﺷﻮد در ﻣﺤﻴﻂ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ )‪ (IDE‬آرﮔﻮﻣﺎنﻫﺎ را ﺑﻪ ﺑﺮﻧﺎﻣﻪ داد ﺗﺎ ﻛﺎر ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ راﺣﺖ‬ ‫ﺗﺮ ﺑﺎﺷﺪ‪ .‬ﺑﺮاي اﻳﻦ ﻛﺎ در ‪ BDS 2006‬اﻳﻦ ﻣﺴﻴﺮ را ﻃﻲ ﻛﻨﻴﺪ‪:‬‬ ‫…‪Run | Parameters‬‬ ‫اﻳﻦ ﭘﻨﺠﺮه ﺑﺎز ﻣﻲﺷﻮد‪:‬‬

‫در ﻗﺴﻤﺖ ‪ Parameters‬ﻣﻲﺗﻮاﻧﻴﻢ آرﮔﻮﻣﺎن را وارد ﻛﻨﻴﻢ‪.‬‬ ‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ آرﮔﻮﻣﺎنﻫﺎ ﺑﺎ ﻳﻚ ﺟﺎي ﺧﺎﻟﻲ ﺟﺪا ﻣﻲﺷﻮﻧﺪ‪ .‬ﺑﺮﻧﺎﻣﻪي زﻳﺮ اﺳﻢ و آدرس و ﻫﻤﻪي آرﮔﻮﻣﺎنﻫﺎي‬ ‫ﺑﺮﻧﺎﻣﻪ را ﭼﺎپ ﻣﻲﻛﻨﺪ‪ .‬ﺑﻪ آن آرﮔﻮﻣﺎنﻫﺎي‬ ‫‪yek do se char panj 25‬‬

‫را دادهام و آن را اﺟﺮا ﻛﺮدهام‪:‬‬ ‫>‪#include <iostream‬‬

‫‪352‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ using namespace std; int main(int argc, char *argv[]) { for(int i = 0; i < argc; i++) cout<< argv[i] << endl; system("pause"); }

Output: G:\Important Files\My Documents\Borland Studio Projects\Console\Debug_Build\Cons ole.exe yek do se char panj 25 Press any key to continue . . .

.‫ ﺑﺴﻴﺎر ﻣﺘﺪاول اﺳﺖ‬main() ‫ ﺑﺮاي ﭘﺎراﻣﺘﺮ دوم‬argv ‫ ﺑﺮاي ﭘﺎراﻣﺘﺮ اول و اﺳﻢ‬argc ‫اﺳﻢ‬

stdarg.h

(‫ ﺗﻌﺪاد ﻣﺘﻐﻴﺮﻫﺎي )ﻳﻌﻨﻲ ﭘﺎراﻣﺘﺮﻫﺎي‬،‫ ﻛﻤﻲ ﺗﻌﺠﺐ ﻛﺮده ﺑﺎﺷﻴﺪ ﭼﻮن ﺗﺎ ﻗﺒﻞ از آن‬printf ‫ﺷﺎﻳﺪ ﺑﺎ دﻳﺪن ﺗﺎﺑﻊ‬ ‫ ﻣﺎ ﻫﻢ ﻣﻲﺗﻮاﻧﻴﻢ‬stdarg.h ‫ ﺑﺎ اﺳﺘﻔﺎده از‬.‫ ﻧﺎﻣﺸﺨﺺ اﺳﺖ‬printf ‫ﺗﺎﺑﻊﻫﺎ ﻣﺸﺨﺺ ﺑﻮد اﻣﺎ ﺗﻌﺪاد ﻣﺘﻐﻴﺮﻫﺎي‬ :‫ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‬.‫ﻫﻤﭽﻴﻦ ﺗﺎﺑﻊﻫﺎﻳﻲ ﺑﻨﻮﻳﺴﻴﻢ‬ #include <conio.h> #include <stdio.h> #include <stdarg.h> void Print(int a, ...) { va_list marker; va_start(marker,a); int* p = (int*)marker; int i = 0; printf("%d\n",a); for(i = 0; p[i] != 0; i++) printf("%d\n",p[i]); } int main() {

353

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;)‪Print(1,2,3,4,5,6,7,8,9,0‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬ ‫‪7‬‬ ‫‪8‬‬ ‫‪9‬‬

‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺗﺎﺑﻊ )(‪ Print‬ﻫﻤﻪي آرﮔﻮﻣﺎنﻫﺎي ﺧﻮد را ﻛﻪ ﻗﺮار اﺳﺖ ﻧﻮع ‪ int‬داﺷﺘﻪ ﺑﺎﺷﻨﺪ ﭼﺎپ ﻣﻲﻛﻨﺪ‪.‬‬ ‫ﻣﺘﻐﻴﺮ ‪) marker‬ﻛﻪ در واﻗﻊ ﻳﻚ ‪ pointer‬اﺳﺖ( از ﻧﻮع ‪ va_list‬ﺗﻌﺮﻳﻒ ﺷﺪه و ﻗﺮار اﺳﺖ ﺑﻪ ﻟﻴﺴﺖ‬ ‫ﭘﺎراﻣﺘﺮﻫﺎ ﺑﻪ ﺟﺰ ﭘﺎراﻣﺘﺮ اول اﺷﺎره داﺷﺘﻪ ﺑﺎﺷﺪ‪ va_start .‬ﻳﻚ ﻣﺎﻛﺮو اﺳﺖ و ﻛﺎر آن اﻳﻦ اﺳﺖ ﻛﻪ‬ ‫‪ marker‬را ﻃﻮري ﺗﻐﻴﻴﺮ ﺑﺪﻫﺪ ﻛﻪ ﺑﻪ ﻟﻴﺴﺖ ﭘﺎراﻣﺘﺮﻫﺎي ﻣﺸﺨﺺ ﻧﺸﺪه اﺷﺎره ﻛﻨﺪ‪ .‬اوﻟﻴﻦ آرﮔﻮﻣﺎن آن ‪marker‬‬

‫و دوﻣﻴﻦ آرﮔﻮﻣﺎن آن )اﺳﻢ( آﺧﺮﻳﻦ ﭘﺎراﻣﺘﺮ ﻣﺸﺨﺺ ﺷﺪه اﺳﺖ‪ .‬ﺑﻌﺪ از اﺟﺮاي آن‪ marker ،‬ﺑﻪ ﻟﻴﺴﺖ‬ ‫ﭘﺎراﻣﺘﺮﻫﺎي ﻣﺸﺨﺺ ﻧﺸﺪه اﺷﺎره دارد‪ .‬ﭼﻮن ﻗﺮار اﺳﺖ ﭘﺎراﻣﺘﺮﻫﺎ‪ ،‬ﻧﻮع ‪ int‬داﺷﺘﻪ ﺑﺎﺷﻨﺪ ‪ p‬را ﺑﺎ ﻧﻮع *‪ int‬ﻣﻌﺮﻓﻲ‬ ‫ﻛﺮدهام و ‪ marker‬را ﺑﻪ آن ﻧﺴﺒﺖ دادهام‪ .‬ﻣﻘﺎدﻳﺮ ﭘﺎراﻣﺘﺮﻫﺎ )ﻛﻪ ﻗﺮار اﺳﺖ ﺑﻪ ﺻﻔﺮ ﺧﺘﻢ ﺷﻮﻧﺪ( ﭼﺎپ ﻣﻲﺷﻮﻧﺪ‪.‬‬ ‫راه رﺳﻤﻲ ﺗﺮي ﻫﻢ ﺑﺮاي اﺳﺘﻔﺎده از ‪ marker‬ﻫﺴﺖ و آن ﺑﻪ ﻛﺎر ﺑﺮدن ﻣﺎﻛﺮوي )(‪ va_arg‬اﺳﺖ‪ .‬ﻣﺜﺎل ﻗﺒﻞ‬ ‫را ﻣﻲﺷﻮد ﺑﻪ اﻳﻦ ﺻﻮرت ﺗﻐﻴﻴﺮ داد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <stdio.h‬‬ ‫>‪#include <stdarg.h‬‬ ‫)‪void Print(int a, ...‬‬ ‫{‬ ‫;‪va_list marker‬‬ ‫;)‪va_start(marker,a‬‬ ‫;‪int i‬‬ ‫))‪for(i = a; i != 0; i = va_arg(marker,int‬‬ ‫;)‪printf("%d\n",i‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪Print(1,2,3,4,5,6,7,8,9,0‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬

‫‪354‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪1‬‬ ‫‪2‬‬ ‫‪3‬‬ ‫‪4‬‬ ‫‪5‬‬ ‫‪6‬‬ ‫‪7‬‬ ‫‪8‬‬ ‫‪9‬‬

‫در واﻗﻊ اﮔﺮ ‪ marker‬را ﺑﻪ ﻋﻨﻮان ﻟﻴﺴﺖ ﭘﺎراﻣﺘﺮﻫﺎ ﺑﮕﻴﺮﻳﻢ ﻣﺜﻼ ﻟﻴﺴﺖ زﻳﺮ‬ ‫‪2,3,4,5,6,7,8,9,0‬‬

‫ﺑﺎ ﻧﻮﺷﺘﻦ‬ ‫)‪i = va_arg(marker,int‬‬

‫ﭼﻬﺎر ﺑﺎﻳﺖ اول ﻟﻴﺴﺖ ﺟﺪا ﻣﻲﺷﻮد و در ‪ i‬ﻗﺮار ﻣﻲﮔﻴﺮد و ﺑﻌﺪ اﺟﺮاي اﻳﻦ دﺳﺘﻮر‪ marker ،‬ﺑﻪ اﻳﻦ ﻟﻴﺴﺖ‪:‬‬ ‫‪3,4,5,6,7,8,9,0‬‬

‫اﺷﺎره دارد‪ .‬آرﮔﻮﻣﺎن دوم )(‪ va_arg‬ﻧﻮع ﻣﺘﻐﻴﺮ را ﻣﺸﺨﺺ ﻣﻲﻛﻨﺪ‪ .‬در اﻳﻦ ﻣﺜﺎل ﻓﺮض ﺑﺮ اﻳﻦ اﺳﺖ ﻛﻪ‬ ‫ﻣﺘﻐﻴﺮﻫﺎﻳﻲ ﻛﻪ ﺑﻪ )(‪ Print‬داده ﻣﻲﺷﻮﻧﺪ‪ ،‬ﻫﻤﻪ ﻧﻮع ‪ int‬داﺷﺘﻪ ﺑﺎﺷﻨﺪ‪ .‬ﺣﺎل ﺑﻴﺎﻳﻴﺪ ﺗﺎﺑﻌﻲ ﺑﻨﻮﻳﺴﻴﻢ ﻛﻪ ﻣﺸﺎﺑﻪ‬ ‫‪ printf‬ﻋﻤﻞ ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪#include <stdarg.h‬‬ ‫)‪void f(char* c,...‬‬ ‫{‬ ‫;‪va_list marker‬‬ ‫;)‪va_start(marker,c‬‬ ‫;‪unsigned r = 0‬‬ ‫)‪while(true‬‬ ‫{‬ ‫)]‪switch(c[r++‬‬ ‫{‬ ‫‪case 'd':‬‬ ‫{‬ ‫;)‪double d = va_arg(marker,double‬‬ ‫;‪cout<< d << endl‬‬ ‫;‪break‬‬ ‫}‬ ‫‪case 'i':‬‬ ‫{‬ ‫;)‪int i = va_arg(marker,int‬‬ ‫;‪cout<< i << endl‬‬ ‫;‪break‬‬ ‫}‬ ‫‪default:‬‬

‫‪355‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;‪return‬‬ ‫}‬ ‫}‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪f("iddii", 1, 2.3, 4.56, 7, 8‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1‬‬ ‫‪2.3‬‬ ‫‪4.56‬‬ ‫‪7‬‬ ‫‪8‬‬ ‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ آرﮔﻮﻣﺎن اول ﺗﺎﺑﻊ‪ ،‬ﻳﻚ رﺷﺘﻪ اﺳﺖ ﻛﻪ ﺑﺎﻳﺪ ﺗﻨﻬﺎ ﺷﺎﻣﻞ ﻛﺎراﻛﺘﺮﻫﺎي '‪ 'i‬ﺑﻪ ﻧﺸﺎﻧﻪي ‪ int‬و '‪'d‬‬ ‫ﺑﻪ ﻧﺸﺎﻧﻪي ‪ double‬ﺑﺎﺷﺪ‪ .‬آرﮔﻮﻣﺎنﻫﺎي ﺑﻌﺪي ﺗﺎﺑﻊ ﺑﺎﻳﺪ ﻃﺒﻖ آن ﭼﻪ در رﺷﺘﻪ ﻫﺴﺖ از ﻧﻮع ‪ int‬ﻳﺎ ‪double‬‬

‫ﺑﺎﺷﻨﺪ‪ f() .‬اﻳﻦ آرﮔﻮﻣﺎنﻫﺎ را ﭼﺎپ ﻣﻲﻛﻨﺪ‪ .‬ﻣﻲﺷﻮد ﺑﻪ ﺟﺎي‬ ‫)‪void f(char* c,...‬‬

‫ﻧﻮﺷﺖ‪:‬‬ ‫)‪void f(char* c...‬‬

‫ﻛﻪ در آن »‪ «,‬ﺣﺬف ﺷﺪه‪ .‬در ‪ BDS 2006‬در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻣﻲﺷﻮد‬ ‫>‪#include <stdarg.h‬‬

‫را ﺣﺬف ﻛﺮد‪.‬‬ ‫آﻳﺎ ﻣﻲﺷﻮد ﺗﺎﺑﻌﻲ ﺑﺎ ‪ prototype‬زﻳﺮ داﺷﺖ؟‬ ‫;)‪void f(...‬‬

‫در )(‪ va_start‬ﭘﺎراﻣﺘﺮ دوم ﺑﺎﻳﺪ ﻧﺎم آﺧﺮﻳﻦ ﭘﺎراﻣﺘﺮ ﻣﺸﺨﺺ ﺑﺎﺷﺪ وﻟﻲ اﻳﻦ ﺟﺎ ﻫﻴﭻ ﭘﺎراﻣﺘﺮ ﻣﺸﺨﺼﻲ ﻧﺪارﻳﻢ‬ ‫ﺑﻨﺎﺑﺮاﻳﻦ ﻧﻤﻲﺗﻮاﻧﻴﻢ از )(‪ va_start‬اﺳﺘﻔﺎده ﻛﻨﻴﻢ‪ .‬در ﻫﺮ ﺣﺎل ﺑﺮﻧﺎﻣﻪي زﻳﺮ اﺟﺮا ﻣﻲﺷﻮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫)‪void f(...‬‬ ‫{‬ ‫;"‪cout<< "hello\n‬‬ ‫}‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪f(1,2‬‬

‫‪356‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫;)(‪cout<< typeid(f).name‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫‪hello‬‬ ‫)‪void (*)(...‬‬ ‫‪Output (Visual C++ 2005):‬‬ ‫‪hello‬‬ ‫)‪void __cdecl(...‬‬

‫در ‪compiler‬ﻫﺎي ﻗﺪﻳﻤﻲ ﺗﺮ ‪ ،Borland‬در [ ‪! 0.‬رد‪!6 ,‬ا‪T , * .8G/‬ر‪ !+‬ن دوم‬ ‫)(‪ & ،va_start‬ﺑﮕﺬارﻳﻢ‪.‬‬

‫‪map‬‬

‫‪ map‬ﻳﻚ ‪ header file‬ﻣﺨﺼﻮص ‪ C++‬اﺳﺖ و در ‪ C‬ﻗﺎﺑﻞ اﺳﺘﻔﺎده ﻧﻴﺴﺖ‪ .‬ﻳﺎد ﮔﺮﻓﺘﻦ ‪header file‬ﻫﺎي‬ ‫‪ C++‬ﺳﺨﺖ ﺗﺮ از ‪header file‬ﻫﺎي ‪ C‬اﺳﺖ ﭼﻮن ﺑﺎ اﺳﺘﻔﺎده از ﻛﻼسﻫﺎ ﻧﻮﺷﺘﻪ ﺷﺪهاﻧﺪ‪ .‬ﺑﻪ ﺷﻜﻞ زﻳﺮ ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬

‫در اﻳﻦ ﺗﺼﻮﻳﺮ‪ 1 ،‬ﺑﻪ ‪ 30‬ﻧﮕﺎﺷﺘﻪ ﺷﺪه‪ .‬ﻫﻤﻴﻦ ﻃﻮر ‪ 2‬ﺑﻪ ‪ 10‬و ‪ 3‬ﺑﻪ ‪ 20‬ﻧﮕﺎﺷﺘﻪ ﺷﺪه‪ .‬ﺑﻪ ﺟﺎي ﺑﻪ ﻛﺎر ﺑﺮدن ﺷﻜﻞ‬ ‫ﺑﺎﻻ ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻨﻮﻳﺴﻴﻢ‪:‬‬ ‫)‪(1,30‬‬ ‫)‪(2,10‬‬ ‫)‪(3,20‬‬

‫‪357‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ﺑﻪ ﻣﻌﻨﻲ ﻧﮕﺎﺷﺖ‬mapping .‫ ﻧﺎم دارﻧﺪ( ﻳﻚ ﻧﮕﺎﺷﺖ ﻣﻲﮔﻮﻳﻴﻢ‬pair ‫ﺑﻪ ﻣﺠﻤﻮﻋﻪي اﻳﻦﻫﺎ )ﻛﻪ دوﺗﺎﻳﻲ ﻣﺮﺗﺐ ﻳﺎ‬ ‫ ﻛﻪ در‬map ‫ در ﻣﺜﺎل زﻳﺮ از ﻛﻼس‬.‫ از ﻫﻤﻴﻦ ﻛﻠﻤﻪ ﮔﺮﻓﺘﻪ ﺷﺪه‬map ِ header file ‫اﺳﺖ و اﺣﺘﻤﺎﻻ اﺳﻢ‬ ‫ ﻣﻌﺮﻓﻲ ﺷﺪه اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ و ﻧﮕﺎﺷﺖ‬map ِ header file (1,10.1) (2,20.2) (3,30.3)

-‫ﻫﺎي( اﻳﻦ ﻧﮕﺎﺷﺖ را ﭼﺎپ ﻣﻲ‬pair =) ِ ‫ ﺟﺎي ﻣﻲدﻫﻴﻢ و ﺑﻌﺪ دوﺗﺎﻳﻲﻫﺎي ﻣﺮﺗﺐ‬map ‫ از ﻧﻮع‬object ‫را در ﻳﻚ‬ :‫ﻛﻨﻴﻢ‬ #include <conio.h> #include <iostream> using namespace std; #include <map> typedef map<int,double> typedef MAP::iterator typedef pair<int,double>

MAP; ITERATOR; PAIR;

int main() { MAP m; ITERATOR it; m.insert(PAIR(1, 10.1)); m.insert(PAIR(2, 20.2)); m.insert(PAIR(3, 30.3)); for(it = m.begin(); it != m.end(); it++) { cout << it -> first << " "; cout << it -> second << "\n"; } _getch(); }

Output: 1 10.1 2 20.2 3 30.3

‫ﻫﺎي‬pair ‫ ﻳﻚ ﻧﮕﺎﺷﺖ را ﻣﺸﺨﺺ ﻣﻲﻛﻨﺪ ﻛﻪ‬map<int,double> .‫ اﺳﺖ‬template ‫ در واﻗﻊ ﻳﻚ‬map ‫ در اﻳﻦ ﻣﺜﺎل ﺑﺮاي راﺣﺘﻲ‬.‫ دارد‬double ‫ ﻧﻮع‬y ‫ و‬int ‫ ﻧﻮع‬x ‫(ﻫﺴﺘﻨﺪ ﻛﻪ‬x,y) ‫آن ﺑﻪ ﺷﻜﻞ‬ .‫ ﻧﺸﺎن دادهام‬MAP ‫ را ﺑﺎ‬map<int,double> (‫ از ﻧﻮع آن‬object ‫ آن )ﻳﻌﻨﻲ ﻫﺮ‬instance ‫ ﻫﻢ در واﻗﻊ ﻛﻼﺳﻲ اﺳﺖ ﻛﻪ ﻫﺮ‬pair<int,double> .‫ دارد‬double ‫ ﻧﻮع‬y ‫ و‬int ‫ ﻧﻮع‬x ‫(اﺳﺖ ﻛﻪ‬x,y) ‫ ﺑﻪ ﺷﻜﻞ‬pair ‫ﻧﻤﺎﻳﻨﺪهي ﻳﻚ‬ 358

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪ map<int,double>::iterator‬ﻳﻚ ﻧﻮع اﺳﺖ ﻛﻪ ﻗﺮار اﺳﺖ ﻫﺮ ‪ instance‬آن ﺑﻪ ﻳﻚ ‪ pair‬در‬ ‫ﻧﮕﺎﺷﺖ اﺷﺎره ﻛﻨﺪ‪ .‬اﻳﻦ ﻧﻮع را ﺑﺎ ‪ ITERATOR‬ﻧﺸﺎن دادهام‪.‬‬ ‫در ﺗﺎﺑﻊ )(‪ main‬ﻳﻚ ﻧﮕﺎﺷﺖ ﺑﺎ ﻧﺎم ‪ m‬ﺗﻌﺮﻳﻒ ﻛﺮدهام ﻛﻪ ﻗﺮار اﺳﺖ ‪pair‬ﻫﺎﻳﻲ ﺑﻪ ﺷﻜﻞ )‪(x,y‬داﺷﺘﻪ ﺑﺎﺷﺪ ﻛﻪ‬ ‫در آن ‪ x‬ﻧﻮع ‪ int‬و ‪ y‬ﻧﻮع ‪ double‬دارد‪.‬‬ ‫‪ insert‬ﻳﻚ ‪ method‬اﺳﺖ ﻛﻪ ﻛﺎر آن اﺿﺎﻓﻪ ﻛﺮدن ﻳﻚ ‪ pair‬ﺑﻪ ﻧﮕﺎﺷﺖ اﺳﺖ‪pair .‬ﻫﺎي‬ ‫)‪(1,10.1‬‬ ‫)‪(2,20.2‬‬ ‫)‪(3,30.3‬‬

‫ﺑﺎ اﺳﺘﻔﺎده از ‪ insert‬ﺑﻪ ﻧﮕﺎﺷﺖ ‪ m‬اﺿﺎﻓﻪ ﺷﺪهاﻧﺪ‪ .‬ﺑﻌﺪ از اﺟﺮاي )(‪ it ،it = m.begin‬ﺑﻪ اوﻟﻴﻦ ‪pair‬‬ ‫اﺷﺎره ﻣﻲﻛﻨﺪ‪ .‬ﺑﺎ اﺟﺮاي ‪ it ،it++‬ﺑﻪ ‪ pair‬ﺑﻌﺪي اﺷﺎره ﻣﻲﻛﻨﺪ‪ .‬در ﺣﻠﻘﻪي ‪ for‬وﻗﺘﻲ ‪ it‬ﺑﺮاﺑﺮ ﺷﺪ ﺑﺎ‬ ‫)(‪ m.end‬ﻫﻤﻪي ‪pair‬ﻫﺎ ﭼﺎپ ﺷﺪهاﻧﺪ‪ .‬وﻗﺘﻲ ‪ it‬ﺑﻪ ‪ (x,y) ِ pair‬اﺷﺎره دارد‪ it-> first ،‬ﺑﺮاﺑﺮ ﺑﺎ ‪x‬‬

‫و ‪ it->second‬ﺑﺮاﺑﺮ ﺑﺎ ‪ y‬اﺳﺖ‪.‬‬ ‫اﮔﺮ ‪ m‬ﻳﻚ ﻧﮕﺎﺷﺖ ﺑﺎﺷﺪ و )‪ (x,y‬در ‪ m‬ﺑﺎﺷﺪ ﻣﻲﮔﻮﻳﻴﻢ ‪ x ،m‬را ﺑﻪ ‪ y‬ﻣﻲﻧﮕﺎرد‪ .‬از وﻳﮋﮔﻲﻫﺎي ﻳﻚ ﻧﮕﺎﺷﺖ اﻳﻦ‬ ‫اﺳﺖ ﻛﻪ ﻳﻚ ﭼﻴﺰ را ﺑﻪ ﭼﻨﺪ ﭼﻴﺰ ﻧﻤﻲﻧﮕﺎرد ﻳﻌﻨﻲ اﮔﺮ ‪ x‬را ﺑﻪ ‪ y‬ﺑﻨﮕﺎرد‪ x ،‬را ﺑﻪ ﻫﻴﭻ ﭼﻴﺰ دﻳﮕﺮي ﻧﻤﻲﻧﮕﺎرد‪ .‬ﻣﺜﺎل‬ ‫ﻗﺒﻞ را ﻛﻤﻲ ﺗﻐﻴﻴﺮ ﻣﻲدﻫﻢ ﺗﺎ اﻳﻦ ﻣﻄﺐ روﺷﻦ ﺑﺸﻮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪#include <map‬‬ ‫;‪MAP‬‬ ‫;‪ITERATOR‬‬ ‫;‪PAIR‬‬

‫>‪typedef map<int,double‬‬ ‫‪typedef MAP::iterator‬‬ ‫>‪typedef pair<int,double‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪MAP m‬‬ ‫;‪ITERATOR it‬‬ ‫;))‪m.insert(PAIR(1, 10.1‬‬ ‫;))‪m.insert(PAIR(2, 20.2‬‬ ‫;))‪m.insert(PAIR(1, 30.3‬‬

‫)‪for (it = m.begin(); it != m.end(); it++‬‬ ‫{‬ ‫;" " << ‪cout << it -> first‬‬ ‫;"‪cout << it -> second << "\n‬‬ ‫}‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪359‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪Output:‬‬ ‫‪1 10.1‬‬ ‫‪2 20.2‬‬

‫اﻳﻦ ﻣﺜﺎل دﻗﻴﻘﺎ ﻣﺎﻧﻨﺪ ﻣﺜﺎل ﻗﺒﻞ اﺳﺖ ﺑﺎ اﻳﻦ ﻓﺮق ﻛﻪ در اﻳﻦ ﺟﺎ ﺑﻪ ﺟﺎي )‪(3,30.1‬ﺳﻌﻲ ﻛﺮدهام )‪ (1,30.1‬را‬ ‫ﺑﻪ ﻧﮕﺎﺷﺖ ‪ m‬وارد ﻛﻨﻢ‪ .‬اﻣﺎ )‪ (1,30.1‬ﺑﻪ ‪ m‬وارد ﻧﺸﺪه اﺳﺖ ﭼﻮن اﮔﺮ وارد ﻣﻲﺷﺪ ‪ 1‬ﺑﻪ دو ﻋﺪد ﻣﺨﺘﻠﻒ‬ ‫ﻧﮕﺎﺷﺘﻪ ﻣﻲﺷﺪ ﻛﻪ اﻳﻦ اﻣﻜﺎن ﻧﺪارد‪.‬‬ ‫ﻣﺴﺄﻟﻪي دﻳﮕﺮ )ﺷﺎﻳﺪ ﻫﻢ ﻣﺴﺌﻠﻪي دﻳﮕﺮ‬

‫( ﺗﺮﺗﻴﺐ ‪pair‬ﻫﺎ در ﻳﻚ ﻧﮕﺎﺷﺖ اﺳﺖ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪#include <map‬‬ ‫;‪MAP‬‬ ‫;‪ITERATOR‬‬ ‫;‪PAIR‬‬

‫>‪typedef map<int,int‬‬ ‫‪typedef MAP::iterator‬‬ ‫>‪typedef pair<int,int‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪MAP m‬‬ ‫;‪ITERATOR it‬‬ ‫;))‪m.insert(PAIR(21, 10‬‬ ‫;))‪m.insert(PAIR(3, 10‬‬ ‫;))‪m.insert(PAIR(7, 30‬‬

‫)‪for (it = m.begin(); it != m.end(); it++‬‬ ‫{‬ ‫;" " << ‪cout << it -> first‬‬ ‫;"‪cout << it -> second << "\n‬‬ ‫}‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪3 10‬‬ ‫‪7 30‬‬ ‫‪21 10‬‬

‫در ﻳﻚ ‪ pair‬ﻣﺜﻞ )‪ (x,y‬ﺑﻪ ‪ x‬ﻣﺆﻟﻔﻪي اول و ﺑﻪ ‪ y‬ﻣﺆﻟﻔﻪي دوم ﻣﻲﮔﻮﻳﻴﻢ )ﻣﺆﻟﻔﻪ را ‪ /mo alle fe/‬ﺑﺎ ﻳﻚ‬ ‫ﺗﺸﺪﻳﺪ روي »ل« ﺗﻠﻔﻆ ﻛﻨﻴﺪ‬

‫(‪pair .‬ﻫﺎي ﻳﻚ ﻧﮕﺎﺷﺖ ﺑﻪ ﻃﻮر ﺧﻮدﻛﺎر ﺑﺎ ﺗﻮﺟﻪ ﺑﻪ ﻣﺆﻟﻔﻪي اول از ﻛﻮﭼﻚ‬

‫ﺑﻪ ﺑﺰرگ ﻣﺮﺗﺐ ﻣﻲﺷﻮﻧﺪ‪ .‬ﺑﺮﻧﺎﻣﻪي ﺑﺎﻻ اﻳﻦ را ﻧﺸﺎن ﻣﻲدﻫﺪ‪ .‬در ﺿﻤﻦ ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ )‪ (3,10‬و )‪ (21,10‬ﺑﺎ‬ ‫اﻳﻦ ﻛﻪ ﻣﺆﻟﻔﻪي دوم ﻣﺴﺎوي دارﻧﺪ ﻫﺮ دو در ‪ m‬ﻫﺴﺘﻨﺪ‪ .‬ﻧﮕﺎﺷﺖ ﻧﻤﻲﺗﻮاﻧﺪ ﻳﻚ ﭼﻴﺰ را ﺑﻪ ﭼﻨﺪ ﭼﻴﺰ ﺑﻨﮕﺎرد اﻣﺎ ﻣﻲ‪-‬‬ ‫ﺗﻮاﻧﺪ ﭼﻨﺪ ﭼﻴﺰ را ﺑﻪ ﻳﻚ ﭼﻴﺰ ﺑﻨﮕﺎرد در اﻳﻦ ﺟﺎ ‪ 3‬و ‪ 21‬ﻫﺮ دو ﺑﻪ ‪ 10‬ﻧﮕﺎﺷﺘﻪ ﺷﺪهاﻧﺪ‪.‬‬

‫‪360‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻣﻤﻜﻦ اﺳﺖ ﺑﺨﻮاﻫﻴﻢ ﻳﻚ ﺗﺮﺗﻴﺐ دﻳﮕﺮ ﺑﺮاي ﻣﺮﺗﺐ ﻛﺮدن داﺷﺘﻪ ﺑﺎﺷﻴﻢ ﻳﻌﻨﻲ ‪pair‬ﻫﺎ ﺑﺎ ﻗﺎﻋﺪهي دﻳﮕﺮي ﻣﺮﺗﺐ‬ ‫ﺑﺸﻮﻧﺪ ﻣﺜﻼ اﮔﺮ ﻣﺆﻟﻔﻪﻫﺎي اول ِ ‪pair‬ﻫﺎ ﻋﺪد ﺑﺎﺷﻨﺪ‪ ،‬ﻣﻤﻜﻦ اﺳﺖ ﺑﺨﻮاﻫﻴﻢ اول اﻋﺪاد زوج ﻣﺮﺗﺐ و ﭼﺎپ ﺑﺸﻮﻧﺪ و‬ ‫ﺑﻌﺪ اﻋﺪاد ﻓﺮد‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﺑﺘﻮاﻧﻴﻢ ﻫﻤﭽﻴﻦ ﺗﺮﺗﻴﺒﻲ را ﺑﻪ ‪ map‬ﺑﺸﻨﺎﺳﺎﻧﻴﻢ ﺑﺎﻳﺪ ﺑﺎ ‪ِ template‬‬ ‫>‪template<class Type‬‬ ‫>‪struct less : public binary_function <Type, Type, bool‬‬ ‫{‬ ‫‪bool operator()(const Type& _Left,‬‬ ‫;‪const Type& _Right) const‬‬ ‫;}‬

‫آﺷﻨﺎ ﺑﺸﻮﻳﻢ ﻛﻪ ﺑﺎ ‪ #include‬ﻛﺮدن ‪ map‬در اﺧﺘﻴﺎر ﻣﺎ ﻗﺮار ﻣﻲﮔﻴﺮد‪ .‬ﻗﺒﻞ از آﺷﻨﺎﻳﻲ ﺑﺎ ﻛﺎرﺑﺮد ‪less‬؛ ﺑﻪ ﻧﺤﻮه‪-‬‬ ‫ي ﺗﻌﺮﻳﻒ ‪ less‬ﺗﻮﺟﻪ ﻛﻨﻴﺪ‪ less ِ template .‬از ﻛﻼﺳﻲ ﺳﺎﺧﺘﻪ ﺷﺪه ﻛﻪ ﺧﻮدش از ﻛﻼﺳﻲ دﻳﮕﺮ ‪derive‬‬ ‫ﺷﺪه )اﻟﺒﺘﻪ ﻣﻨﻈﻮر از ﻛﻼس ﻫﻤﺎن ‪ struct‬اﺳﺖ!(‪.‬‬ ‫در ‪ () ،less‬ﻳﻚ ‪ operator‬ﺑﺎ دو ﭘﺎراﻣﺘﺮ اﺳﺖ‪ .‬ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪#include <map‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪less<int> A‬‬ ‫;‪cout<< A(3,2) << endl‬‬ ‫;‪cout<< A(2,3) << endl‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪0‬‬ ‫‪1‬‬

‫)‪ A(3,2‬ﺑﺮاﺑﺮ ﺑﺎ ‪ false‬اﺳﺖ ﭼﻮن ‪ 3‬ﻛﻢ ﺗﺮ از ‪ 2‬ﻧﻴﺴﺖ و )‪ A(2,3‬ﺑﺮاﺑﺮ ﺑﺎ ‪ true‬اﺳﺖ ﭼﻮن ‪ 2‬ﻛﻢ ﺗﺮ از‬ ‫‪ 3‬اﺳﺖ‪ .‬ﻋﻠﺖ اﻳﻦ ﻛﻪ ‪ compiler‬ﻛﻢ ﺗﺮ ﺑﻮدن ِ ‪ 2‬از ‪ 3‬را ﺗﺸﺨﻴﺺ ﻣﻲدﻫﺪ اﻳﻦ اﺳﺖ ﻛﻪ ‪ 2‬و ‪ 3‬ﻧﻮع ‪ int‬دارﻧﺪ‬ ‫و ﺑﺮاي ‪ int‬ﺗﻌﺮﻳﻒ )( ‪) operator‬ﻳﺎ ﺗﻌﺮﻳﻒ ﻋﻤﻠﮕﺮﻫﺎﻳﻲ ﻣﺜﻞ »ﻛﻮﭼﻚ ﺗﺮ ﻣﺴﺎوي«( ﻣﻮﺟﻮد اﺳﺖ‪.‬‬ ‫ﻣﺜﺎل ﻗﺒﻞ را ﻃﻮري ﺗﻐﻴﻴﺮ ﻣﻲدﻫﻴﻢ ﻛﻪ ﻧﺘﻴﺠﻪ ﺑﺮ ﻋﻜﺲ ﺷﻮد ﻳﻌﻨﻲ ‪ 3‬ﻛﻢ ﺗﺮ از ‪ 2‬در ﻧﻈﺮ ﮔﺮﻓﺘﻪ ﺷﻮد و ‪ 2‬ﺑﻴﺶ ﺗﺮ از‬ ‫‪) !!!3‬‬

‫اﻳﻦ ﭼﻴﺰﻫﺎ ﻓﻘﻂ از ﻧﻈﺮ رﻳﺎﺿﻴﺪاﻧﺎن ﻣﺤﺘﺮم ﻋﺎدي ﺑﻪ ﻧﻈﺮ ﻣﻲرﺳﺪ(‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬

‫‪361‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ using namespace std; #include <map> class Less : public less<int> { public: bool operator () (int x, int y) { return y < x; } }; int main() { Less A; cout<< A(3,2) << endl; cout<< A(2,3) << endl; _getch(); }

Output: 1 0

‫ ﺣﺎﻻ ﺑﺎ اﺳﺘﻔﺎده‬.y<x ‫ ﻧﻮﺷﺘﻪام‬x<y ‫ ﺑﻪ ﺟﺎي‬operator () ‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻧﺘﺎﻳﺞ ﺑﺮ ﻋﻜﺲ اﺳﺖ ﭼﻮن در ﺗﻌﺮﻳﻒ‬ :‫ﻫﺎ را از ﺑﺰرگ ﺑﻪ ﻛﻮﭼﻚ ﻣﺮﺗﺐ ﻛﻨﺪ‬pair ‫ ﻳﻚ ﻧﮕﺎﺷﺖ را وادار ﻣﻲﻛﻨﻴﻢ ﻛﻪ‬،‫از اﻳﻦ‬ #include <conio.h> #include <iostream> using namespace std; #include <map> class Less : public less<int> { public: bool operator () (int x, int y) { return y < x; } }; typedef map<int,int,Less> typedef MAP::iterator typedef pair<int,int>

MAP; ITERATOR; PAIR;

int main() { MAP m; ITERATOR it; m.insert(PAIR(21, 10)); m.insert(PAIR(3, 10)); m.insert(PAIR(7, 30)); for (it = m.begin(); it != m.end(); it++)

362

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { cout << it -> first << " "; cout << it -> second << "\n"; } _getch(); }

Output: 21 10 7 30 3 10

‫ در ﺑﺎﻻي ﺑﺮﻧﺎﻣﻪ اﺿﺎﻓﻪ ﺷﺪه و‬Less ‫اﻳﻦ ﺑﺮﻧﺎﻣﻪ درﺳﺖ ﻣﺜﻞ ﻳﻜﻲ از ﺑﺮﻧﺎﻣﻪﻫﺎي ﭘﻴﺸﻴﻦ اﺳﺖ ﺑﺎ اﻳﻦ ﻓﺮق ﻛﻪ ﻛﻼس‬ ‫ﺑﻪ ﺟﺎي‬ typedef map<int,int>

MAP;

:‫ﻧﻮﺷﺘﻪاﻳﻢ‬ typedef map<int,int,Less>

MAP;

‫ ﺣﺎﻻ ﻫﻤﻴﻦ ﺑﺮﻧﺎﻣﻪ را ﻃﻮري ﺗﻐﻴﻴﺮ ﻣﻲدﻫﻴﻢ‬.‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ اﻳﻦ ﺑﺎر ﻣﺆﻟﻔﻪﻫﺎي اول از ﺑﺰرگ ﺑﻪ ﻛﻮﭼﻚ ﻣﺮﺗﺐ ﺷﺪهاﻧﺪ‬ ‫ﻛﻪ اﺑﺘﺪا ﻣﺆﻟﻔﻪﻫﺎي اول زوج را از ﻛﻮﭼﻚ ﺑﻪ ﺑﺰرگ و ﺑﻌﺪ ﻣﺆﻟﻔﻪﻫﺎي اول ﻓﺮد را از ﻛﻮﭼﻚ ﺑﻪ ﺑﺰرگ ﺑﻨﻮﻳﺴﺪ‬ :(

‫)»اول« در اﻳﻦ ﺟﺎ ﻫﻴﭻ رﺑﻄﻲ ﺑﻪ »ﻋﺪد اول« ﻧﺪارد‬

#include <conio.h> #include <iostream> using namespace std; #include <map> class Less : public less<int> { public: bool operator () (int x, int y) { if(x%2 == 0 && y%2 == 1) return true; if(x%2 == 1 && y%2 == 0) return false; return x < y; } }; typedef map<int,int,Less> MAP; typedef MAP::iterator ITERATOR; typedef pair<int,int> PAIR; int main() { MAP m; ITERATOR it; m.insert(PAIR(1, 10)); m.insert(PAIR(2, 20)); m.insert(PAIR(3, 30));

363

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ m.insert(PAIR(4, 40)); m.insert(PAIR(5, 50)); m.insert(PAIR(6, 60)); for (it = m.begin(); it != m.end(); it++) { cout << it -> first << " "; cout << it -> second << "\n"; } _getch(); }

Output: 2 20 4 40 6 60 1 10 3 30 5 50

.‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﻣﺆﻟﻔﻪﻫﺎي اول زوج ﺑﺮ ﻣﺆﻟﻔﻪﻫﺎي اول ﻓﺮد ﺑﺮﺗﺮي داده ﺷﺪهاﻧﺪ‬ ‫ ﺑﺎ ﺑﻪ ﻛﺎر‬.‫ ﺑﻪ ﻳﻚ ﻧﮕﺎﺷﺖ را ﺧﻴﻠﻲ راﺣﺖ ﻛﺮد‬pair ‫ ﻣﻲﺷﻮد ﻛﺎر وارد ﻛﺮدن‬operator []‫ﺑﺎ اﺳﺘﻔﺎده از‬ :‫ ﺑﻪ اﻳﻦ ﻣﺜﺎل ﻧﮕﺎه ﻛﻨﻴﺪ‬.pair<int,int> ‫ ﻫﺴﺖ ﻧﻪ ﺑﻪ‬insert() ‫ ﻧﻪ ﻧﻴﺎزي ﺑﻪ‬،‫ﮔﺮﻓﺘﻦ آن‬ #include <conio.h> #include <iostream> using namespace std; #include <map> typedef map<int,int> int main() { MAP m; m[1] = 10; m[2] = 20; m[3] = 30; m[4] = 40; m[5] = 50; m[6] = 60;

MAP;

int i; for (i = 1; i <= 6; i++) { cout << i << " " << m[i] << endl; } _getch(); }

Output: 1 10 2 20 3 30 4 40

364

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪5 50‬‬ ‫‪6 60‬‬

‫ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺑﺮﻧﺎﻣﻪ ﺧﻴﻠﻲ ﺳﺎده و ﻗﺎﺑﻞ ﻓﻬﻢ ﺗﺮ ﺷﺪه اﺳﺖ‪.‬‬ ‫ﻣﺜﺎل زﻳﺮ ﺟﺎﻟﺐ اﺳﺖ‪ .‬در اﻳﻦ ﻣﺜﺎل ﻓﺮق ﻛﻮﭼﻚ ﺑﻴﻦ ‪ insert‬و ][ ‪ operator‬ﻣﺸﺨﺺ ﺷﺪه‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪#include <map‬‬ ‫>‪typedef map<int,int‬‬ ‫;‪MAP‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;‪MAP m‬‬ ‫;‪m[1] = 10‬‬ ‫;‪m[1] = 20‬‬ ‫;‪cout << 1 << " " << m[1] << endl‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪1 20‬‬

‫‪ insert‬وﻗﺘﻲ ﻗﺎﻧﻮن ﻧﮕﺎﺷﺖﻫﺎ )ﻳﻌﻨﻲ ﻗﺎﻧﻮن »ﻳﻚ ﭼﻴﺰ ﺑﻪ ﭼﻨﺪ ﭼﻴﺰ ﻧﮕﺎﺷﺘﻪ ﻧﻤﻲﺷﻮد«( در ﺷﺮف ﻧﻘﺾ ﻗﺮار ﻣﻲ‪-‬‬ ‫ﮔﺮﻓﺖ )‬

‫( از وارد ﻛﺮدن ‪ ِ pair‬ﻧﻘﺾ ﻛﻨﻨﺪه‪ ،‬ﺧﻮدداري ﻣﻲﻛﺮد اﻣﺎ ‪ ِ operator [] pair‬ﻗﺒﻠﻲ را ﺣﺬف‬

‫ﻣﻲﻛﻨﺪ و ‪ ِ pair‬ﺟﺪﻳﺪ را ﺟﺎي آن ﻣﻲﻧﺸﺎﻧﺪ‪.‬‬ ‫ﻗﺎﻧﻮن ﻧﮕﺎﺷﺖﻫﺎ در واﻗﻊ ﻫﻤﺎن ﺷﺮﻃﻲ اﺳﺖ ﻛﻪ رﻳﺎﺿﻴﺪاﻧﺎن ﺑﺮاي »ﺗﺎﺑﻊ« ﺑﻮدن ﻳﻚ ﻣﺠﻤﻮﻋﻪ از زوجﻫﺎي ﻣﺮﺗﺐ‬ ‫)ﻳﻌﻨﻲ ﻫﻤﺎن ‪pair‬ﻫﺎ( ﻣﻲﮔﺬارﻧﺪ‪ .‬وﺟﻮد آن ﻣﺰاﻳﺎﻳﻲ دارد‪ .‬اﻣﺎ ﻣﻤﻜﻦ اﺳﺖ در ﺟﺎﻫﺎﻳﻲ ﻣﺰاﺣﻢ ﻛﺎر ﻣﺎ ﺑﺎﺷﺪ‪ .‬اﮔﺮ‬ ‫ﺑﺨﻮاﻫﻴﻢ اﻳﻦ ﻗﺎﻧﻮن اﻋﻤﺎل ﻧﺸﻮد ﺑﻪ ﺟﺎي ‪ map‬از ‪ multimap‬اﺳﺘﻔﺎده ﻣﻲﻛﻨﻴﻢ‪ multimap .‬ﺗﺎ ﺣﺪ زﻳﺎدي ﻣﺜﻞ‬ ‫‪ map‬ﻋﻤﻞ ﻣﻲﻛﻨﺪ‪ .‬ﻣﺜﺎل زﻳﺮ ﻧﺤﻮهي ﺑﻪ ﻛﺎر ﺑﺮدن آن را ﻧﺸﺎن ﻣﻲدﻫﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪#include <map‬‬ ‫;‪MAP‬‬ ‫;‪ITERATOR‬‬ ‫;‪PAIR‬‬

‫>‪typedef multimap<int,double‬‬ ‫‪typedef MAP::iterator‬‬ ‫>‪typedef pair<int,double‬‬

‫;‪it‬‬

‫‪365‬‬

‫‪www.pupuol.com‬‬

‫)(‪int main‬‬ ‫{‬ ‫;‪MAP m‬‬ ‫‪ITERATOR‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ m.insert(PAIR(1, 10.1)); m.insert(PAIR(2, 20.2)); m.insert(PAIR(1, 30.3)); for (it = m.begin(); it != m.end(); it++) { cout << it -> first << " "; cout << it -> second << "\n"; } _getch(); }

Output: 1 10.1 1 30.3 2 20.2

string

‫ ﺑﺎ‬string ‫ ﻫﺴﺖ و ﻛﻼس‬basic_string ‫ي ﺑﻪ ﻧﺎم‬string template ِ header file ‫در‬ typedef basic_string<char> string;

‫ ﻛﺎرﺑﺮد دارد‬C++ ‫ ﻓﻘﻂ در‬string ‫ ﺑﺎ اﻳﻦ ﻛﻪ‬.‫ ﻛﺎر ﺑﺎ رﺷﺘﻪﻫﺎ را آﺳﺎن ﻣﻲﻛﻨﺪ‬string ‫ ﻛﻼس‬.‫ﺗﻌﺮﻳﻒ ﺷﺪه‬ .‫ﻳﺎد ﮔﺮﻓﺘﻦ آن ﺧﻴﻠﻲ راﺣﺖ اﺳﺖ‬ :‫ را ﻧﺸﺎن ﻣﻲدﻫﺪ‬+ ‫ و ﻋﻤﻠﻜﺮد ﻋﻤﻠﮕﺮ‬string ‫ﻫﺎﻳﻲ از‬instance ‫ﻣﺜﺎل زﻳﺮ اﻳﺠﺎد‬ #include <conio.h> #include <iostream> using namespace std; #include <string> int main() { string str1 = "hello"; string str2 ("bye"); cout<< str1 + str2; _getch(); }

Output: hellobye

.‫ دو رﺷﺘﻪ را ﺑﻪ ﻫﻢ ﻣﻲﭼﺴﺒﺎﻧﺪ‬operator + ‫ﺑﻨﺎﺑﺮاﻳﻦ‬

366

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ :(‫ﺑﺎ < و == ﻣﻲﺷﻮد ﺗﺮﺗﻴﺐ را ﻣﺸﺨﺺ ﻛﺮد )ﻣﺜﻞ ﺗﺮﺗﻴﺐ ﻛﻠﻤﺎت در ﻳﻚ ﻓﺮﻫﻨﮓ ﻟﻐﺖ‬ #include <conio.h> #include <iostream> using namespace std; #include <string> int main() { string str1 = "abc"; string str2 = "abd"; if(str1 == str2) cout<<"they are equal"; else if(str1 < str2) cout<< "str1 < str2"; else cout<< "str2 < str1"; _getch(); }

Output: str1 < str2

:‫ﺑﺮاي اﻳﻦ ﻛﻪ ﻣﺜﺎل ﺑﻬﺘﺮي زده ﺑﺎﺷﻢ اﻳﻦ ﺑﺮﻧﺎﻣﻪ را اﺟﺮا ﻛﻨﻴﺪ‬ #include <conio.h> #include <iostream> using namespace std; #include <map> #include <string> typedef map<string,int> typedef MAP::iterator int main() { MAP m; m["hello"] m["bye"] m["Bye"] m["mouse"] m["horton"] m["ratatouille"]

= = = = = =

MAP; ITERATOR;

0; 0; 0; 0; 0; 0;

for (ITERATOR it = m.begin(); it != m.end(); it++) cout << it -> first << endl; _getch(); }

Output: Bye bye hello

367

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ horton mouse ratatouille

‫ ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ ﺑﻪ ﺟﺎي‬.‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻛﻠﻤﺎت ﺑﺎ اﺳﺘﻔﺎده از ﻳﻚ ﻧﮕﺎﺷﺖ ﻣﺮﺗﺐ ﺷﺪهاﻧﺪ‬ string str = "hello"; m[str] = 0;

:‫ﻧﻮﺷﺘﻪام‬ m["hello"] = 0;

‫ ﺗﺒﺪﻳﻞ ﻣﻲﻛﻨﺪ ﺑﻪ ﺟﺎي‬string ‫ را ﺑﻪ‬C Style ‫ ﺑﺎﺷﺪ ﻛﻪ رﺷﺘﻪﻫﺎي ﻣﻌﻤﻮﻟﻲ‬constructor ‫وﻗﺘﻲ ﻳﻚ‬ .‫ ﺑﺎﺷﺪ ﻣﺜﻞ اﻳﻦ ﺟﺎ ﻣﻲﺷﻮد ﻳﻚ رﺷﺘﻪي ﻣﻌﻤﻮﻟﻲ ﻧﻮﺷﺖ‬string ‫آرﮔﻮﻣﺎﻧﻲ ﻛﻪ ﺑﺎﻳﺪ‬ :‫ ﺟﺎي دو رﺷﺘﻪ را ﻋﻮض ﻣﻲﻛﻨﺪ‬swap() ‫ﺗﺎﺑﻊ‬ #include <conio.h> #include <iostream> using namespace std; #include <string> int main() { string s1("hello"), s2("bye"); cout<< s1 << "\t" << s2 << endl; swap(s1,s2); cout<< s1 << "\t" << s2 << endl; _getch(); }

Output: hello bye

bye hello

.‫ ﭼﺎپ ﻣﻲﻛﻨﺪ‬،‫ را‬string ‫ ﺑﻪ راﺣﺘﻲ ﻳﻚ‬cout ‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ‬ :‫ ﻛﺮدن ﺑﻪ ﻛﺎر ﻣﻲرود‬assign ‫ ﺑﺮاي‬operator = #include <conio.h> #include <iostream> using namespace std; #include <string> int main() { string s1("hello"),s2; s2 = s1; cout<< s2; _getch();

368

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ }

Output: hello

string.h

‫ ﻧﻴﺎز ﺑﻪ‬string ِ header file ‫ وﺟﻮد‬.‫ اﺳﺖ‬C ‫ ﺑﺮاي ﻛﺎر ﺑﺎ رﺷﺘﻪﻫﺎﺳﺖ و ﻣﺨﺼﻮص زﺑﺎن‬string.h .‫ ﻫﺴﺖ ﻛﻪ ﻧﻤﻲﺷﻮد از آنﻫﺎ ﮔﺬﺷﺖ‬string.h ‫ ﻛﻢ ﻛﺮده اﻣﺎ ﺗﻮاﺑﻌﻲ در‬C++ ‫ را در‬string.h :‫ ﻃﻮل ﻳﻚ رﺷﺘﻪ را ﻣﺸﺨﺺ ﻣﻲﻛﻨﺪ‬strlen() ‫ﺗﺎﺑﻊ‬ #include <conio.h> #include <iostream> using namespace std; #include <string.h> int main() { cout<< strlen("hello"); _getch(); }

Output: 5

:‫ ﻛﺮدن ﻳﻚ رﺷﺘﻪ در رﺷﺘﻪي دﻳﮕﺮ اﺳﺖ‬copy ‫ ﺑﺮاي‬strcpy() ‫ﺗﺎﺑﻊ‬ #include <conio.h> #include <iostream> using namespace std; #include <string.h> int main() { char a[100] = {0}; strcpy(a,"hello"); cout<< a; _getch(); }

Output: hello

:‫ ﺑﺮاي ﻣﻘﺎﻳﺴﻪي دو رﺷﺘﻪ ﺑﻪ ﻛﺎر ﻣﻲرود‬strcmp() ‫ﺗﺎﺑﻊ‬ #include <conio.h> #include <iostream> using namespace std;

369

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <string> int main() { if(strcmp("ab","ac") < 0) cout<<"ab < ac"

"\n";

if(strcmp("hello","bye") > 0) cout<< "hello > bye"

"\n";

if(strcmp("C++","C++") == 0) cout<<"C++ == C++" _getch();

"\n";

}

Output: ab < ac hello > bye C++ == C++

‫ در ﺿﻤﻦ ﺑﻪ ﺟﺎي‬."hello" > "bye" ‫ ﻳﻌﻨﻲ‬strcmp("hello","bye") > 0 ‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ‬ .‫ ﻧﻮﺷﺘﻪام‬string ‫ ﻓﻘﻂ‬string.h :‫ ﺑﺮاي ﭼﺴﺒﺎﻧﺪن دو رﺷﺘﻪ ﺑﻪ ﻛﺎر ﻣﻲرود‬strcat() ‫ﺗﺎﺑﻊ‬ #include <conio.h> #include <iostream> using namespace std; #include <string.h> int main() { char a[100] = "hello"; strcat(a,"bye"); cout<< a; _getch(); }

Output: hellobye

.‫" را دارد‬hello" ‫ ﻛﺎراﻛﺘﺮ دﻳﮕﺮ‬5 ‫ ﺣﺎﻓﻈﻪي ﻻزم ﺑﺮاي‬a ‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ‬

vector

‫ﻫﺎ در ﺣﻘﻴﻘﺖ‬double ‫ از‬vector ‫ ﻳﻚ‬.‫ دارد‬vector ‫ ﻛﻼﺳﻲ ﺑﺎ ﻧﺎم‬- template ‫ ﻫﻢ‬header file ‫اﻳﻦ‬ ‫ﻳﻚ ﭼﻨﺪ ﺗﺎﻳﻲ ﻣﺮﺗﺐ ﺑﻪ ﺷﻜﻞ‬

370

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ (1.1, 1.4, 5, 3.14, 1, 0)

.‫ ﻣﺆﻟﻔﻪ‬6 ‫ اﺳﺖ ﺑﺎ‬vector ‫ ﭼﻨﺪﺗﺎﻳﻲ ﺑﺎﻻ ﻳﻚ‬.‫اﺳﺖ‬ ‫ ﺑﺴﻴﺎري از دﺳﺘﻮرات ﺷﺒﻴﻪ ﺑﻪ ﻛﻼس‬.‫ ﻣﺆﻟﻔﻪ اﻳﺠﺎد ﻣﻲﻛﻨﺪ و ﻣﺆﻟﻔﻪﻫﺎ را ﭼﺎپ ﻣﻲﻛﻨﺪ‬5 ‫ ﺑﺎ‬vector ‫ﻣﺜﺎل زﻳﺮ ﻳﻚ‬ :‫ اﺳﺖ‬map #include <conio.h> #include <iostream> using namespace std; #include <vector> typedef vector<double> typedef Vector::iterator

Vector; Iterator;

int main() { Vector v(5); v[0] = 5.5; v[1] = 4.4; v[2] = 3.3; v[3] = 2.2; v[4] = 1.1; Iterator it; for(it = v.begin(); it != v.end(); it++) cout<< *it << endl; _getch(); }

Output: 5.5 4.4 3.3 2.2 1.1

‫ ﻣﺆﻟﻔﻪﻫﺎ‬it ‫ ﺑﻪ ﻣﺆﻟﻔﻪﻫﺎ ﻣﻘﺪار داده ﺷﺪه و ﺑﺎ اﺳﺘﻔﺎده از‬operator [] ‫ ﺑﺎ‬،‫ ﻣﺆﻟﻔﻪ اﻳﺠﺎد ﺷﺪه‬5 ‫ ﺑﺎ‬vector ‫ﻳﻚ‬ .‫ﭼﺎپ ﺷﺪهاﻧﺪ‬ :‫ اﺿﺎﻓﻪ ﻛﺮد‬vector ‫ ﻣﻲﺷﻮد ﻳﻚ ﻣﺆﻟﻔﻪ را ﺑﻪ ﻳﻚ‬insert ِ method ‫ﺑﺎ اﺳﺘﻔﺎده از‬ #include <conio.h> #include <iostream> using namespace std; #include <vector> typedef vector<int> typedef Vector::iterator

Vector; Iterator;

int main() {

371

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ Vector v[0] = v[1] = v[2] = v[3] = v[4] =

v(5); 10; 20; 30; 40; 50;

Iterator it = v.begin() + 2; v.insert(it, 25); for(it = v.begin(); it != v.end(); it++) cout<< *it << endl; _getch(); }

Output: 10 20 25 30 40 50

:‫ ﺑﻪ اﻳﻦ ﺻﻮرت دارﻳﻢ‬vector ‫در اﻳﻦ ﻣﺜﺎل اول ﻳﻚ‬ (10, 20, 30, 40, 50)

‫ را ﺑﻪ‬25 ‫ ﻋﺪد‬insert() ‫ و‬it ‫ ﺑﺎ اﺳﺘﻔﺎده از‬.‫ را ﻃﻮري ﺗﻨﻈﻴﻢ ﻣﻲﻛﻨﻴﻢ ﻛﻪ ﺑﻪ ﻣﺆﻟﻔﻪي ﺳﻮم اﺷﺎره ﻛﻨﺪ‬it ‫ﺑﻌﺪ‬ .‫ اﺿﺎﻓﻪ ﻣﻲﻛﻨﻴﻢ ﻛﻪ ﻗﺒﻞ از ﻣﺆﻟﻔﻪي ﺳﻮم ﻗﺮار ﻣﻲﮔﻴﺮد‬vector :‫ اﺿﺎﻓﻪ ﻣﻲﻛﻨﺪ‬vector ‫ ﻳﻚ ﻣﺆﻟﻔﻪ ﺑﻪ اﻧﺘﻬﺎي‬push_back() ِ method #include <conio.h> #include <iostream> using namespace std; #include <vector> typedef vector<int> typedef Vector::iterator

Vector; Iterator;

int main() { Vector v(5); v[0] = 10; v[1] = 20; v[2] = 30; v[3] = 40; v[4] = 50; v.push_back(60); Iterator it; for(it = v.begin(); it != v.end(); it++) cout<< *it << endl; _getch();

372

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ }

Output: 10 20 30 40 50 60

ِ vector ‫ اول‬،‫در اﻳﻦ ﻣﺜﺎل‬ (10, 20, 30, 40, 50)

‫ اﺿﺎﻓﻪ ﻣﻲﻛﻨﻴﻢ ﺗﺎ‬vector ‫ را ﺑﻪ ﺗﻪ اﻳﻦ‬60 ،push_back() ‫را دارﻳﻢ و ﺑﺎ‬ (10, 20, 30, 40, 50, 60)

.‫ﺑﻪ دﺳﺖ ﺑﻴﺎﻳﺪ‬ ‫ ﻓﺮم اول ﺗﻨﻬﺎ ﻳﻚ ﻣﺆﻟﻔﻪ را‬.‫ دو ﻓﺮم از آن ﻫﺴﺖ‬.‫ اﺳﺖ‬vector ‫ ﺑﺮاي ﺣﺬف ﻣﺆﻟﻔﻪﻫﺎ از‬erase() ِ method :‫ﺣﺬف ﻣﻲﻛﻨﺪ‬ #include <conio.h> #include <iostream> using namespace std; #include <vector> typedef vector<int> typedef Vector::iterator int main() { Vector v[0] = v[1] = v[2] = v[3] = v[4] =

Vector; Iterator;

v(5); 10; 20; 30; 40; 50;

Iterator it = v.begin() + 2; v.erase(it); for(it = v.begin(); it != v.end(); it++) cout<< *it << endl; _getch(); }

Output: 10 20 40 50

373

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ :‫ را ﻫﻢ زﻣﺎن ﺣﺬف ﻣﻲﻛﻨﺪ‬vector ‫ ﻳﻚ ردﻳﻒ از ﻣﺆﻟﻔﻪﻫﺎي‬erase() ‫ﻓﺮم دوم‬ #include <conio.h> #include <iostream> using namespace std; #include <vector> typedef vector<int> typedef Vector::iterator int main() { Vector v(5); v[0] = 10; v[1] = 20; v[2] = 30; v[3] = 40; v[4] = 50;

Vector; Iterator;

Iterator it1 = v.begin() + 1; Iterator it2 = v.begin() + 4; v.erase(it1,it2); for(Iterator it = v.begin(); it != v.end(); it++) cout<< *it << endl; _getch(); }

Output: 10 50

‫ ﻣﺆﻟﻔﻪﻫﺎي دوم ﺗﺎ ﭼﻬﺎرم را‬erase() .‫ ﺑﻪ ﻣﺆﻟﻔﻪي ﭘﻨﺠﻢ اﺷﺎره دارد‬it2 ‫ ﺑﻪ ﻣﺆﻟﻔﻪي دوم و‬it1 ‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ‬ .‫ﺣﺬف ﻛﺮده‬ :‫ )ﻳﻌﻨﻲ ﺗﻌﺪاد ﻣﺆﻟﻔﻪﻫﺎي آن( را ﻣﺸﺨﺺ ﻛﺮد‬vector ‫ ﻣﻲﺷﻮد ﻃﻮل‬size() ِ method ‫ﺑﺎ‬ #include <conio.h> #include <iostream> using namespace std; #include <vector> typedef vector<char> int main() { Vector v(5); v[0] = 'h'; v[1] = 'e'; v[2] = 'l'; v[3] = 'l'; v[4] = 'o'; cout<< v.size(); _getch(); }

Vector;

374

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪Output:‬‬ ‫‪5‬‬

‫‪fstream.h‬‬

‫ﻧﻤﻲﺧﻮاﻫﻢ ﺧﻴﻠﻲ در ﻣﻮرد ‪ fstream.h‬ﺗﻮﺿﻴﺢ ﺑﺪﻫﻢ‪ .‬ﺗﻨﻬﺎ ﻣﻲﮔﻮﻳﻢ ﭼﻪ ﻃﻮر ﻣﻲﺷﻮد روي ‪hard disk‬‬ ‫ﻛﺎﻣﭙﻴﻮﺗﺮ ﻳﻚ ﻓﺎﻳﻞ اﻳﺠﺎد ﻛﺮد و در آن ﭼﻴﺰي ﻧﻮﺷﺖ ﻳﺎ اﻃﻼﻋﺎت آن را ﺧﻮاﻧﺪ‪ .‬ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻳﻚ ﻓﺎﻳﻞ ﺑﺎ ﻧﺎم‬ ‫‪ blue.txt‬در دراﻳﻮ ‪ C:‬اﻳﺠﺎد ﻣﻲﻛﻨﺪ و در آن ﻣﻲﻧﻮﻳﺴﻴﺪ ”‪: “I’m Blue‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <fstream‬‬ ‫;‪using namespace std‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)"‪ofstream fout("C:\\blue.txt‬‬ ‫;"‪fout<< "I'm Blue‬‬ ‫;)(‪fout.close‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output: empty‬‬

‫دﻗﺖ ﻛﻨﻴﺪ ﻛﻪ ‪ fout‬در اﻳﻦ ﻣﺜﺎل ﻣﺜﻞ ‪ cout‬ﺑﻪ ﻛﺎر رﻓﺘﻪ‪ .‬ﺣﺎﻻ از ﻃﺮﻳﻖ ‪ My Computer‬ﺑﻪ دراﻳﻮ ‪ C :‬ﺑﺮوﻳﺪ‬ ‫و ﻓﺎﻳﻠﻲ ﺑﺎ ﻧﺎم ‪ blue.txt‬را ﭘﻴﺪا ﻛﻨﻴﺪ‪ .‬ﻓﺎﻳﻞ را ﺑﺎز ﻛﻨﻴﺪ ﺗﺎ ﻣﺤﺘﻮﻳﺎت آن را ﺑﺒﻴﻨﻴﺪ‪:‬‬

‫‪375‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ ﻛﻪ در ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ اﻳﺠﺎد ﺷﺪ ﺑﺎز ﺷﻮد و اﻃﻼﻋﺎت آن ﺧﻮاﻧﺪه‬blue.txt ‫ﺣﺎﻻ ﺑﺮﻧﺎﻣﻪي زﻳﺮ را اﺟﺮا ﻛﻨﻴﺪ ﺗﺎ ﻓﺎﻳﻞ‬ :‫ﺑﺸﻮد‬ #include <conio.h> #include <fstream> #include <iostream> using namespace std; int main() { ifstream fin("C:\\blue.txt"); char a[100] = {0}; fin.getline(a,99); fin.close(); cout<< a; _getch(); }

Output: I'm Blue

‫ ﻛﺎراﻛﺘﺮ( ﺑﺨﻮاﻧﺪ‬99 ‫ ﺳﻌﻲ ﻣﻲﻛﻨﺪ ﻛﺎراﻛﺘﺮﻫﺎي ذﺧﻴﺮه ﺷﺪه در ﻓﺎﻳﻞ را )ﺗﺎ ﺣﺪاﻛﺘﺮ‬getline() ‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ‬ .‫ ﺑﺮﻳﺰد‬a ‫و در‬ .‫ﺑﻌﺪا ﺑﻴﺶ ﺗﺮ ﺑﺮاي ﻓﺎﻳﻞﻫﺎ ﺗﻮﺿﻴﺢ ﻣﻲدﻫﻢ‬

math.h

:‫ ﻣﺜﻼ ﺗﺎﺑﻊ ﺗﻮان‬.(

!‫ ﺗﺎﺑﻊﻫﺎي ﻣﺮﺑﻮط ﺑﻪ رﻳﺎﺿﻴﺎت ﻗﺮار دارد )رﻳﺎﺿﻴﺎت؟‬header file ‫در اﻳﻦ‬

#include <conio.h> #include <iostream> using namespace std; #include <math.h> int main() { cout<< pow(2.0,3); _getch(); }

Output: 8

376

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫در اﻳﻦ ﻣﺜﺎل ﻣﺤﺎﺳﺒﻪ و ﭼﺎپ ﺷﺪه‪ .‬اﮔﺮ ﺑﻪ ﺟﺎي ‪ 2.0‬ﺑﻨﻮﻳﺴﻴﻢ ‪ Visual C++ 2005 ،2‬اﻳﺮاد ﻣﻲﮔﻴﺮد‪.‬‬ ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻫﻢ در ‪ Visual C++ 2005‬اﺟﺮا ﻧﻤﻲﺷﻮد‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪#include <math.h‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)(‪cout<< typeid(pow).name‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬ ‫)‪double (*)(double,double‬‬

‫ﺗﺎﺑﻊ )(‪) sin‬ﺳﻴﻨﻮس( ﻫﻢ در ‪ math.h‬ﻫﺴﺖ وﻟﻲ آرﮔﻮﻣﺎن آن ﺑﺎﻳﺪ ﺑﺮ ﺣﺴﺐ رادﻳﺎن ﺑﺎﺷﺪ ﻧﻪ درﺟﻪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <iostream‬‬ ‫;‪using namespace std‬‬ ‫>‪#include <math.h‬‬ ‫;‪const double Pi = 3.1415926535‬‬ ‫)(‪int main‬‬ ‫{‬ ‫;)‪cout<< sin(Pi/4‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output:‬‬ ‫‪0.707107‬‬

‫اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺳﻴﻨﻮس ‪ 45‬درﺟﻪ را ﭼﺎپ ﻛﺮده‪.‬‬

‫‪windows.h‬‬

‫ﻛﺎرﺑﺮد اﺻﻠﻲ اﻳﻦ ‪ header file‬ﺑﺮاي ﺑﺮﻧﺎﻣﻪﻫﺎي وﻳﻨﺪوز اﺳﺖ‪ .‬اﻣﺎ ﭼﻴﺰﻫﺎﻳﻲ زﻳﺎدي در آن ﻫﺴﺖ ﻛﻪ ﻻزم ﻧﻴﺴﺖ‬ ‫ﺣﺘﻤﺎ در ﻳﻚ ‪ Windows Application‬ﺑﻪ ﻛﺎر رود‪ .‬ﺑﻪ ﭼﻨﺪ ﻣﻮرد از آنﻫﺎ اﺷﺎره ﻣﻲﻛﻨﻢ‪ .‬ﺑﺮﻧﺎﻣﻪﻫﺎﻳﻲ ﻛﻪ در‬ ‫اﻳﻦ ﺑﺨﺶ ﻧﻮﺷﺘﻪام ﺗﻨﻬﺎ در ‪ BDS 2006‬آزﻣﺎﻳﺶ ﺷﺪهاﻧﺪ‪.‬‬

‫‪377‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫اﺑﺘﺪا ﺗﺎﺑﻊ )(‪ MessageBox‬را ﻣﻌﺮﻓﻲ ﻣﻲﻛﻨﻢ ﻛﻪ ﻳﻚ ‪ Message Box‬اﻳﺠﺎد ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <windows.h‬‬ ‫)(‪int main‬‬ ‫{‬ ‫"‪MessageBox(0, "This is a message\n‬‬ ‫‪"This is a message box",‬‬ ‫;)‪"This is Caption", MB_OK‬‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬

‫ﺣﺎﻻ ﻣﻲﺧﻮاﻫﻢ در ﻣﻮرد اﻳﺠﺎد ﻓﺎﻳﻞﻫﺎ و ﻛﺎر ﺑﺎ آنﻫﺎ ﺑﻴﺶ ﺗﺮ ﺣﺮف ﺑﺰﻧﻢ‪ windows.h .‬اﺑﺰارﻫﺎﻳﻲ ﻛﺎﻣﻞ و ﻗﻮي‬ ‫ﺑﺮاي ﻛﺎر ﺑﺎ ﻓﺎﻳﻞﻫﺎ روي ﻫﺎرد در اﺧﺘﻴﺎر ﻣﺎ ﻗﺮار ﻣﻲدﻫﺪ‪.‬‬ ‫ﺑﺮاي اﻳﻦ ﻛﻪ اﻃﻼﻋﺎت را روي ﺣﺎﻓﻈﻪي داﺋﻢ ﻛﺎﻣﭙﻴﻮﺗﺮ ذﺧﻴﺮه ﻛﻨﻴﻢ ﺑﺎﻳﺪ ﻳﻚ ﻓﺎﻳﻞ اﻳﺠﺎد ﻛﻨﻴﻢ‪ ،‬ﻓﺎﻳﻞ را ﺑﺎز ﻛﻨﻴﻢ‪،‬‬ ‫اﻃﻼﻋﺎت را در آن ﻗﺮار ﺑﺪﻫﻴﻢ و ﺑﻌﺪ ﻓﺎﻳﻞ را ﺑﺒﻨﺪﻳﻢ‪.‬‬ ‫ﺑﻪ ﻫﺮ ﻓﺎﻳﻞ ﺑﺎز ﻳﻚ ﻋﺪد ﻧﺴﺒﺖ داده ﻣﻲﺷﻮد ﻛﻪ ﺑﻪ آن ‪ handle‬ﻣﻲﮔﻮﻳﻴﻢ‪ .‬ﺑﺎ ﻛﻤﻚ ‪ handle‬ﻣﻲﺗﻮاﻧﻴﻢ ﺑﻪ ﻓﺎﻳﻞ‬ ‫دﺳﺘﺮﺳﻲ داﺷﺘﻪ ﺑﺎﺷﻴﻢ‪ .‬وﻗﺘﻲ ﻳﻚ ﻓﺎﻳﻞ ﺑﺎز اﺳﺖ ﻳﻚ ﻣﻜﺎن ﺟﺎري در آن ﻓﻌﺎل اﺳﺖ‪ .‬ﺑﺮاي اﻳﻦ ﻛﻪ ﺗﺼﻮري از‬ ‫ﻣﻜﺎن ﺟﺎري داﺷﺘﻪ ﺑﺎﺷﻴﺪ ﻳﻚ ﻓﺎﻳﻞ ﺑﺎ ﭘﺴﻮﻧﺪ ‪ .txt‬را در ﻣﺤﻴﻂ وﻳﻨﺪوز ﺑﺎز ﻛﻨﻴﺪ ﻣﻲﺑﻴﻨﻴﺪ ﻛﻪ ﺧﻄﻲ اﻓﻘﻲ )ﻛﻪ‬ ‫‪ caret‬ﻧﺎم دارد( در آن ﭼﺸﻤﻚ ﻣﻲزﻧﺪ‪:‬‬

‫‪378‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬

‫ﻣﻜﺎن ‪ caret‬در واﻗﻊ ﻫﻤﺎن ﻣﻜﺎن ﺟﺎري اﺳﺖ‪ .‬وﻗﺘﻲ ﺑﺎ ‪ keyboard‬ﭼﻴﺰي ﺗﺎﻳﭗ ﻣﻲﻛﻨﻴﺪ ﺣﺮوف در ﻣﻜﺎن ﺟﺎري‬ ‫ﻗﺮار ﻣﻲﮔﻴﺮﻧﺪ‪ .‬وﻗﺘﻲ ﻓﺎﻳﻠﻲ ﺑﺎز ﺑﺎﺷﺪ ﻳﻚ ﻣﻜﺎن ﺟﺎري دارد ﻛﻪ ﻣﻲﺷﻮد آن ﻣﻜﺎن را ﻣﺜﻞ ‪ caret‬ﺟﺎ ﺑﻪ ﺟﺎ ﻛﺮد ﺗﺎ‬ ‫دادهﻫﺎ در ﺟﺎي ﻣﻨﺎﺳﺐ وارد ﺑﺸﻮﻧﺪ‪.‬‬ ‫ﻫﺮ ﻓﺎﻳﻞ ﻳﻚ اﻧﺪازه دارد ﻛﻪ ﺑﺮاﺑﺮ اﺳﺖ ﺑﺎ ﺗﻌﺪاد ﺑﺎﻳﺖﻫﺎﻳﻲ ﻛﻪ در آن ﻧﻮﺷﺘﻪ ﺷﺪه‪.‬‬ ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﻳﻚ ﻓﺎﻳﻞ ﺑﺎ ﻧﺎم ‪ hello.txt‬در آدرس \‪ C:‬درﺳﺖ ﻣﻲﻛﻨﺪ و آن را ﺑﺎز ﻣﻲﻛﻨﺪ و در آن ﻣﻲﻧﻮﻳﺴﺪ‬ ‫”‪.“Glad to meet you‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <windows.h‬‬ ‫)(‪int main‬‬ ‫{‬ ‫= ‪HANDLE han‬‬ ‫(‪CreateFile‬‬ ‫"‪"C:\\hello.txt‬‬ ‫‪,‬‬ ‫‪FILE_ALL_ACCESS‬‬ ‫‪,‬‬ ‫‪FILE_SHARE_WRITE | FILE_SHARE_READ,‬‬ ‫‪0‬‬ ‫‪,‬‬ ‫‪OPEN_ALWAYS‬‬ ‫‪,‬‬ ‫‪FILE_ATTRIBUTE_NORMAL‬‬ ‫‪,‬‬ ‫‪0‬‬ ‫;)‬ ‫;"‪char a[] = "Glad to meet you‬‬ ‫;)‪unsigned len = strlen(a‬‬ ‫;‪unsigned long data_actually_wrote‬‬ ‫(‪WriteFile‬‬ ‫‪han,‬‬ ‫‪a,‬‬ ‫‪len,‬‬ ‫‪&data_actually_wrote,‬‬

‫‪379‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪0‬‬ ‫;)‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006): empty‬‬

‫ﺑﻌﺪ از اﺟﺮاي ﺑﺮﻧﺎﻣﻪ ﺑﻪ \‪ C:‬ﺳﺮي ﺑﺰﻧﻴﺪ و ‪ hello.txt‬را ﺑﺎز ﻛﻨﻴﺪ‪:‬‬

‫ﺑﺎ ﺗﺎﺑﻊ )(‪ CreateFile‬ﻣﻲﺷﻮد ﻓﺎﻳﻞ ﺟﺪﻳﺪي اﻳﺠﺎد ﻛﺮد ﻳﺎ ﻓﺎﻳﻠﻲ را ﻛﻪ از ﻗﺒﻞ ﻣﻮﺟﻮد اﺳﺖ ﺑﺎز ﻛﺮد‪ .‬اﺻﻼ از‬ ‫ﺷﻜﻞ ﻛﺎرﺑﺮد آن در ﺑﺮﻧﺎﻣﻪ ﻧﺘﺮﺳﻴﺪ ﺗﻨﻬﺎ ﭼﻴﺰﻫﺎﻳﻲ ﻛﻪ ﺑﺎ آنﻫﺎ ﻛﺎر دارﻳﻢ ﺧﺮوﺟﻲ و آرﮔﻮﻣﺎن اول اﻳﻦ ﺗﺎﺑﻊ ﻫﺴﺘﻨﺪ‪.‬‬ ‫ﺧﺮوﺟﻲ‪handle ،‬ي ﺑﻪ ﻓﺎﻳﻞ ﺑﺎز ﺷﺪه ﻣﻲدﻫﺪ و آرﮔﻮﻣﺎن اول در واﻗﻊ آدرس و اﺳﻢ ﻓﺎﻳﻞ ﺑﻪ ﺻﻮرت ﻳﻚ رﺷﺘﻪ‬ ‫اﺳﺖ‪ .‬ﺑﻘﻴﻪي آرﮔﻮﻣﺎنﻫﺎ را ﺑﻪ ﻫﻤﻴﻦ ﺻﻮرت ﺑﻪ ﻛﺎر ﺑﺒﺮﻳﺪ‪ .‬اﻳﻦ آرﮔﻮﻣﺎنﻫﺎي اﺿﺎﻓﻪ در واﻗﻊ ﺗﻨﻈﻴﻤﺎت و وﻳﮋﮔﻲ‪-‬‬ ‫ﻫﺎي ﻓﺎﻳﻞ ﺑﺎز ﺷﺪه را ﻣﺸﺨﺺ ﻣﻲﻛﻨﻨﺪ‪ .‬در اﻳﻦ ﺑﺮﻧﺎﻣﻪ اﻳﻦ آرﮔﻮﻣﺎن ﻃﻮري ﻧﻮﺷﺘﻪ ﺷﺪهاﻧﺪ ﻛﻪ ﻓﺎﻳﻞ را ﺑﺮاي ﺧﻮاﻧﺪن‬ ‫و ﻧﻮﺷﺘﻦ آﻣﺎده ﻛﻨﻨﺪ‪ .‬در ﺿﻤﻦ اﻳﻦ ﺗﻨﻈﻴﻤﺎت ﺑﻪ ﮔﻮﻧﻪاي ﻫﺴﺘﻨﺪ ﻛﻪ اﮔﺮ ﻓﺎﻳﻞ ﻣﻮﺟﻮد ﻧﺒﺎﺷﺪ‪ ،‬اﻳﺠﺎد ﺑﺸﻮد و اﮔﺮ‬ ‫ﻣﻮﺟﻮد ﺑﺎﺷﺪ ﻓﻘﻂ ﺑﺎز ﺷﻮد ﺑﺪون اﻳﻦ ﻛﻪ اﻃﻼﻋﺎﺗﺶ از ﺑﻴﻦ ﺑﺮود‪.‬‬ ‫ﺑﻌﺪ از اﺟﺮاي )(‪ CreateFile‬ﻳﻚ ﻓﺎﻳﻞ ﺑﺎز دارﻳﻢ ﻛﻪ ‪ handle ،han‬آن اﺳﺖ‪ .‬ﭼﻮن ﻓﺎﻳﻞ‪ ،‬ﺗﺎزه ﺑﺎز ﺷﺪه‬ ‫ﻣﻜﺎن ﺟﺎري آن اﺑﺘﺪاي ﻓﺎﻳﻞ اﺳﺖ )ﺑﻪ ﻋﺒﺎرت دﻳﮕﺮ ﻣﻜﺎن ﺟﺎري ﺻﻔﺮ اﺳﺖ(‪ .‬ﺑﺎ ﺗﺎﺑﻊ )(‪ WriteFile‬ﻣﻲﺷﻮد‬ ‫در ﻣﻜﺎن ﺟﺎري اﻃﻼﻋﺎت را وارد ﻛﺮد‪ .‬ﻓﻘﻂ ﺑﺎ ﺳﻪ ﭘﺎراﻣﺘﺮ اول اﻳﻦ ﺗﺎﺑﻊ ﻛﺎر دارﻳﻢ دو ﭘﺎراﻣﺘﺮ آﺧﺮ را ﻫﻤﻴﺸﻪ ﺑﻪ‬ ‫ﻫﻤﻴﻦ ﺷﻜﻞ ﺑﻨﻮﻳﺴﻴﺪ‪ .‬آرﮔﻮﻣﺎن اول )(‪ han ،WriteFile‬اﺳﺖ‪ .‬اﻳﻦ آرﮔﻮﻣﺎن ﻣﺸﺨﺺ ﻣﻲﻛﻨﺪ ﻛﻪ‬ ‫)(‪ WriteFile‬ﺑﺎﻳﺪ در ﻛﺪام ﻓﺎﻳﻞ ِ ﺑﺎز اﻃﻼﻋﺎت را وارد ﻛﻨﺪ‪ .‬آرﮔﻮﻣﺎن دوم ﻳﻚ ‪ pointer‬ﺑﻪ اﻃﻼﻋﺎﺗﻲ اﺳﺖ‬ ‫ﻛﻪ ﺑﺎﻳﺪ وارد ﻓﺎﻳﻞ ﺑﺸﻮﻧﺪ‪ .‬در اﻳﻦ ﺟﺎ ‪ a‬ﺑﻪ دﺳﺘﻪاي از ﺑﺎﻳﺖﻫﺎ اﺷﺎره دارد‪ .‬اﻳﻦ اﺻﻼ ﻣﻬﻢ ﻧﻴﺴﺖ ﻛﻪ اﻳﻦ ﺑﺎﻳﺖﻫﺎ ﻳﻚ‬

‫‪380‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ آرﮔﻮﻣﺎن ﺳﻮم ﺗﻌﺪاد ﺑﺎﻳﺖﻫﺎﻳﻲ‬.‫رﺷﺘﻪ ﺗﺸﻜﻴﻞ ﻣﻲدﻫﻨﺪ ﺗﻨﻬﺎ ﭼﻴﺰ ﻣﻬﻢ ﺻﻔﺮ و ﻳﻚﻫﺎي ﻫﺮ ﺑﺎﻳﺖ و ﺗﻌﺪاد ﺑﺎﻳﺖﻫﺎﺳﺖ‬ .‫ﻛﻪ ﺑﺎﻳﺪ ﺑﻪ ﻓﺎﻳﻞ وارد ﺑﺸﻮﻧﺪ ﻣﺸﺨﺺ ﻣﻲﻛﻨﺪ‬ ‫ﺣﺎﻻ ﺑﺮﻧﺎﻣﻪاي ﻣﻲﻧﻮﻳﺴﻴﻢ ﻛﻪ ﻓﺎﻳﻠﻲ را ﻛﻪ در ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ اﻳﺠﺎد ﺷﺪ ﺑﺎز ﻛﻨﺪ و اﻃﻼﻋﺎت ﺛﺒﺖ ﺷﺪه در ﻓﺎﻳﻞ را‬ ‫“ ﺗﺒﺪﻳﻞ ﺷﻮد )آوردهاﻧﺪ ﻛﻪ ﮔﺮﺑﻪاي‬Glad to eat you” ‫ﻃﻮري ﺗﻐﻴﻴﺮ دﻫﺪ ﻛﻪ ﻣﺘﻦ ﻧﻮﺷﺘﻪ ﺷﺪه در آن ﺑﻪ‬ :(

glad to eat you ‫ ﻣﻮﺷﻲ را ﻣﻲﺑﻴﻨﻴﺪ و ﺑﻪ او ﻣﻲﮔﻮﻳﺪ‬،‫اﻧﮕﻴﺴﻲ زﺑﺎن‬

#include <conio.h> #include <windows.h> unsigned __int64 MySetFilePointer ( HANDLE han, const unsigned __int64& position, unsigned long from_where = FILE_BEGIN ) { LARGE_INTEGER large_integer; large_integer.QuadPart = position; large_integer.LowPart = SetFilePointer( han , large_integer.LowPart , &large_integer.HighPart, from_where ); return large_integer.QuadPart; } int main() { HANDLE han = CreateFile( "C:\\hello.txt" , FILE_ALL_ACCESS , FILE_SHARE_WRITE | FILE_SHARE_READ, 0 , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , 0 ); char a[] ="eat you "; unsigned len = strlen(a); MySetFilePointer(han,8);// where the action is unsigned long data_actually_wrote; WriteFile( han, a,

381

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫‪len,‬‬ ‫‪&data_actually_wrote,‬‬ ‫‪0‬‬ ‫;)‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006): empty‬‬

‫ﺣﺎﻻ ‪ C:\hello.txt‬را )ﺑﺎ ‪ (Notepad‬ﺑﺎز ﻛﻨﻴﺪ ﺗﺎ ﺗﻐﻴﻴﺮات را ﺑﺒﻴﻨﻴﺪ‪:‬‬

‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺗﺎﺑﻌﻲ ﺑﻪ ﻧﺎم )(‪ MySetFilePointer‬ﺗﻌﺮﻳﻒ ﻛﺮدهام‪ .‬ﻛﺎر آن ﺗﻐﻴﻴﺮ ﻣﻜﺎن ﺟﺎري در ﻳﻚ‬ ‫ﻓﺎﻳﻞ ﺑﺎز اﺳﺖ‪ ِ handle .‬ﻓﺎﻳﻞ ﺑﺎز ﺑﻪ ﻋﻨﻮان آرﮔﻮﻣﺎن اول داده ﻣﻲﺷﻮد‪ .‬ﻧﻴﺎزي ﺑﻪ اﻳﻦ ﻛﻪ ﺑﺪاﻧﻴﻢ اﻳﻦ ﺗﺎﺑﻊ ﭼﻪ ﻃﻮر‬ ‫ﺗﻌﺮﻳﻒ ﺷﺪه ﻧﺪارﻳﻢ‪ .‬اﻳﻦ ﺗﺎﺑﻊ را ﺑﺎ ﻫﻤﻴﻦ ﺗﻌﺮﻳﻒ در ﺑﺮﻧﺎﻣﻪﻫﺎي ﺧﻮدﺗﺎن ﺑﻪ ﻛﺎر ﺑﺒﺮﺑﺪ‪ .‬در ﺣﻘﻴﻘﺖ ﭼﻮن ‪__int64‬‬

‫)ﻛﻪ ﻳﻚ ﻋﺪد ﺻﺤﻴﺢ ﺑﺎ ‪ 64‬ﺑﺎﻳﺖ ﺣﺎﻓﻈﻪ اﺳﺖ( ﻳﻚ ﻧﻮع اﺳﺘﺎﻧﺪارد ﻧﻴﺴﺖ‪ ،‬ﺗﺎﺑﻊﻫﺎي اﺳﺘﺎﻧﺪارد از آن اﺳﺘﻔﺎده ﻧﻤﻲ‪-‬‬ ‫ﻛﻨﻨﺪ‪ .‬اﻣﺎ ﻓﺎﻳﻞﻫﺎي اﻣﺮوزي ﺧﻴﻠﻲ ﺣﺠﻴﻢ ﻫﺴﺘﻨﺪ و ‪ long‬ﻇﺮﻓﻴﺖ ﻻزم ﺑﺮاي اﺷﺎره ﺑﻪ اﻧﺪازهي آنﻫﺎ را ﻧﺪارد‪ .‬ﺑﻪ‬ ‫ﻧﺎﭼﺎر ﺗﺎﺑﻊ اﺳﺘﺎﻧﺪارد )(‪ SetFilePointer‬ﺑﺮاي اﺷﺎره ﺑﻪ ﻣﻜﺎن ﺧﺎﺻﻲ از ﻓﺎﻳﻞ‪ ،‬دو ﭘﺎراﻣﺘﺮ دارد ﻛﻪ ﺗﺮﻛﻴﺐ‬ ‫آنﻫﺎ ﻣﻜﺎن ﺧﺎﺻﻲ از ﻓﺎﻳﻞ را ﻧﺸﺎن ﻣﻲدﻫﺪ‪ .‬ﺗﺎﺑﻌﻲ ﻛﻪ ﻣﻦ ﻧﻮﺷﺘﻪام ﻛﺎر را ﺳﺎده ﻣﻲﻛﻨﺪ و ﻳﻚ ﭘﺎراﻣﺘﺮ ‪ 64‬ﺑﺎﻳﺘﻲ را‬ ‫ﺑﺮاي اﺷﺎره ﺑﻪ ﻣﻜﺎنﻫﺎي ﻳﻚ ﻓﺎﻳﻞ ﺑﻪ ﻛﺎر ﻣﻲﺑﺮد‪.‬‬ ‫در ﺗﺎﺑﻊ )(‪ main‬اول ﻓﺎﻳﻞ ‪ hello.txt‬را ﺑﺎز ﻛﺮدهام ﻛﻪ ﻫﻤﺎن اﻃﻼﻋﺎﺗﻲ را دارد ﻛﻪ در ﺑﺮﻧﺎﻣﻪي ﻗﺒﻞ ﺑﻪ آن وارد‬ ‫ﻛﺮدﻳﻢ‪ .‬وﻗﺘﻲ ﻓﺎﻳﻞ ﺑﺎز ﻣﻲﺷﻮد ﻣﻜﺎن ﺟﺎري ﺻﻔﺮ اﺳﺖ )ﻳﻌﻨﻲ اﺑﺘﺪاي ﻓﺎﻳﻞ اﺳﺖ(‪ .‬از‬ ‫)(‪ MySetFilePointer‬اﺳﺘﻔﺎده ﻛﺮدهام ﺗﺎ ﻣﻜﺎن ﺟﺎري را ‪ 8‬ﻛﻨﻢ )ﻳﻌﻨﻲ ﻗﺒﻞ از ”‪ (“meet you‬ﺑﻌﺪ ﺑﺎ‬ ‫اﺳﺘﻔﺎده از ﺗﺎﺑﻊ )(‪ WriteFile‬ﻣﺜﻞ ﻗﺒﻞ اﻃﻼﻋﺎت ‪ a‬را )ﻳﻌﻨﻲ "‪ "eat you‬را( در ﻣﻜﺎن ﺟﺎري ﻧﻮﺷﺘﻢ‪.‬‬ ‫ﺗﻮﺟﻪ ﻛﻨﻴﺪ ﻛﻪ اﻃﻼﻋﺎت ﺟﺪﻳﺪ اﻃﻼﻋﺎت ﻗﺒﻠﻲ را ﭘﺎك ﻣﻲﻛﻨﺪ و ﺑﻪ ﺟﺎي آنﻫﺎ ﻗﺮار ﻣﻲﮔﻴﺮد‪.‬‬ ‫ﺑﺮﻧﺎﻣﻪي زﻳﺮ اﻃﻼﻋﺎت را از ﻓﺎﻳﻠﻲ ﻛﻪ در ﺑﺮﻧﺎﻣﻪﻫﺎي ﻗﺒﻠﻲ ﺳﺎﺧﺘﻪ ﺷﺪ ﻣﻲﺧﻮاﻧﺪ و ﭼﺎپ ﻣﻲﻛﻨﺪ‪:‬‬ ‫>‪#include <conio.h‬‬

‫‪382‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ #include <windows.h> #include <iostream> using namespace std; unsigned __int64 MyGetFileSize(HANDLE han) { LARGE_INTEGER large_integer; large_integer.LowPart = GetFileSize(han,(LPDWORD) &large_integer.HighPart); return large_integer.QuadPart; } int main() { HANDLE han = CreateFile( "C:\\hello.txt" , FILE_ALL_ACCESS , FILE_SHARE_WRITE | FILE_SHARE_READ, 0 , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , 0 ); unsigned size = MyGetFileSize(han); char* c = new char [size+1]; unsigned long number_of_bytes_read; ReadFile( han, c, size, &number_of_bytes_read, 0 ); c[size] = 0; cout<< c; _getch(); }

Output (BDS 2006): Glad to eat you

‫ ﻛﻪ ﺧﻮد ﻣﺎ آن را ﻧﻮﺷﺘﻪاﻳﻢ‬MyGetFileSize() ‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ اول ﻓﺎﻳﻞ ﺑﺎز ﻣﻲﺷﻮد و ﺑﻌﺪ ﺑﺎ اﺳﺘﻔﺎده از ﺗﺎﺑﻊ‬ heap ‫ ﺑﺎﻳﺖ ﺣﺎﻓﻈﻪ از‬size+1 ‫ ﺑﻌﺪ ﺑﻪ اﻧﺪازهي‬.‫ ذﺧﻴﺮه ﻣﻲﺷﻮد‬size ‫اﻧﺪازهي ﻓﺎﻳﻞ ﻣﺸﺨﺺ ﻣﻲﺷﻮد و در‬ ‫ ﺗﺎﺑﻊ‬.‫ ﻣﻜﺎن ﺟﺎري در ﺻﻔﺮ )اول ﻓﺎﻳﻞ( ﻗﺮار دارد‬.‫ ﻣﻲﮔﻴﺮﻳﻢ‬c ‫درﻳﺎﻓﺖ ﻣﻲﻛﻨﻴﻢ و اﺷﺎره ﮔﺮ آن را‬ c ‫ ﺑﺎﻳﺖ از ﻓﺎﻳﻞ )ﻳﻌﻨﻲ ﻫﻤﻪي اﻃﻼﻋﺎت ﻓﺎﻳﻞ( را در ﺣﺎﻓﻈﻪاي ﻗﺮار ﻣﻲدﻫﺪ ﻛﻪ‬size ‫ ﺑﻪ اﻧﺪازه‬ReadFile() c[size] ‫ ﻳﻚ رﺷﺘﻪ ﺑﺎﺷﺪ ﻛﺎراﻛﺘﺮ آﺧﺮ آن ﺑﺎﻳﺪ ﺻﻔﺮ ﺑﺎﺷﺪ ﺑﺮاي ﻫﻤﻴﻦ‬c ‫ ﭼﻮن ﻗﺮار اﺳﺖ‬.‫ﺑﻪ آن اﺷﺎره ﻣﻲﻛﻨﺪ‬

.‫ را ﭼﺎپ ﻣﻲﻛﻨﻴﻢ‬c ‫را ﺻﻔﺮ ﻣﻲﻛﻨﻴﻢ و ﺑﻌﺪ‬

383

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ اﻧﺪازهي آن را ﺗﻐﻴﻴﺮ‬،‫ ﻫﻨﮕﺎم ﻧﻮﺷﺘﻦ در ﻓﺎﻳﻞ‬WriteFile() ‫ دﻳﺪﻳﻢ ﻛﻪ‬.‫ﻣﺴﺄﻟﻪي ﺑﻌﺪ ﺗﻐﻴﻴﺮ اﻧﺪازهي ﻓﺎﻳﻞ اﺳﺖ‬ :‫ در ﺑﺮﻧﺎﻣﻪي زﻳﺮ ﺗﺎﺑﻌﻲ ﻛﺎﻣﻞ ﺗﺮ ﺑﺮاي ﺗﻐﻴﻴﺮ اﻧﺪازهي ﻓﺎﻳﻞ ﻣﻌﺮﻓﻲ ﻛﺮدهام‬.‫ﻣﻲدﻫﺪ‬ #include <conio.h> #include <windows.h> unsigned __int64 MySetFilePointer ( HANDLE han, const unsigned __int64& position, unsigned long from_where = FILE_BEGIN ) { LARGE_INTEGER large_integer; large_integer.QuadPart = position; large_integer.LowPart = SetFilePointer( han , large_integer.LowPart , &large_integer.HighPart, from_where ); return large_integer.QuadPart; } void MySetFileSize( HANDLE han, unsigned __int64 end_of_file, unsigned long from_where = FILE_BEGIN) { MySetFilePointer(han, end_of_file, from_where); SetEndOfFile(han); } int main() { HANDLE han = CreateFile( "C:\\hello.txt" , FILE_ALL_ACCESS , FILE_SHARE_WRITE | FILE_SHARE_READ, 0 , OPEN_ALWAYS , FILE_ATTRIBUTE_NORMAL , 0 ); MySetFileSize(han, 100000); _getch(); }

Output (BDS 2006): empty

384

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﺗﺎﺑﻊ )(‪ MySetFilePointer‬ﻫﻤﺎن اﺳﺖ ﻛﻪ در ﺑﺮﻧﺎﻣﻪﻫﺎي ﻗﺒﻞ ﻣﻌﺮﻓﻲ ﻛﺮدم‪ .‬در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺗﻨﻬﺎ در ﺗﻌﺮﻳﻒ‬ ‫ﺗﺎﺑﻊ )(‪ MySetFileSize‬ﺑﻪ ﻛﺎر رﻓﺘﻪ‪ .‬ﻛﺎر‬ ‫)(‪ MySetFileSize‬ﺗﻐﻴﻴﺮ اﻧﺪازهي ﻳﻚ ﻓﺎﻳﻞ اﺳﺖ‪.‬‬ ‫در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﻓﺎﻳﻞ ‪ C:\hello.txt‬را ﺑﺎز ﻛﺮدهاﻳﻢ و ﺑﻌﺪ‬ ‫اﻧﺪازهي آن را ‪ 100000‬ﺑﺎﻳﺖ ﻗﺮار دادهاﻳﻢ‪.‬‬ ‫ﺑﺮاي اﻳﻦ ﻛﻪ ﻣﻄﻤﺌﻦ ﺑﺎﺷﻴﺪ اﻧﺪازهي ﻓﺎﻳﻞ ﻫﻤﻴﻦ اﺳﺖ ﺑﻪ‬ ‫دراﻳﻮ ‪ C:‬ﺑﺮوﻳﺪ‪ ،‬روي ‪ hello.txt‬ﻛﻠﻴﻚ راﺳﺖ ﻛﻨﻴﺪ و‬ ‫‪ Properties‬را اﻧﺘﺨﺎب ﻛﻨﻴﺪ‪:‬‬

‫ﺗﺎ ﭘﻨﺠﺮهي زﻳﺮ ﺑﺎز ﺷﻮد‪:‬‬

‫‪385‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫اﮔﺮ ﻫﻨﮕﺎم ﺑﺎز ﻛﺮدن ﻳﻚ ﻓﺎﻳﻞ ﺑﺎ )(‪ CreateFile‬در آرﮔﻮﻣﺎن اول ﺑﻪ ﺟﺎي آدرس و اﺳﻢ ﻓﺎﻳﻞ ﻓﻘﻂ اﺳﻢ آن‬ ‫را ﺑﻨﻮﻳﺴﻴﻢ ﻓﺎﻳﻞ در ﻣﺤﻞ ﺟﺎري اﻳﺠﺎد ﻣﻲﺷﻮد ﻛﻪ ﻣﻌﻤﻮﻻ ﻫﻤﺎن ﺟﺎﻳﻲ اﺳﺖ ﻛﻪ ﻓﺎﻳﻞ ‪.exe‬ي ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ در آن‬ ‫ﻗﺮار دارد‪ .‬اﻳﻦ ﺑﺮﻧﺎﻣﻪ زﻳﺮ اﺟﺮا ﻛﻨﻴﺪ‪:‬‬ ‫>‪#include <conio.h‬‬ ‫>‪#include <windows.h‬‬ ‫)(‪int main‬‬ ‫{‬ ‫(‪CreateFile‬‬ ‫"‪"hello.txt‬‬ ‫‪,‬‬ ‫‪FILE_ALL_ACCESS‬‬ ‫‪,‬‬ ‫‪FILE_SHARE_WRITE | FILE_SHARE_READ,‬‬ ‫‪0‬‬ ‫‪,‬‬ ‫‪OPEN_ALWAYS‬‬ ‫‪,‬‬ ‫‪FILE_ATTRIBUTE_NORMAL‬‬ ‫‪,‬‬ ‫‪0‬‬ ‫;)‬ ‫;)(‪_getch‬‬ ‫}‬

‫‪Output (BDS 2006): empty‬‬

‫ﺣﺎل ﺑﻪ ﻣﺤﻠﻲ ﻛﻪ ﻓﺎﻳﻞ اﺟﺮاﻳﻲ )ﻳﻌﻨﻲ ﻓﺎﻳﻞ ‪.exe‬ي( ﺑﺮﻧﺎﻣﻪي ﺷﻤﺎ اﻳﺠﺎد ﺷﺪه ﺑﺮوﻳﺪ و ﻓﺎﻳﻞ ‪ hello.txt‬را ﭘﻴﺪا‬ ‫ﻛﻨﻴﺪ‪:‬‬

‫ﺑﺮاي ﺑﺴﺘﻦ ﻳﻚ ﻓﺎﻳﻞ ﺑﺎز ﺑﺎ ‪ han ِ handle‬ﺑﺎﻳﺪ ﻧﻮﺷﺖ‪:‬‬ ‫;)‪CloseHandle(han‬‬

‫‪386‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ .‫در واﻗﻊ در آﺧﺮ ﻫﻤﻪي ﺑﺮﻧﺎﻣﻪي ﻗﺒﻠﻲ ﻛﻪ ﻳﻚ ﻓﺎﻳﻞ ﺑﺎز ﺷﺪه ﺑﻬﺘﺮ اﺳﺖ ﻓﺎﻳﻞ را ﺑﺒﻨﻴﺪم‬ ‫ ﻳﻚ ﺑﺮﻧﺎﻣﻪي ﺑﺴﻴﺎر ﺳﺎدهي وﻳﻨﺪوز را ﺑﻪ ﺷﻤﺎ ﻣﻌﺮﻓﻲ ﻣﻲﻛﻨﻢ ﺗﺎ ﺷﺮوع ﻛﺎر ﺷﻤﺎ ﺑﺎ ﺑﺮﻧﺎﻣﻪ ﻧﻮﻳﺴﻲ وﻳﻨﺪوز‬،‫در ﭘﺎﻳﺎن‬ :‫ اﻳﺠﺎد ﺷﻮد‬project ‫ ﻣﺴﻴﺮ زﻳﺮ را ﻃﻲ ﻛﻨﻴﺪ ﺗﺎ ﻳﻚ‬BDS 2006 ‫ در‬.‫ﺑﺎﺷﺪ‬ File | New | Other… | C++Builder Projects | Console Application :‫ ﺗﻨﻈﻴﻤﺎت را ﻃﻮري ﺗﻐﻴﻴﺮ دﻫﻴﺪ ﻛﻪ ﻣﺜﻞ ﺷﻜﻞ زﻳﺮ ﺷﻮد‬.‫ﭘﻨﺤﺮهاي ﺑﺎز ﻣﻲﺷﻮد‬

.‫ را ﻓﺸﺎر دﻫﻴﺪ‬OK :‫ ﺑﻪ وﺟﻮد آﻣﺪه ﺑﻨﻮﻳﺴﻴﺪ و اﺟﺮا ﻛﻨﻴﺪ‬project ‫ﺑﺮﻧﺎﻣﻪ زﻳﺮ را در‬ #include <windows.h> long WINAPI WindowProcedure(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { HDC hdc = GetDC(hwnd); switch(uMsg) { case WM_MOUSEMOVE: LineTo(hdc,LOWORD(lParam),HIWORD(lParam)); return 0; case WM_DESTROY: PostQuitMessage(0); return 0; } return DefWindowProc(hwnd, uMsg, wParam, lParam); } class hkNormalWindow { public: HINSTANCE LPSTR int HWND

hi; lpCmd; nCmd; hwnd;

// provided in WinMain() // provided in WinMain() // the handle of window created

387

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ //in MakeWindow() below // procedure used by window

WNDPROC Proc; char *className; WNDCLASSEX wcx; int menuID; int smallIconID;

// window class name // window class to be registered //in RegisterClass() below // ID of a menu in resource // ID of an icon in resource

hkNormalWindow(WNDPROC WndProc);// constructor gets the procedure bool RegisterClass(); // fills & registers wcx bool MakeWindow(); // creates a window using wcx bool Run(

//gets WinMain & other information HINSTANCE hinstance, // provided in WinMain() LPSTR lpCmdLine, // provided in WinMain() int nCmdShow, // provided in WinMain() int menu_id_in_resource=101, // ID of a menu

//in resource int small_icon_id_in_resource=100 // ID of an icon in //resource ); //hPrevInstance is not needed because its always 0 }; hkNormalWindow::hkNormalWindow(WNDPROC WndProc) :className("hkClass"),Proc(WndProc)//constructor {} bool hkNormalWindow::RegisterClass() { wcx.cbSize = sizeof(wcx); // size of structure wcx.style = CS_HREDRAW | CS_VREDRAW; // redraw if size changes wcx.lpfnWndProc = Proc; // points to window procedure wcx.cbClsExtra = 0; // no extra class memory wcx.cbWndExtra = 0; // no extra window memory wcx.hInstance = hi; // handle to instance wcx.hIcon =0; //default wcx.hCursor = LoadCursor(NULL,IDC_ARROW); // predefined arrow wcx.hbrBackground =(HBRUSH)GetStockObject(WHITE_BRUSH); // white background brush wcx.lpszMenuName = MAKEINTRESOURCE(menuID); // name of menu resource wcx.lpszClassName = className; // name of window class wcx.hIconSm =(HICON)LoadImage( // small class icon hi, MAKEINTRESOURCE(smallIconID), IMAGE_ICON, GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR ); return RegisterClassEx(&wcx); } bool hkNormalWindow::MakeWindow()

388

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ { hwnd = CreateWindowEx(

); if (!hwnd) return false; ShowWindow(hwnd,nCmd); UpdateWindow(hwnd); return true;

WS_EX_WINDOWEDGE|WS_EX_CLIENTEDGE, className, // name of window class "Sample", // title-bar string WS_OVERLAPPEDWINDOW, // top-level window CW_USEDEFAULT, // default horizontal position CW_USEDEFAULT, // default vertical position CW_USEDEFAULT, // default width CW_USEDEFAULT, // default height (HWND) NULL, // no owner window (HMENU) NULL, // use class menu hi, // handle to application instance (LPVOID) NULL // no window-creation data

} bool hkNormalWindow::Run( HINSTANCE hinstance, LPSTR lpCmdLine, int nCmdShow, int menu_id_in_resource, int small_icon_id_in_resource ) { hi = hinstance ; lpCmd = lpCmdLine ; nCmd = nCmdShow ; menuID= menu_id_in_resource; smallIconID=small_icon_id_in_resource; if(RegisterClass()==false) return false; if(MakeWindow()==false) return false; return true; } MSG hkLoop() //message loop { MSG msg; bool bRet; while( (bRet = GetMessage( &msg, NULL, 0, 0 )) != 0) { if(bRet == -1) MessageBox(GetDesktopWindow(), "An error in receiving messages","Error",MB_OK); else { TranslateMessage(&msg); DispatchMessage(&msg);

389

www.pupuol.com


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫}‬ ‫}‬ ‫;‪return msg‬‬ ‫}‬ ‫‪#pragma argsused‬‬ ‫‪int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hPrevInstance,‬‬ ‫)‪LPSTR lpCmdLine, int nCmdShow‬‬ ‫{‬ ‫;)‪hkNormalWindow MyWindow(WindowProcedure‬‬ ‫;)‪MyWindow.Run(hinstance,lpCmdLine,nCmdShow‬‬ ‫;‪return hkLoop().wParam‬‬ ‫}‬

‫‪Output (BDS 2006):‬‬

‫ﻣﻬﻢ ﺗﺮﻳﻦ ﺑﺨﺶ در اﻳﻦ ﺑﺮﻧﺎﻣﻪ ﺗﺎﺑﻊ )(‪ WindowProcedure‬اﺳﺖ‪ .‬ﺑﺎ ﻛﻠﻴﻚ ﻛﺮدن ﻣﺎوس روي ﭘﻨﺠﺮهي‬ ‫ﺑﺮﻧﺎﻣﻪ‪ ،‬ﺣﺮﻛﺖ ﻣﺎوس روي آن‪ ،‬ﻓﺸﺎر ﻛﻠﻴﺪﻫﺎي ﺻﻔﺤﻪ ﻛﻠﻴﺪ ﻳﺎ‪ ...‬ﻳﻚ ﭘﻴﺎم )‪ (message‬ﺑﻪ ﺗﺎﺑﻊ‬ ‫)(‪ WindowProcedure‬ﻓﺮﺳﺘﺎده ﻣﻲﺷﻮد‪ .‬اﻳﻦ ﭘﻴﺎم ﺣﺎوي اﻃﻼﻋﺎت ﺧﺎﺻﻲ اﺳﺖ‪ .‬ﻣﺜﻼ اﮔﺮ ﻣﺎوس ﺣﺮﻛﺖ‬ ‫ﻛﻨﺪ اﻃﻼﻋﺎت ﻣﺮﺑﻮط ﺑﻪ ﻣﻜﺎن ﻣﺎوس ﺟﺰﺋﻲ از ﭘﻴﺎم اﺳﺖ‪ WindowProcedure() .‬ﺑﺎﻳﺪ ﺑﺎ ﺗﻮﺟﻪ ﺑﻪ ﻧﻮع و‬ ‫اﻃﻼﻋﺎت ﭘﻴﺎم ﻛﺎرﻫﺎﻳﻲ را اﻧﺠﺎم ﺑﺪﻫﺪ‪ .‬در اﻳﻦ ﺑﺮﻧﺎﻣﻪ وﻗﺘﻲ ﭘﻴﺎم ﺣﺮﻛﺖ ﻣﺎوس ﻣﻲرﺳﺪ‪،‬‬ ‫)(‪ WindowProcedure‬ﺧﻄﻲ از ﮔﻮﺷﻪي ﭘﻨﺠﺮه ﺑﻪ ﻣﺤﻞ ﻓﻌﻠﻲ ﻣﺎوس رﺳﻢ ﻣﻲﻛﻨﺪ‪.‬‬

‫‪390‬‬

‫‪www.pupuol.com‬‬


‫ﭘﻮﭘﻮﻝ ﻣﺮﺟﻊ ﺩﺍﻧﺸﮕﺎﻩ ﻭ ﻣﺪﺭﺳﻪ‬ ‫ﻛﻢ ﻛﻢ دارﻳﻢ ﺑﻪ ﺧﻂﻫﺎي ﭘﺎﻳﺎﻧﻲ اﻳﻦ ﻧﻮﺷﺘﻪ ﻧﺰدﻳﻚ ﻣﻲﺷﻮﻳﻢ‪ .‬ﺗﺎ ﻧﻮﺷﺘﻪاي دﻳﮕﺮ ﻫﻤﻪي ﺷﻤﺎ ﻋﺰﻳﺰان را ﺑﻪ‬ ‫‪compiler‬ﺗﺎن ﻣﻲﺳﭙﺎرم‬

‫‪.‬‬

‫> ا ‪ Q‬ار‬

‫‪391‬‬

‫‪www.pupuol.com‬‬


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.