You are on page 1of 82

‫‪ -١‬ﺑﻨﻴﺔ ﺍﻟﺒﻴﺎﻧﺎﺕ ﺑﻠﻐﺔ ‪Visual C++‬‬

‫ﳝﻜــﻦ ﲤﺜﻴــﻞ ﻛــﻞ اﻷﺷــﻴﺎء اﻟــﱵ ﻧﺘﻌﺎﻣــﻞ ﻣﻌﻬــﺎ ﲜﻤﻠــﺔ ﻣــﻦ اﻟﺒﻴﺎﻧــﺎت‪ ،‬اﻟﻄﺎﻟــﺐ ﻣــﺜﻼً ﺑﺎﻟﻨﺴــﺒﺔ ﻟﺸــﺆون‬
‫اﻟﻄﻼب ﻫـﻮ ﻣﻌﻠﻮﻣـﺎت ﺗﺸـﻤﻞ اﺳـﻢ اﻟﻄﺎﻟـﺐ وﺗﻮﻟـﺪﻩ وﻋﻨﻮاﻧـﻪ وﺗـﺎرﻳﺦ اﻟﺘﺴـﺠﻴﻞ واﻟﺴـﻨﺔ اﻟـﱵ ﻳـﺪرس ـﺎ‪ ،‬وﰲ‬
‫ﺷ ــﻌﺒﺔ اﻻﻣﺘﺤﺎﻧــﺎت ﻫ ــﻮ ﻋﺒ ــﺎرة ﻋ ــﻦ ﲨﻠ ــﺔ ﺑﻴﺎﻧ ــﺎت ﻗ ــﺪ ﺗﺘﻀــﻤﻦ ﺟــﺰءاً ﻣ ــﻦ اﻟﺒﻴﺎﻧ ــﺎت اﻟ ــﱵ ــﻢ ﺷــﻌﺒﺔ ﺷ ــﺆون‬
‫اﻟﻄﻼب إﺿﺎﻓﺔ إﱃ ﻣﻌﻠﻮﻣﺎت ﺗﺘﻌﻠﻖ ﺑﺪرﺟﺎﺗﻪ ﰲ اﻣﺘﺤﺎﻧﺎت اﳌﻘﺮرات‪.‬‬
‫اﳌﺆﺷﺮ ﻫﻮ ﻋﻨﻮان ﰲ اﻟﺬاﻛﺮة اﻟﺪاﺧﻠﻴﺔ ﳉﻬﺎز اﳊﺎﺳﻮب ﻳـﺪل ﻋﻠـﻰ ﻣﻮﻗـﻊ ﲣـﺰﻳﻦ ﻛﺘﻠـﺔ ﻣـﻦ اﻟﺒﻴﺎﻧـﺎت‪.‬‬
‫وﻫــﻮ ﻣﺘﻐــﲑ ﳛــﺪد ﻗﻴﻤﺘــﻪ ﻣــﱰﺟﻢ اﻟﻠﻐــﺔ ﰲ أﺛﻨــﺎء اﻟﺘﺼ ـﺮﻳﺢ ﻋﻨــﻪ ﰲ اﻟﱪﻧــﺎﻣﺞ أو ﳝﻜــﻦ ﲢﺪﻳــﺪ ﻗﻴﻤﺘــﻪ ﻣــﻦ ﻗﺒــﻞ‬
‫اﳌﱪﻣﺞ ﻛﺒﺎﻗﻲ اﳌﺘﻐﲑات ﻟﻘﺮاءة ﻣﻮاﻗﻊ ﰲ اﻟﺬاﻛﺮة‪ ،‬وﻫﺬا ﻣﺎ ﻻ ﻳﺴﺘﺨﺪﻣﻪ اﳌﱪﳎﻮن إﻻ ﻧﺎدراً ﻟﻌﺪم اﳊﺎﺟﺔ ﻟﻪ‪.‬‬
‫ﺳــﻨﺒﲔ ﰲ ﻫــﺬﻩ اﻟﻮﺣــﺪة ﻛﻴﻔﻴــﺔ اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ اﳌﺆﺷـﺮات ﻛﻤﺘﻐـﲑات دﻳﻨﺎﻣﻴﻜﻴــﺔ‪ ،‬وﺳــﻨﺒﲔ أﻳﻀـﺎً ﻛﻴﻔﻴــﺔ‬
‫ﲣـ ـﺰﻳﻦ اﻟﺒﻴﺎﻧ ــﺎت ﰲ اﳌﻮاﻗ ــﻊ اﻟ ــﱵ ﺗ ــﺪل ﻋﻠﻴﻬ ــﺎ ﻫ ــﺬﻩ اﳌﺆﺷـ ـﺮات واﺳ ــﺘﺨﺮاﺟﻬﺎ‪ .‬ﻛﻤ ــﺎ ﺳ ــﻨﺒﲔ ﻛﻴﻔﻴ ــﺔ اﺳ ــﺘﺨﺪام‬
‫اﳌﺆﺷﺮات ﰲ ﺑﻨﺎء اﻟﻠﻮاﺋﺢ اﳋﻄﻴﺔ‪.‬‬

‫‪ -١-١‬إﻋﺎدة ﺗﺴﻤﻴﺔ أﻧﻤﺎط اﻟﺒﻴﺎﻧﺎت‬


‫ﺗﺘــﻴﺢ ﻟﻐــﺔ ‪ Visual C++‬ﺑﺸــﻜﻞ ﻋــﺎم إﻋــﺎدة ﺗﺴــﻤﻴﺔ أﳕــﺎط اﻟﺒﻴﺎﻧــﺎت اﳌﻌﺮﻓــﺔ ﻣﺴــﺒﻘﺎً ــﺪف ﺗﺴــﻬﻴﻞ‬
‫ﻋﻤﻠﻴﺔ ﲢﺮﻳﺮ اﻟﱪﻧﺎﻣﺞ‪ ،‬ﻳﺴﺘﺨﺪم ﻟﺬﻟﻚ اﻟﻜﻠﻤﺔ اﶈﺠﻮزة ‪ typedef‬ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪Typedef old_type new_type‬‬
‫ﺣﻴﺚ ‪ old_type‬اﻻﺳﻢ اﻟﺴﺎﺑﻖ ﻟﻠﻨﻤﻂ و ‪ new_type‬اﻻﺳﻢ اﳉﺪﻳﺪ ﻟﻠﻨﻤﻂ‪.‬‬
‫ﳝﻜﻨﻨﺎ ﻋﻠﻰ ﺳﺒﻴﻞ اﳌﺜﺎل اﺳﺘﺒﺪال ﺗﺴﻤﻴﺔ اﻟﻨﻤﻂ ‪ unsigned short‬ﺑﺎﻟﺘﺴﻤﻴﺔ اﳌﺨﺘﺼﺮة ‪ uns‬ﺑﺎﺳـﺘﺨﺪام ﻫـﺬا‬
‫اﻷﻣﺮ ﻋﻠﻰ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;‪Typedef unsigned short uns‬‬
‫وﳝﻜﻨﻨﺎ ﻋﻨﺪﺋﺬ أن ﻧﻌﺮف اﳌﺘﻐﲑات ﻣﻦ اﻟﻨﻤﻂ ‪ unsigned short‬ﺑﺄﻣﺮ ﻣﻦ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;‪uns num1, num2‬‬
‫;‪const uns=60‬‬

‫‪ -٢-١‬اﻟﻤﺘﻐﻴﺮات اﻟﺘﻌﺪادﻳﺔ )اﻟﻤﺠﻤﻮﻋﺎت(‬


‫ﳝﻜﻨﻨﺎ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺘﻐﲑات ﺗﻌﺪادﻳﺔ ‪ Enumeration‬ﻳﺘﻢ ﻓﻴﻬﺎ ﲢﺪﻳﺪ اﻟﻘﻴﻢ اﻟﱵ ﳝﻜـﻦ ﻟﻠﻤﺘﻐـﲑ أن‬
‫ﻳﺄﺧــﺬﻫﺎ‪ ،‬أي ﳎﻤﻮﻋــﺔ ﻣــﻦ اﻟﺜﻮاﺑــﺖ‪ .‬ﻋﻠــﻰ ﺳــﺒﻴﻞ اﳌﺜــﺎل‪ ،‬ﳝﻜﻨﻨــﺎ أن ﻧﻌــﺮف ﻣﺘﻐــﲑ ‪ Week‬أو اﻷﺳــﺒﻮع اﻟــﺬي‬

‫‪١-١‬‬
‫ﻳﺄﺧــﺬ ﻗﻴﻤــﺔ ﲤﺜــﻞ أﺣــﺪ أﻳــﺎم اﻷﺳــﺒﻮع )اﻟﺴــﺒﺖ اﻷﺣــﺪ‪ .(Saturday, Sunday ....‬ﻳــﺘﻢ اﻟﺘﻌﺮﻳ ـﻒ ﻋــﻦ‬
‫اﺠﻤﻟﻤﻮﻋﺎت وﻛﺄ ﺎ أﳕﺎط ﺟﺪﻳﺪة ﻏﲑ اﻷﳕﺎط اﻟﻘﻴﺎﺳﻴﺔ اﳌﻌﺮﻓﺔ ﻣﺴـﺒﻘﺎً وﻣـﻦ ﰒ ﻳـﺘﻢ اﻟﺘﺼـﺮﻳﺢ ﻋـﻦ ﻣﺘﻐـﲑات ﻣـﻦ‬
‫ﻫﺬا اﻟﻨﻤﻂ‪ .‬ﻳﺘﻢ اﻟﺘﺼﺮﻳﺢ ﻋﻦ اﺠﻤﻟﻤﻮﻋﺔ ﺑﺎﻟﺼﻴﻐﺔ اﻟﻌﺎﻣﺔ اﻵﺗﻴﺔ‪:‬‬
‫;]‪enum [tag] {enum-list} [declarator‬‬
‫ﺣﻴﺚ‪:‬‬
‫‪ :tag‬اﺳﻢ اﺠﻤﻟﻤﻮﻋﺔ‪ ،‬وﲣﻀﻊ ﺗﺴﻤﻴﺔ اﺠﻤﻟﻤﻮﻋﺔ ﻟﻘﻮاﻋﺪ ﺗﺴﻤﻴﺔ اﳌﺘﻐﲑات‪ ،‬وﻫﻮ اﺧﺘﻴﺎري‪.‬‬
‫‪ :enum-list‬ﺛﻮاﺑﺖ اﺠﻤﻟﻤﻮﻋﺔ أو ﻗﻴﻢ اﺠﻤﻟﻤﻮﻋﺔ وﻫﻲ ﻗﻴﻢ ﲢﺪد ﺎﻳﺎ ﺎ ﺑﺎﻟﻔﺎﺻﻠﺔ‪.‬‬
‫‪ :declarator‬اﺳﻢ ﻣﺘﻐﲑ ﻳﺄﺧﺬ ﻗﻴﻤﻪ ﺿﻤﻦ ﺛﻮاﺑﺖ اﺠﻤﻟﻤﻮﻋﺔ وﻫﻮ اﺧﺘﻴﺎري‪.‬‬
‫ﳝﻜﻨﻨﺎ اﻟﺘﺼﺮﻳﺢ ﻋﻦ اﺠﻤﻟﻤﻮﻋﺔ ﺑﺘﻌﺮﻳﻒ اﲰﻬﺎ ‪ tag‬وﰲ اﻟﻮﻗﺖ ﻧﻔﺴﻪ اﻟﺘﺼﺮﻳﺢ ﻋـﻦ ﻣﺘﻐـﲑ ﻣـﻦ ﻫـﺬا اﻟـﻨﻤﻂ‪ .‬أي‬
‫ﺑﺎﻟﺸﻜﻞ اﻟﺴﺎﺑﻖ‪ ،‬أو ﺑﺎﻟﺘﺼﺮﻳﺢ ﻋﻦ ﳎﻤﻮﻋﺔ ﺑﺪون ﺗﻌﺮﻳﻒ اﳌﺘﻐﲑ ﺑﺄﻣﺮ اﻟﺘﺼﺮﻳﺢ‪ ،‬أي ﺑﺎﻟﺸﻜﻞ‪:‬‬
‫;}‪enum [tag] {enum-list‬‬
‫ﻛﻤﺎ ﳝﻜﻦ ﺗﻌﺮﻳﻒ ﳎﻤﻮﻋﺔ ﺑﺪون اﺳﻢ وﻳﻌﺮف ﻣﺘﻐﲑ واﺣﺪ ﻓﻘﻂ ﻣﻦ ﳕﻂ اﺠﻤﻟﻤﻮﻋﺔ‪ ،‬أي ﺑﺎﻟﺸﻜﻞ‪:‬‬
‫;]‪enum {enum-list} [declarator‬‬
‫ﻛﻞ ﻋﻨﺼﺮ ﻣﻦ ﻋﻨﺎﺻﺮ اﺠﻤﻟﻤﻮﻋـﺔ ﳛﻤـﻞ رﻗﻤـﺎً ﳝﺜـﻞ ﺗﺮﺗﻴـﺐ ﻫـﺬا اﻟﻌﻨﺼـﺮ داﺧـﻞ اﺠﻤﻟﻤﻮﻋـﺔ‪ .‬ﻳﺒـﺪأ ﺗـﺮﻗﻴﻢ‬
‫ﻫﺬﻩ اﻟﻌﻨﺎﺻﺮ ﻣﻦ اﻟﺼﻔﺮ‪ ،‬وﳝﻜﻦ إﻋﻄﺎء أي رﻗﻢ ﺻﺤﻴﺢ ﻷي ﻋﻨﺼﺮ ﰲ اﺠﻤﻟﻤﻮﻋﺔ‪.‬‬
‫وﳝﻜﻦ ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑات ﻣﻦ ﳕﻂ اﺠﻤﻟﻤﻮﻋﺔ اﳌﻌﺮﻓﺔ ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;‪enum tag declarator‬‬

‫ﻣﺜﺎل ‪١-١‬‬
‫ﻟﻠﺘﺼﺮﻳﺢ ﻋﻦ ﳎﻤﻮﻋﺔ ‪ Week‬ﺗﺘﻀﻤﻦ أﻳﺎم اﻷﺳﺒﻮع ﳝﻜﻨﻨﺎ أن ﻧﻜﺘﺐ‪:‬‬
‫>‪#include <iostream.h‬‬
‫)(‪main‬‬
‫{‬
‫‪enum Days‬‬
‫{‬
‫‪Saturday,‬‬
‫‪Sunday,‬‬
‫‪Monday=4,‬‬
‫‪Tuesday,‬‬
‫‪Wednesday,‬‬
‫‪Thursday,‬‬
‫‪Friday,‬‬
‫;‪} Day1‬‬

‫‪٢-١‬‬
‫;‪enum Days Day2‬‬
‫;‪Day1=Monday‬‬
‫;‪Day2=Thursday‬‬
‫;‪cout<<Day1<<" "<<Day2‬‬
‫;)‪return(0‬‬
‫}‬
‫ﰎ اﻟﺘﺼـﺮﻳﺢ ﰲ ﻫــﺬا اﻟﱪﻧــﺎﻣﺞ ﻋــﻦ ﳎﻤﻮﻋــﺔ أﻳــﺎم اﻷﺳــﺒﻮع ‪ Days‬وﺗﻌــﺪاد ﻗــﻴﻢ ﻫــﺬﻩ اﺠﻤﻟﻤﻮﻋــﺔ اﳌﻤﺜﻠــﺔ‬
‫ﻷﻳﺎم اﻷﺳﺒﻮع‪ ،‬وﻗﺪ ﰎ اﻟﺘﺼﺮﻳﺢ ﻋـﻦ ﻣﺘﻐـﲑ ‪ Day1‬ﺑـﺎﻷﻣﺮ ﻧﻔﺴـﻪ اﻟـﺬي ﰎ ﻓﻴـﻪ اﻟﺘﺼـﺮﻳﺢ ﻋـﻦ ﻫـﺬﻩ اﺠﻤﻟﻤﻮﻋـﺔ‪.‬‬
‫ﺗﺄﺧﺬ اﻟﻘﻴﻤﺔ ‪ Saturday‬ﺗﻠﻘﺎﺋﻴﺎً اﻟﺮﻗﻢ ‪ 0‬واﻟﻘﻴﻤـﺔ ‪ Sunday‬اﻟـﺮﻗﻢ ‪ 1‬وﻫﻜـﺬا‪ ...‬ﳝﻜﻨﻨـﺎ ﺗﻐﻴـﲑ اﻟﱰﻗـﻴﻢ اﻟﺘﻠﻘـﺎﺋﻲ‬
‫ﻟﻠﻘــﻴﻢ ﺑﺈﺳــﻨﺎد أرﻗــﺎم ﻷي ﻣــﻦ ﻫــﺬﻩ اﻟﻘــﻴﻢ أو ﳉﻤﻴﻌﻬــﺎ‪ .‬إذا أﻋﻄﻴﻨــﺎ اﻟــﺮﻗﻢ ‪ 5‬ﻋﻠــﻰ ﺳــﺒﻴﻞ اﳌﺜــﺎل ﻟﻠﻘﻴﻤــﺔ اﻷوﱃ‬
‫ﻓــﺎﻟﱰﻗﻴﻢ ﺳــﻴﺒﺪأ ﻣــﻦ ‪ .5‬ﻟﻘــﺪ ﺣــﺪدﻧﺎ رﻗــﻢ ‪ 4‬ﻟﻠﻘﻴﻤــﺔ ‪ Monday‬ﰲ اﳌﺜــﺎل وﻣــﻦ ﰒ ﻓــﺈن ﺗــﺮﻗﻴﻢ اﻟﻘﻴﻤــﺔ اﻷوﱃ‬
‫واﻟﺜﺎﻧﻴﺔ ﺗﺒﻘﻰ ﻛﻤﺎ ﻫﻲ ﻋﻠﻰ اﻟﺘﻮاﱄ ‪ 0‬و ‪ 1‬أﻣﺎ اﻟﻘﻴﻢ اﻵﺗﻴﺔ ﻓﻴﺒﺪأ ﺗﺮﻗﻴﻤﻬﺎ ﻣﻦ اﻟﺮﻗﻢ ‪.4‬‬
‫ﳝﻜــﻦ أن ﻧﺴــﺘﺨﺪم ﻫــﺬا اﻟــﻨﻤﻂ ﰲ اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ ﻣﺘﻐـﲑات ﲤﺎﻣـﺎً ﻛﺎﻟﺘﺼـﺮﻳﺢ ﻋــﻦ أي ﻣﺘﻐــﲑ ﻣــﻦ أي‬
‫ﳕﻂ ﻣﻦ اﻷﳕﺎط اﻟﻘﻴﺎﺳﻴﺔ‪ ،‬ﻟﻠﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺘﻐﲑ ‪ week1‬ﻧﻜﺘﺐ‪:‬‬
‫;‪enum Days Day2‬‬
‫وﻧﺎﺗﺞ ﺗﻨﻔﻴﺬ اﻟﱪﻧﺎﻣﺞ ﻫﻮ‪:‬‬
‫‪4‬‬ ‫‪7‬‬

‫‪Visual C++‬‬ ‫‪ -٣-١‬اﻟﻤﺆﺷﺮات ‪ Pointers‬ﺑﻠﻐﺔ‬


‫إن اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ ﻣﺘﻐــﲑ ‪ x‬ﺑــﺎﻷﻣﺮ ;‪ int x‬ﺳــﻴﺤﺠﺰ ﻋﻨﻮاﻧـﺎً ﰲ اﻟــﺬاﻛﺮة اﻟﺪاﺧﻠﻴــﺔ ﻟﺘﺨـﺰﻳﻦ ﻗﻴﻤــﺔ ﻫــﺬا‬
‫اﳌﺘﻐــﲑ‪ .‬ﳝﻜﻨﻨــﺎ ﻣﻌﺮﻓــﺔ ﻫــﺬا اﻟﻌﻨـﻮان ﺑﻄﺒﺎﻋﺘــﻪ ﺑﺎﺳــﺘﺨﺪام اﻟﺮﻣــﺰ "&" ﺑــﺎﻷﻣﺮ ;‪ .cout<<&x‬اﻷﻣــﺮ ;‪cout<<x‬‬
‫ﻳﻈﻬــﺮ ﻗﻴﻤــﺔ ‪ x‬أﻣــﺎ اﻷﻣــﺮ ;‪ cout<<&x‬ﺳــﻴﻈﻬﺮ اﻟﻌﻨ ـﻮان ﻣــﻦ اﻟــﺬاﻛﺮة اﻟــﺬي ﺗــﺘﻢ ﻓﻴــﻪ ﻋﻤﻠﻴــﺔ ﲣ ـﺰﻳﻦ ﻗﻴﻤــﺔ ‪.x‬‬
‫واﻟﻮاﻗــﻊ‪ ،‬ﻋﻨ ـﻮان اﻟــﺬاﻛﺮة اﻟــﺬي ﳜــﺰن ﻓﻴــﻪ ﻗﻴﻤــﺔ ‪ x‬ﻳﺴــﻤﻰ ﺑﺎﳌﺆﺷــﺮ ‪ Pointer‬إﱃ ‪ ،x‬وﳝﻜــﻦ ﳍــﺬا اﳌﺆﺷــﺮ أن‬
‫ﻳﻜــﻮن أي ﻋﻨ ـﻮان ﰲ اﻟــﺬاﻛﺮة وﻣــﻦ ﰒ ﳝﻜــﻦ اﻟﺘﻌﺎﻣــﻞ ﻣﻌــﻪ ﻛــﺄي ﻣﺘﻐــﲑ‪ .‬وﻫــﻲ اﻟﻔﻜــﺮة اﻷﺳﺎﺳــﻴﺔ ﻻﺳــﺘﺨﺪام‬
‫اﳌﺆﺷﺮات‪.‬‬
‫اﳌﺆﺷ ـﺮات ﻫــﻲ ﻋﺒــﺎرة ﻋــﻦ ﻣﺘﻐ ـﲑات ﺗﺄﺧــﺬ ﻗﻴﻤﻬ ـﺎ ﺿــﻤﻦ ﳎﻤﻮﻋــﺔ اﻷﻋــﺪاد اﻟﺼــﺤﻴﺤﺔ ﺑﻨﻈــﺎم اﻟﻌــﺪ‬
‫اﻟﺴﺪاﺳﻲ ﻋﺸﺮ‪ ،‬وﻫﻲ ﺗﺸﲑ إﱃ ﻣﻮﻗﻊ ﻗﻴﻤﺔ ﰲ اﻟﺬاﻛﺮة اﻟﺪاﺧﻠﻴﺔ‪ .‬ﻳﺘﻢ اﻟﺘﺼﺮﻳﺢ ﻋﻦ اﳌﺆﺷﺮات ﺑﻠﻐﺔ ‪Visual‬‬
‫‪ C++‬ﺑﺎﺳﺘﺨﺪام رﻣﺰ اﻟﻨﺠﻤﺔ ﻗﺒﻞ اﺳﻢ اﳌﺘﻐﲑ وﻓﻖ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪Type *Variable_Name‬‬
‫أو ﺑﺎﻟﺸﻜﻞ‪:‬‬
‫‪Type* Variable_Name‬‬

‫‪٣-١‬‬
‫ﺣﻴــﺚ ‪ Type‬ﳕــﻂ ﻣــﻦ أﳕــﺎط اﻟﺒﻴﺎﻧــﺎت اﳌﻌﺮﻓــﺔ ﺑﻠﻐــﺔ ‪ C++‬ﺑﺸــﻜﻞ ﻣﺴــﺒﻖ أو اﳌﻌــﺮف ﻣــﻦ ﻗﺒــﻞ اﳌﺴــﺘﺨﺪم و‬
‫‪ Variable_Name‬اﺳﻢ اﳌﺘﻐﲑ‪.‬‬
‫‪new‬‬ ‫‪ -١-٣-١‬اﻷﻣﺮ‬
‫ﻋﻨــﺪ اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ ﻣﺘﻐــﲑ ﻣﺆﺷــﺮ ﺑﻠﻐــﺔ ‪ Visual C++‬ﻳﺄﺧــﺬ ﻫــﺬا اﳌﺘﻐــﲑ اﻟﻘﻴﻤــﺔ ‪ NULL‬اﻟــﱵ ﺗــﺪل‬
‫ﻋﻠـﻰ ﻻ ﺷـﻲء‪ ،‬وﻫـﻲ ﻗﻴﻤــﺔ ﻣﻌﺮﻓـﺔ ﺑﻠﻐـﺔ ‪ Visual C++‬وﺗـﺪل ﻋﻠـﻰ اﻟﻌﻨـﻮان ‪ .0x000000‬وﻫـﺬا اﻟﻌﻨـﻮان ﻣــﻦ‬
‫اﻟﺬاﻛﺮة ﻻ ﳝﻜﻦ ﲣﺰﻳﻦ ﻓﻴﻪ ﺷﻲء‪ .‬ﻟﺬا ﻓﻌﻨﺪ اﺳﺘﺨﺪاﻣﻨﺎ ﳌﺘﻐﲑ ﻣﺆﺷﺮ ﻻ ﺑﺪ ﻣﻦ إﻋﻄﺎﺋﻪ ﻗﻴﻤـﺔ‪ ،‬وﳝﻜﻨﻨـﺎ ﲢﺪﻳـﺪ‬
‫ﻋﻨ ـﻮان اﻟ ــﺬاﻛﺮة اﳌ ـﺮاد ﲣ ـﺰﻳﻦ ﻗﻴﻤ ــﺔ اﳌﺘﻐ ــﲑ ﻓﻴﻬ ــﺎ أو ﳝﻜﻨﻨ ــﺎ ﺗ ــﺮك اﻟﻠﻐ ــﺔ إﻋﻄ ــﺎء ﻗﻴﻤ ــﺔ ﲝﺴ ــﺐ اﻟ ــﺬاﻛﺮة اﳌﺘﺎﺣ ــﺔ‬
‫ﺑﺎﺳﺘﺨﺪام اﻷﻣﺮ ‪ new‬اﻟﺬي ﳛﺪد أﻳﻀﺎً ﺣﺠﻢ اﻟﺬاﻛﺮة اﳌﺨﺼﺼﺔ ﻟﺘﺨﺰﻳﻦ ﻗﻴﻤﺔ اﳌﺘﻐﲑ‪.‬‬
‫ﻳﺴﺘﺨﺪم اﻷﻣﺮ ‪ new‬ﻋﻠﻰ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪Variable_Name =new type‬‬
‫ﺣﻴ ــﺚ ‪ type‬ﻫ ــﻮ ﳕ ــﻂ ﺑﻴﺎﻧ ــﺎت اﳌﺘﻐ ــﲑ اﳌﺆﺷ ــﺮ و ‪ Variable_Name‬ﻫ ــﻮ اﺳ ــﻢ اﳌﺘﻐ ــﲑ اﳌﺼ ــﺮح ﻋﻨ ــﻪ ﻣﺴ ــﺒﻘﺎً‬
‫ﺑﺎﻟﺸﻜﻞ‪:‬‬
‫‪type *Variable_Name;.‬‬

‫‪ -٢-٣-١‬إﺳﻨﺎد ﻗﻴﻤﺔ ﻣﺆﺷﺮ‬


‫ﳝﻜــﻦ إﺳــﻨﺎد ﻗﻴﻤــﺔ ﻣﺆﺷــﺮ دال ﻋﻠــﻰ ﻣﻮﻗــﻊ ﻣﺘﻐــﲑ إﱃ ﻣﺆﺷــﺮ ﻣﺘﻐــﲑ آﺧــﺮ ﻣــﻦ اﻟــﻨﻤﻂ ﻧﻔﺴــﻪ ﺑﻌﻤﻠﻴــﺔ‬
‫إﺳﻨﺎد ﻋﺎدﻳﺔ ﺑﺎﻟﺸﻜﻞ‪:‬‬
‫‪Variable_Name1=&Variable_Name2‬‬
‫ﳛ ــﺪد ﺣﺠ ــﻢ اﻟ ــﺬاﻛﺮة اﳌﺨﺼﺼ ــﺔ ﻟﺘﺨـ ـﺰﻳﻦ اﻟﻘﻴﻤ ــﺔ ﻣ ــﻦ ﺧ ــﻼل ﳕ ــﻂ اﻟﺒﻴﺎﻧ ــﺎت اﳌﺸ ــﺎر إﻟﻴﻬ ــﺎ‪ .‬ﻓﻌﻨ ــﺪ‬
‫اﻟﺘﻌﺮﻳــﻒ ﻋــﻦ ﻣﺆﺷــﺮ ﻟﻘﻴﻤــﺔ ﻣﺘﻐــﲑ ﻣــﻦ اﻟــﻨﻤﻂ اﻟﺼــﺤﻴﺢ ‪ int‬ﻳــﺘﻢ ﺣﺠــﺰ ‪ 2‬ﺑﺎﻳــﺖ ﻟﺘﺨ ـﺰﻳﻦ ﻗﻴﻤــﺔ ﻫــﺬا اﳌﺘﻐــﲑ‪.‬‬
‫وﻣﻬﻤﺎ ﻛﺎن ﺣﺠﻢ اﻟﺒﻴﺎﻧﺎت اﳌﺸـﺎر إﻟﻴﻬـﺎ ﺑﺎﳌﺆﺷـﺮ ﻳﺒﻘـﻰ ﺣﻴـﺰ اﻟـﺬاﻛﺮة اﳌﺨﺼﺼـﺔ ﻟﺘﺨـﺰﻳﻦ ﻗﻴﻤـﺔ اﳌﺘﻐـﲑ اﳌﺆﺷـﺮ‬
‫ﺛﺎﺑﺘـﺎً‪ ،‬وﳜﺘﻠــﻒ ﻫــﺬا اﳊﻴــﺰ ﲝﺴــﺐ إﺻــﺪار اﻟﻠﻐــﺔ وﻧــﻮع ﺟﻬــﺎز اﳊﺎﺳــﻮب‪ .‬ﻋﻨــﺪ اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ ﻣﺘﻐــﲑ ﻣﺆﺷــﺮ ‪x‬‬
‫ﺑﺎﻷﻣﺮ‪:‬‬
‫;‪int *x‬‬
‫وﺑﻌﺪ وﺿﻊ ﻗﻴﻤﺔ ﻣﺘﻐﲑ ﻣﺜﻞ ‪ y‬ﻛﻘﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ ﻟﻠﻤﺘﻐﲑ ‪ *x‬ﺑﺎﻷواﻣﺮ ‪:١‬‬
‫;‪y=10‬‬
‫;‪x=&y‬‬

‫‪ ١‬ﳚﺐ إﻋﻄﺎء اﳌﺘﻐﲑ اﳌﺆﺷﺮ ﻗﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ ﻟﺘﻼﰲ ﺣﺼﻮل ﺧﻄﺄ ﰲ أﺛﻨﺎء ﺗﺮﲨﺔ اﻟﱪﻧﺎﻣﺞ‪ .‬وﻳﺘﻢ ذﻟﻚ إﻣﺎ ﺑﺘﺤﺪﻳﺪ ﻫﺬا اﻟﻌﻨﻮان‬
‫ﻣﺒﺎﺷﺮة أو ﺑﺈﺳﻨﺎد ﻋﻨﻮان ﻣﺘﻐﲑ ﻣﻦ ﳕﻂ اﳌﺆﺷﺮ ﻧﻔﺴﻪ ﳕﻂ اﳌﺆﺷﺮ إﱃ اﳌﺘﻐﲑ اﳌﺆﺷﺮ‪.‬‬

‫‪٤-١‬‬
‫ﻓــﺈن ‪ x‬ﻳﺸــﲑ إﱃ ﻋﻨ ـﻮان ﰲ اﻟــﺬاﻛﺮة اﻟﺪاﺧﻠﻴــﺔ ﻛﻤﻮﻗــﻊ ﻟﺘﺨ ـﺰﻳﻦ ﻫــﺬﻩ اﻟﻘﻴﻤــﺔ )ﻗﻴﻤــﺔ ‪ ،(x‬أي أن ﻗﻴﻤــﺔ ‪ x‬ﻣــﻦ‬
‫اﻟﺸﻜﻞ ‪ ،x=0x3FBA000‬أﻣﺎ ﻗﻴﻤﺔ ‪ *x‬ﻓﻬﻲ ‪ .10‬ﻳﻮﺿﺢ اﻟﺸﻜﻞ ‪ ١-١‬ﻋﻤﻠﻴﺔ ﲤﺜﻴﻞ اﻟﺒﻴﺎﻧﺎت ﺑﺎﺳﺘﺨﺪام‬
‫اﳌﺆﺷﺮات‪.‬‬
‫‪x‬‬ ‫ﻣﺆﺷﺮ اﳌﺘﻐﲑ‬ ‫‪x‬‬ ‫ﻣﻮﻗﻊ اﳌﺘﻐﲑ‬

‫‪0x3FBA000‬‬ ‫‪10‬‬

‫‪0x3FBA000‬‬

‫اﻟﺸﻜﻞ ‪ ١-١‬ﺷﻜﻞ اﳌﺆﺷﺮات‬

‫‪ -٣-٣-١‬اﻟﻌﻤﻠﻴﺎت ﻋﻠﻰ اﻟﻤﺆﺷﺮات‬


‫‪x‬‬ ‫ﻳﺘﻢ اﻟﺘﻌﺎﻣﻞ ﻣﻊ ﻗﻴﻤﺔ ﻣﺘﻐﲑ ﻣﺆﺷـﺮ ﻟﻠﻤﺘﻐـﲑ ‪ x‬اﳌﺼـﺮح ﻋﻨـﻪ ﺑـﺎﻷﻣﺮ ;‪ int *x‬ﺑﺎﺳـﺘﺨﺪام ‪ *x‬وﻟـﻴﺲ‬
‫اﻟﺬي ﻳﺸﲑ إﱃ ﻣﻮﻗﻊ اﻟـﺬاﻛﺮة‪ ،‬ﺣﻴـﺚ ﺗﻘـﺮأ ﻗـﻴﻢ اﳌﺘﻐـﲑات اﳌﺼـﺮح ﻋﻨﻬـﺎ ﻛﻤﺆﺷـﺮات ﻟﻘـﺮاءة اﳌﺘﻐـﲑات اﻟﻌﺎدﻳـﺔ‪،‬‬
‫ﻛﻤــﺎ ﳝﻜــﻦ إﺟ ـﺮاء ﻛــﻞ اﻟﻌﻤﻠﻴــﺎت اﳊﺴــﺎﺑﻴﺔ اﳌﻌﺮﻓــﺔ ﺳــﺎﺑﻘﺎً ﻋﻠــﻰ اﳌﺘﻐــﲑ ‪ .*x‬ﻻ ﺗﺄﺧــﺬ اﳌﺘﻐ ـﲑات ﻣــﻦ ﳕــﻂ‬
‫اﳌﺆﺷ ـﺮات ﻗﻴﻤ ـﺎً ﳏــﺪدة‪ ،‬ﺑــﻞ ﻗــﺪ ﲣﺘﻠــﻒ ﻫــﺬﻩ اﻟﻘــﻴﻢ ﰲ اﻟﺘﻄﺒﻴــﻖ اﻟﻮاﺣــﺪ ﲝﺴــﺐ اﳉﻬــﺎز أو ﲝﺴــﺐ اﻟ ـﱪاﻣﺞ‬
‫اﻷﺧﺮى اﻟﱵ ﻳﺘﻢ ﺗﺸﻐﻴﻠﻬﺎ ﻋﻠﻰ اﳉﻬﺎز‪ .‬واﻟﻮاﻗﻊ ﻫﻲ ﻋﻨـﺎوﻳﻦ ﰲ اﻟـﺬاﻛﺮة ﲢـﺪد ﻣـﻦ ﻗﺒـﻞ ﻣـﱰﺟﻢ اﻟﻠﻐـﺔ ﲝﺴـﺐ‬
‫ﻣﺸﻐﻮﻟﻴﺔ اﻟﺬاﻛﺮة‪.‬‬
‫ﻣﺜﺎل ‪٢-١‬‬
‫ﻓﻴﻤﺎ ﻳﺄﰐ ﺑﻌﺾ اﻟﻌﻤﻠﻴﺎت اﻷﺳﺎﺳﻴﺔ ﻋﻠﻰ اﳌﺆﺷﺮات‪:‬‬
‫>‪#include <iostream.h‬‬
‫)(‪void main‬‬
‫{‬
‫;‪int y,*x‬‬
‫;‪int* z‬‬
‫;‪y=10‬‬
‫إﺳﻨﺎد ﻋﻨﻮان اﳌﺘﻐﲑ إﱃ اﳌﺆﺷﺮ ‪x=&y; //‬‬
‫;‪z=x‬‬ ‫إﺳﻨﺎد ﻗﻴﻤﺔ ﻣﺆﺷﺮ إﱃ ﻣﺆﺷﺮ آﺧﺮ ‪//‬‬
‫;"‪cout<<"&y="<<&y<<"\n‬‬
‫;"‪cout<<"x="<<x<<"\n‬‬
‫;"‪cout<<"z="<<z<<"\n‬‬
‫ﺗﻨﻔﻴﺬ ﻋﻤﻠﻴﺔ ﺣﺴﺎﺑﻴﺔ ‪cout<<"*x/2="<<*x/2; //‬‬
‫}‬
‫وﻧﺎﺗﺞ ﺗﻨﻔﻴﺬ ﻫﺬﻩ اﻷواﻣﺮ ﻫﻮ‪:‬‬

‫‪٥-١‬‬
‫‪&y=0x0012FF7C‬‬
‫‪x=0x0012FF7C‬‬
‫‪z=0x0012FF7C‬‬
‫‪*x/2=5‬‬

‫‪Records‬‬ ‫‪ -٤-١‬ﺑﻨﻴﺔ اﻟﺴﺠﻼت‬


‫ﻳﻌﺮف اﻟﺴﺠﻞ ﻋﻠﻰ أﻧﻪ ﲡﻤﻴﻊ ﻟﺒﻴﺎﻧﺎت ﻣﻦ اﻷﳕﺎط اﻷوﻟﻴﺔ اﳌﻌﺮوﻓﺔ ﺑﺎﺳﻢ ﳏﺪد ﻟﺘﺼﻒ ﳕـﻂ ﺟﺪﻳـﺪ‬
‫ﻳﺴﺘﺨﺪم ﻛﺎﻷﳕﺎط اﻷﺳﺎﺳﻴﺔ ﰲ اﻟﺘﺼﺮﻳﺢ ﻋﻦ اﳌﺘﻐﲑات‪ .‬ﻟﻠﺴﺠﻞ إذاً ﺗﻌﺮﻳﻒ ﻋﻠﻰ اﳌﺴـﺘﻮى اﳌﻨﻄﻘـﻲ‪ ،‬ﺣﻴـﺚ‬
‫ﻳﺘﻜــﻮن ﻣــﻦ ﳎﻤﻮﻋــﺔ ﺑﻴﺎﻧــﺎت‪ ،‬وﻫــﻲ ﻣــﻦ أﳕــﺎط ﳐﺘﻠﻔــﺔ ﻟﻴﺴــﺖ ﺑﺎﻟﻀــﺮورة ﻣﺘﺠﺎﻧﺴــﺔ‪ ،‬ﺗــﺪﻋﻰ ﺑﻌﻨﺎﺻــﺮ اﻟﺴــﺠﻞ‬
‫‪ Member‬أو ﺑ ــﺎﳊﻘﻮل ‪ ،Field‬ﻳ ــﺘﻢ اﻟﻮﺻ ــﻮل إﻟﻴﻬ ــﺎ ﻋ ــﱪ أﲰ ــﺎء ﳏ ــﺪدة‪ .‬ﺗ ــﺪﻋﻢ ﻟﻐ ــﺔ ‪ Visual C++‬ﻓﻜ ــﺮة‬
‫اﻟﺴﺠﻞ ﻣﻦ ﺧﻼل اﻟﺘﻌﺮﻳﻒ ‪.struct‬‬
‫‪ -١-٤-١‬ﺗﻌﺮﻳﻒ اﻟﺴﺠﻼت‬
‫ﻳﻌﺮف اﻟﺴﺠﻞ ﺑﻠﻐﺔ ‪ Visual C++‬ﺑﺼﻴﻐﺘﻪ اﻟﻌﺎﻣﺔ ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪struct tag_field‬‬
‫{‬
‫;‪member_type member1‬‬
‫;‪member_type member2‬‬
‫‪……………………….‬‬
‫;‪member_type member n‬‬
‫;}‬
‫ﺣﻴـﺚ ‪ tag_field‬ﳝﺜــﻞ اﺳــﻢ اﻟﺴـﺠﻞ اﻟــﺬي ﻳــﺘﻢ ﺗﻌﺮﻳﻔـﻪ‪ ،‬وﳜﻀــﻊ ﺑﺘﺴــﻤﻴﺘﻪ إﱃ ﻗﻮاﻋـﺪ ﺗﺴــﻤﻴﺔ اﳌﺘﻐـﲑات ﺑﻠﻐــﺔ‬
‫‪ ،C++‬أﻣـ ــﺎ ‪ member‬ﻓﻬـ ــﻲ أﲰـ ــﺎء اﳊﻘـ ــﻮل ﰲ اﻟﺴـ ــﺠﻞ اﶈـ ــﺪد ﺑﺎﻷﳕـ ــﺎط ‪ ،member_type‬ﲣﻀـ ــﻊ أﲰـ ــﺎء‬
‫اﳊﻘﻮل أﻳﻀﺎً إﱃ ﻗﻮاﻋﺪ ﺗﺴﻤﻴﺔ اﳌﺘﻐﲑات‪.‬‬
‫ﻣﺜﺎل ‪٣-١‬‬
‫ﻳﺘﻤﺜــﻞ اﻟﻮﻗــﺖ ﺑــﺜﻼث ﻣﻌﻠﻮﻣــﺎت أﺳﺎﺳــﻴﺔ ﻫــﻲ اﻟﺴــﺎﻋﺔ واﻟﺪﻗﻴﻘــﺔ واﻟﺜﺎﻧﻴــﺔ‪ ،‬ﻛــﻞ ﻣــﻦ ﻫــﺬﻩ اﳌﻌﻠﻮﻣــﺎت‬
‫ﻫﻲ ﻗﻴﻤﺔ ﺻﺤﻴﺤﺔ ‪ ،Integer‬وﺑﺪﻻً ﻣﻦ اﻟﺘﻌﺎﻣﻞ ﻣﻊ اﳌﻌﻠﻮﻣﺎت اﻟﺜﻼث ﳝﻜﻨﻨﺎ ﺗﻌﺮﻳـﻒ ﺳـﺠﻞ ﻳﺘﻀـﻤﻦ ﺛﻼﺛـﺔ‬
‫ﺣﻘﻮل ﻋﻠﻰ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪struct time‬‬
‫{‬
‫;‪int hour‬‬
‫;‪int minute‬‬
‫;‪int second‬‬
‫;}‬

‫‪٦-١‬‬
‫‪ -٢-٤-١‬اﺳﺘﺨﺪام اﻟﺴﺠﻼت ﻛﺄﻧﻤﺎط ﻟﻠﺒﻴﺎﻧﺎت‬
‫ﺗﺴﺘﺨﺪم اﻟﺴﺠﻼت اﳌﻌﺮﻓﺔ ﺑﻠﻐﺔ ‪ Visual C++‬ﲤﺎﻣﺎً ﻛﺎﺳﺘﺨﺪام اﻷﳕـﺎط اﻟﻘﻴﺎﺳـﻴﺔ ﻟﻠﺒﻴﺎﻧـﺎت اﳌﻌﺮﻓـﺔ‬
‫ﻣﺴﺒﻘﺎً‪ .‬ﳝﻜﻨﻨﺎ ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑات ﻣﻦ ﻫﺬﻩ اﻷﳕﺎط‪ ،‬ﳝﻜﻨﻨﺎ ﻋﻠﻰ ﺳـﺒﻴﻞ اﳌﺜـﺎل اﺳـﺘﺨﺪام اﻟﺴـﺠﻞ ‪ time‬اﳌﻌـﺮف‬
‫ﺑﺎﳌﺜﺎل اﻟﺴﺎﺑﻖ ﻛﻨﻤﻂ ﳌﺘﻐﲑ ‪ time1‬وأﺧﺮ ﺑﺎﺳﻢ ‪ the_time‬ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;‪time time1, the_time‬‬
‫ﻛﻤﺎ ﳝﻜﻨﻨﺎ اﺳﺘﺨﺪاﻣﻬﺎ ﻛﺄﳕﺎط ﻣﺆﺷﺮات ﺑﺎﻟﺸﻜﻞ‪:‬‬
‫;‪time *time2,*the_time1‬‬
‫ﲟــﺎ أن اﻟﺘﻌﺮﻳــﻒ ﻋــﻦ ﺳــﺠﻞ ﳝﻜﻨﻨــﺎ ﻣــﻦ اﺳــﺘﺨﺪاﻣﻪ ﻟﻠﺘﺼ ـﺮﻳﺢ ﻋــﻦ ﻣﺘﻐ ـﲑات ﻣــﻦ ﳕــﻂ اﻟﺴــﺠﻞ ﻟــﺬا‬
‫ﳝﻜﻨﻨــﺎ اﺳــﺘﺨﺪاﻣﻪ ﰲ اﻟﺘﺼ ـﺮﻳﺢ ﻋــﻦ ﺣﻘــﻮل ﰲ ﺳــﺠﻼت ﺟﺪﻳــﺪة‪ ،‬وﺑــﺬﻟﻚ ﳝﻜﻨﻨــﺎ ﺗﻌﺮﻳــﻒ ﺳــﺠﻼت ﺗﺼــﻒ‬
‫اﻟﺒﻴﺎﻧﺎت ﺑﺸﻜﻞ ﻫﺮﻣﻲ ﻛﻤﺎ ﻳﻮﺿﺤﻪ اﳌﺜﺎل اﻵﰐ‪.‬‬
‫ﻣﺜﺎل ‪٤-١‬‬
‫ﺑﻔ ــﺮض ﺗﻜ ــﻮﻳﻦ ﺳ ــﺠﻞ ﻟﻠﺘ ــﺎرﻳﺦ ‪ date‬ﻳﺘﻀ ــﻤﻦ اﻟﻴ ــﻮم ‪ day‬واﻟﺸ ــﻬﺮ ‪ month‬وآﺧ ــﺮ ﻟﻠﺴ ــﻨﺔ ‪،year‬‬
‫وﺳــﺠﻞ آﺧــﺮ ﻟﻠﻌﻨ ـﻮان ‪ address‬ﻳﺘﻀــﻤﻦ رﻗــﻢ اﻟﺸــﺎرع ‪ number‬و اﺳــﻢ اﻟﺸــﺎرع ‪ street‬واﺳــﻢ اﳌﺪﻳﻨــﺔ ‪city‬‬
‫ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪struct date‬‬
‫{‬
‫;‪byte day‬‬
‫;‪byte month‬‬
‫;‪int year‬‬
‫;}‬
‫‪struct address‬‬
‫{‬
‫;‪int number‬‬
‫;][‪char street‬‬
‫;][‪char city‬‬
‫;}‬
‫ﳝﻜﻨﻨ ــﺎ اﺳ ــﺘﺨﺪام ﺗﻌﺮﻳ ــﻒ ﻫ ــﺬﻳﻦ اﻟﺴ ــﺠﻠﲔ ﰲ اﻟﺘﺼ ـﺮﻳﺢ ﻋ ــﻦ ﺳ ــﺠﻞ آﺧ ــﺮ ﻳﺘﻀ ــﻤﻦ اﺳ ــﻢ اﻟﻄﺎﻟ ــﺐ‬
‫‪ name‬و اﻟﻘﺴ ــﻢ ‪ departement‬وﻫ ــﻲ ﲨﻴﻌﻬ ــﺎ ﻣ ــﻦ اﻟﻨ ــﻮع اﳊ ــﺮﰲ‪ ،‬أﻣ ــﺎ اﻟﻌﻨ ـﻮان ‪ staddress‬ﻓﻬ ــﻮ ﻣ ــﻦ ﳕ ــﻂ‬
‫‪ address‬و ﺗﺎرﻳﺦ اﳌﻴﻼد وﺗﺎرﻳﺦ اﻟﻮﻻدة ‪ birthday‬و ‪ inscription‬ﻓﻬﻲ ﻣﻦ ﳕﻂ ‪ date‬ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪struct student‬‬
‫{‬
‫;][‪char name‬‬
‫;][‪char department‬‬

‫‪٧-١‬‬
‫;‪address stadsress‬‬
‫;‪date birthday, inscription‬‬
‫;}‬

‫‪ -٣-٤-١‬اﻟﻮﺻﻮل إﻟﻰ ﺣﻘﻮل ﺳﺠﻼت‬


‫ﻳــﺘﻢ اﻟﻮﺻــﻮل إﱃ ﺣﻘــﻮل اﻟﺒﻴﺎﻧــﺎت ﰲ اﻟﺴــﺠﻞ ﺑﺎﺳــﺘﺨﺪام اﻟﻨﻘﻄــﺔ "‪ ".‬اﻟــﱵ ﺗﻔﺼــﻞ ﺑــﲔ اﺳــﻢ اﳌﺘﻐــﲑ‬
‫ﻣﻦ ﳕﻂ اﻟﺴﺠﻞ واﳊﻘﻞ ﰲ اﻟﺴﺠﻞ اﳌﻌﺮف‪ .‬ﺑﻔﺮض أﻧﻨﺎ ﻗﻤﻨﺎ ﺑﺘﻌﺮﻳﻒ ﺳﺠﻞ اﻟﻮﻗﺖ ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪struct time‬‬
‫{‬
‫;‪int hour‬‬
‫;‪int minute‬‬
‫;‪int second‬‬
‫;}‬
‫وﺑﻔﺮض ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑ ﻣﻦ ﳕﻂ ‪ time‬ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;‪time the_time‬‬
‫ﻓﺈﻧﻪ ﻳﺘﻢ اﻟﻮﺻﻮل إﱃ ﻛﻞ ﺣﻘﻞ ﻣﻦ اﳊﻘﻮل ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;‪the_time.hour‬‬
‫;‪the_time.minute‬‬
‫;‪the_time.second‬‬
‫وﻳﺘﻢ اﻟﺘﻌﺎﻣﻞ ﻣﻌﻬﺎ ﻛﻤﺘﻐﲑات ﻣﻦ أﳕﺎﻃﻬﺎ اﻷﺳﺎﺳﻴﺔ اﻟﱵ ﰎ ﺗﻌﺮﻳﻔﻬﺎ ﰲ اﻟﺴﺠﻞ ‪.time‬‬
‫‪ -٤-٤-١‬ﺗﻤﺮﻳﺮ اﻟﺴﺠﻼت إﻟﻰ اﻹﺟﺮاءات ﻛﻮﺳﻄﺎء ﻓﻌﻞ‬
‫ﻗﺪ ﳓﺘﺎج ﰲ ﻛﺜﲑ ﻣـﻦ اﻷﺣﻴـﺎن ﲤﺮﻳـﺮ اﻟﺒﻴﺎﻧـﺎت اﳌﻌﺮﻓـﺔ ﻋﻠـﻰ ﺷـﻜﻞ ﺳـﺠﻼت إﱃ اﻹﺟـﺮاءات اﳌﻌﺮﻓـﺔ‬
‫ﻣﺴـﺒﻘﺔ ﺑﻠﻐـﺔ ‪) Visual C++‬أو اﻹﺟـﺮاءات اﻟـﱵ ﻧﻌﺮﻓﻬـﺎ داﺧـﻞ اﻟﱪﻧـﺎﻣﺞ‪ ،‬وﺳـﻨﺮى ﻛﻴﻔﻴـﺔ اﻟﺘﺼـﺮﻳﺢ ﻋـﻦ ﻫـﺬﻩ‬
‫اﻹﺟﺮاءات ﻻﺣﻘﺎً(‪ .‬ﻳـﺘﻢ ﲤﺮﻳـﺮ ﻫـﺬﻩ اﻟﺒﻴﺎﻧـﺎت ﺑﺎﻟﻘﻴﻤـﺔ‪ ،‬ﺣﻴـﺚ ﲤـﺮر ﻧﺴـﺨﺔ ﻣـﻦ اﻟﺒﻴﺎﻧـﺎت إﱃ اﻹﺟـﺮاء وﻣـﻦ ﰒ‬
‫ﻻ ﳝﻜﻦ ﻟﻺﺟﺮاء أن ﻳﺒﺪل ﳏﺘﻮﻳﺎت اﻟﺴﺠﻞ اﻷﺳﺎﺳﻲ‪.‬‬
‫ﻣﺜﺎل ‪٥-١‬‬
‫ﻓﻴﻤــﺎ ﻳــﺄﰐ ﺑﺮﻧــﺎﻣﺞ ﻳﻌﻤــﻞ ﻋﻠــﻰ ﻗ ـﺮاءة ﺗــﻮﻗﻴﺘﲔ ﳐﺘﻠﻔــﲔ وﻳﺴــﺘﺪﻋﻲ داﻟﺘــﲔ ﲢــﺪدان أي ﻣــﻦ اﻟﺘــﻮﻗﻴﺘﲔ‬
‫ﻳﺄﰐ ﻗﺒﻞ اﻵﺧﺮ‪:‬‬
‫>‪#include <iostream.h‬‬
‫‪struct time‬‬
‫{‬
‫;‪int hour‬‬
‫;‪int minut‬‬

‫‪٨-١‬‬
int second;
};

time max(time t1, time t2);


void main()
{
time tim1, tim2, tim3;
cout<<"Tim1.hour:"; cin>>tim1.hour;
cout<<"Tim1.minut:"; cin>>tim1.minut;
cout<<"Tim1.second:"; cin>>tim1.second;
cout<<"Tim2.hour:"; cin>>tim2.hour;
cout<<"Tim2.minut:"; cin>>tim2.minut;
cout<<"Tim2.second:"; cin>>tim2.second;
tim3=max(tim1,tim2);
cout<<"hour:"<<tim3.hour<<endl;
cout<<"minut:"<<tim3.minut<<endl;
cout<<"second:"<<tim3.second<<endl;
}

time max(time t1, time t2)


{
if (t1.hour>t2.hour) return t1;
else if(t1.hour<t2.hour) return t2;
else if (t1.minut>t2.minut) return t1;
else if (t1.minut<t2.minut) return t2;
else if (t1.second>t2.second) return t1;
else if (t1.second<t2.second) return t2;
}

‫ ﻣﺆﺷﺮات اﻟﺴﺠﻼت‬-٥-٤-١
‫ﻳــﺘﻢ اﻟﺘﺼ ـﺮﻳﺢ ﻋــﻦ ﻣﺆﺷ ـﺮات اﻟﺴــﺠﻼت ﺑﺎﻟﻄﺮﻳﻘــﺔ ﻧﻔﺴــﻬﺎ اﻟــﱵ ﻳــﺘﻢ اﻟﺘﺼ ـﺮﻳﺢ ﻓﻴﻬــﺎ ﻋــﻦ ﻣﺆﺷ ـﺮات‬
"->" arrow ‫ وﳝﻜﻦ اﻟﻮﺻـﻮل إﱃ ﺣﻘـﻮل اﻟﺴـﺠﻞ ﺑﺎﺳـﺘﺨﺪام اﳌﺆﺷـﺮ اﻟﺴـﻬﻢ‬.‫اﳌﺘﻐﲑات ﻣﻦ اﻟﻨﻤﻂ اﻟﻘﻴﺎﺳﻲ‬
‫ ﻋﻨـﺪ اﻟﺘﺼـﺮﻳﺢ ﻋـﻦ ﺳـﺠﻞ اﻟﻮﻗـﺖ‬.‫ﺑﺪﻻً ﻣـﻦ اﻟﻨﻘﻄـﺔ اﻟـﱵ ﺗﺴـﺘﺨﺪم ﰲ أﺛﻨـﺎء اﻟﺘﺼـﺮﻳﺢ ﻋﻨﻬـﺎ ﺑﺎﻟﺸـﻜﻞ اﻟﻌـﺎدي‬
:‫ﺑﺎﻟﺸﻜﻞ‬
struct time
{
int hour;
int minute;
int second;
٩-١
‫;}‬
‫وﺑﻔﺮض ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑ ﻣﺆﺷﺮ ﻣﻦ ﳕﻂ ‪ time‬ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;‪time *the_time‬‬
‫ﻓﺈﻧﻪ ﻳﺘﻢ اﻟﻮﺻﻮل إﱃ ﻛﻞ ﺣﻘﻞ ﻣﻦ اﳊﻘﻮل ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;‪the_time->hour‬‬
‫;‪the_time->minute‬‬
‫;‪the_time->second‬‬

‫‪ -٦-٤-١‬ﺗﻤﺮﻳﺮ اﻟﺴﺠﻼت إﻟﻰ اﻹﺟﺮاءات ﺑﺎﻟﻌﻨﺎوﻳﻦ‬


‫ﻟﻘــﺪ ذﻛﺮﻧــﺎ ﺳــﺎﺑﻘﺎً أن ﻋﻤﻠﻴــﺔ ﲤﺮﻳــﺮ اﻟﺒﻴﺎﻧــﺎت ﺑﺸــﻜﻞ ﻋــﺎم إﱃ اﻹﺟ ـﺮاءات ﺗﺴــﻤﺢ ﺑﺎﻻﺳــﺘﻐﻨﺎء ﻋــﻦ‬
‫ﺗﻜــﻮﻳﻦ ﻧﺴــﺨﺔ إﺿــﺎﻓﻴﺔ ﻣــﻦ اﻟﺒﻴﺎﻧــﺎت اﳌـﺮاد ﻣﻌﺎﳉﺘﻬــﺎ ﰲ اﻹﺟـﺮاءات‪ ،‬وﲟــﺎ أﻧــﻪ ﳝﻜﻨﻨــﺎ اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ اﻟﺴــﺠﻼت‬
‫اﳌﻌﺮﻓﺔ ﺑﺎﺳﺘﺨﺪام اﳌﺆﺷﺮات ﻟﺬا ﳝﻜﻨﻨﺎ أﻳﻀﺎً ﲤﺮﻳﺮﻫﺎ ﺑﺎﳌﺆﺷﺮات ﻛﻤﺎ ﻳﺒﻴﻨﻪ اﳌﺜﺎل اﻵﰐ‪.‬‬
‫ﻣﺜﺎل ‪٦-١‬‬
‫ﺳﻨﻌﻴﺪ ﻛﺘﺎﺑﺔ أواﻣﺮ اﻟﱪﻧﺎﻣﺞ ﰲ اﳌﺜﺎل ‪ ٥-١‬ﺑﺎﺳﺘﺨﺪام اﳌﺆﺷﺮات وﲤﺮﻳﺮ اﻟﺴﺠﻼت ﺑﺎﳌﺆﺷﺮات‪:‬‬
‫>‪#include <iostream.h‬‬
‫‪struct time‬‬
‫{‬
‫;‪int hour‬‬
‫;‪int minut‬‬
‫;‪int second‬‬
‫;}‬

‫;)‪time *max(time *t1, time *t2‬‬

‫)(‪void main‬‬
‫{‬
‫;‪time *tim1, *tim2, *tim3‬‬
‫;‪tim1=new time‬‬
‫;‪tim2=new time‬‬
‫;‪cout<<"Tim1->hour:"; cin>>tim1->hour‬‬
‫;‪cout<<"Tim1->minut:"; cin>>tim1->minut‬‬
‫;‪cout<<"Tim1->second:"; cin>>tim1->second‬‬
‫;‪cout<<"Tim2->hour:"; cin>>tim2->hour‬‬
‫;‪cout<<"Tim2->minut:"; cin>>tim2->minut‬‬
‫;‪cout<<"Tim2->second:"; cin>>tim2->second‬‬
‫;)‪tim3=max(tim1,tim2‬‬

‫‪١٠-١‬‬
‫;‪cout<<"hour:"<<tim3->hour<<endl‬‬
‫;‪cout<<"minut:"<<tim3->minut<<endl‬‬
‫;‪cout<<"second:"<<tim3->second<<endl‬‬
‫}‬

‫)‪time *max(struct time *t1, struct time *t2‬‬


‫{‬
‫;‪if (t1->hour>t2->hour) return t1‬‬
‫;‪else if(t1->hour<t2->hour) return t2‬‬
‫;‪else if (t1->minut>t2->minut) return t1‬‬
‫;‪else if (t1->minut<t2->minut) return t2‬‬
‫;‪else if (t1->second>t2->second) return t1‬‬
‫;‪else if (t1->second<t2->second) return t2‬‬
‫}‬
‫‪max‬‬ ‫ــﺬﻩ اﻟﻄﺮﻳﻘــﺔ ﺳــﻴﺘﻢ ﻧﻘــﻞ ﻋﻨــﺎوﻳﻦ اﻟﺴــﺠﻼت ﰲ اﻟــﺬاﻛﺮة ‪ tim1‬و ‪ tim2‬ﻛﻮﺳــﻄﺎء ﻓﻌــﻞ إﱃ اﻹﺟ ـﺮاء‬
‫وﻟــﻴﺲ ﺑﻴﺎﻧــﺎت ﻫــﺬﻩ اﻟﺴــﺠﻼت ﻛﻤــﺎ ﰲ اﳌﺜــﺎل اﻟﺴــﺎﺑﻖ‪ ،‬واﻟﻘﻴﻤــﺔ اﳌﻌــﺎدة أﻳﻀ ـﺎً ﻫــﻲ ﻋﻨ ـﻮان اﻟﺴــﺠﻞ اﻷﻛــﱪ‬
‫وﻟﻴﺲ ﺑﻴﺎﻧﺎت ﻫﺬا اﻟﺴﺠﻞ‪.‬‬
‫‪ -٧-٤-١‬ﺗﻜﻮﻳﻦ ﻣﺼﻔﻮﻓﺔ ﻣﻦ اﻟﺴﺠﻼت‬
‫ﻟﻘ ــﺪ ذﻛﺮﻧ ــﺎ ﺳ ــﺎﺑﻘﺎً أن اﻟﺴ ــﺠﻼت اﳌﻌﺮﻓ ــﺔ ﺑ ــﺎﻷﻣﺮ ‪ struct‬ﺗﺴ ــﺘﺨﺪم ﻛﺎﺳ ــﺘﺨﺪام اﻷﳕ ــﺎط اﻟﻘﻴﺎﺳ ــﻴﺔ‬
‫ﻟﻠﺒﻴﺎﻧ ــﺎت‪ ،‬وﺑ ــﺬﻟﻚ ﳝﻜﻨﻨ ــﺎ اﺳ ــﺘﺨﺪاﻣﻬﺎ ﻟﺘﻌﺮﻳ ــﻒ ﻣﺼ ــﻔﻮﻓﺔ ﻣ ــﻦ اﻟﺴ ــﺠﻼت ﻛﻤ ــﺎ ﳝﻜﻨﻨ ــﺎ ﺗﻌﺮﻳ ــﻒ ﺳ ــﺠﻞ ﻣ ــﻦ‬
‫اﳌﺼﻔﻮﻓﺎت‪ .‬ﳝﻜﻨﻨﺎ ﻋﻠﻰ ﺳﺒﻴﻞ اﳌﺜﺎل ﺗﻌﺮﻳﻒ ﺳﺠﻞ ﻣﻜﻮن ﻣﻦ ﺛﻼث ﻣﺼﻔﻮﻓﺎت ﺷﻌﺎع ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪struct matrix‬‬
‫{‬
‫;]‪int mat1[100‬‬
‫;]‪float mat2[100‬‬
‫;]‪char mat3[100‬‬
‫;}‬
‫وﺑﺎﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺘﻐﲑ ﻣﻦ اﻟﻨﻤﻂ ‪ matrix‬ﺑﺎﻟﺸﻜﻞ‪:‬‬
‫;‪matrix matrix1‬‬
‫ﳝﻜﻨﻨﺎ اﻟﺪﺧﻮل إﱃ ﻋﻨﺎﺻﺮ ﻫﺬﻩ اﻟﺴﺠﻼت ﺑﺎﻷﺷﻜﺎل اﻵﺗﻴﺔ‪:‬‬
‫‪matrix1.mat1[0], matrix1.mat2[0], matrix1.mat3[0],‬‬
‫‪matrix1.mat1[1], matrix1.mat2[1], matrix1.mat3[1],‬‬
‫‪……..‬‬
‫‪……...‬‬
‫أﻣﺎ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺼﻔﻮﻓﺔ ﺳﺠﻼت ﻣﻦ اﻟﻨﻤﻂ ﻧﻔﺴﻪ ﺑﺎﻟﺸﻜﻞ‪:‬‬

‫‪١١-١‬‬
‫‪struct matrix‬‬
‫{‬
‫;‪int mat1‬‬
‫;‪float mat2‬‬
‫;‪char mat3‬‬
‫;}‬
‫ﳝﻜﻨﻨﺎ ﻣﻦ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺼﻔﻮﻓﺔ ﺳﺠﻼت ﺑﺒﻌﺪ واﺣﺪ أو ﺑﻌﺪة أﺑﻌﺎد ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;]‪matrix matrix1[100‬‬
‫واﻟﻮﺻﻞ إﱃ ﺣﻘﻮل اﻟﺴﺠﻼت ﻳﺘﻢ ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪matrix1[0].mat1, matrix1[0].mat2, matrix1[0].mat3,‬‬
‫‪matrix1[1].mat1, matrix1[1].mat2, matrix1[1].mat3,‬‬
‫‪……..‬‬
‫‪……..‬‬

‫‪Visual C++‬‬ ‫‪ -٥-١‬اﻟﻠﻮاﺋﺢ اﻟﻤﺘﺮاﺑﻄﺔ ‪ Linked List‬ﺑﻠﻐﺔ‬


‫ﺗﺴــﺘﺨﺪم اﻟﻠ ـﻮاﺋﺢ اﳌﱰاﺑﻄــﺔ ﺑﺸــﻜﻞ ﻛﺒــﲑ ﰲ اﻟﱪﳎــﺔ وﺣــﻞ ﳌﺴــﺎﺋﻞ ﺑﺎﺳــﺘﺨﺪام اﳊﺎﺳــﻮب‪ ،‬وﻛﺜ ـﲑاً ﻣــﺎ‬
‫ﻧﺼﺎدف ﰲ ﺣﻴﺎﺗﻨﺎ اﻟﻴﻮﻣﻴﺔ ﻣﺜﻞ ﻫﺬﻩ اﻟﻠﻮاﺋﺢ ﻛﻼﺋﺤﺔ ﻋﻨﺎوﻳﻦ وﻻﺋﺤﺔ أﺷﻴﺎء وﻻﺋﺤﺔ أﲰﺎء وﻫﻜﺬا‪....‬‬
‫ﺗﻌﺮف اﻟﻼﺋﺤﺔ اﳌﱰاﺑﻄﺔ ﺑﺮﳎﻴﺎً ﲟﺠﻤﻮﻋﺔ ﻣﺘﺠﺎﻧﺴﺔ ﻣﻦ اﻟﺒﻴﺎﻧـﺎت ﻣﱰاﺑﻄـﺔ ﻓﻴﻤـﺎ ﺑﻴﻨﻬـﺎ ﺑﺸـﻜﻞ ﺧﻄـﻲ‪.‬‬
‫ﻳﺴــﻤﻰ ﻛــﻞ ﻋﻨﺼــﺮ ﻣــﻦ ﻋﻨﺎﺻــﺮ اﻟﻼﺋﺤــﺔ ﺑﺎﻟﻌﻘــﺪة ‪ ،Node‬وﺗﻌــﲏ اﻟﻌﻼﻗــﺔ اﳋﻄﻴــﺔ ﻋﻠــﻰ اﳌﺴــﺘﻮى اﳌﻨﻄﻘــﻲ ﻫﻨــﺎ‬
‫ﺑــﲔ ﻫــﺬﻩ اﻟﻌﻨﺎﺻــﺮ ﺑــﺄن ﻟﻜــﻞ ﻋﻨﺼــﺮ ﻋــﺪا اﻷول ﰲ اﻟﻼﺋﺤــﺔ ﻟــﻪ ﺳ ـﻠﻒ ‪ Predecessor‬وﻟﻜــﻞ ﻋﻨﺼــﺮ ﻋــﺪا‬
‫اﻷﺧــﲑ ﰲ اﻟﻼﺋﺤــﺔ ﻟــﻪ ﺧﻠــﻒ ‪ .Successor‬وﻫــﻲ ﻣﱰاﺑﻄــﺔ أﻳﻀـﺎً ﻣــﻦ اﻟﻨﺎﺣﻴــﺔ اﻟﻔﻴﺰﻳﺎﺋﻴــﺔ إﳕــﺎ ﺑﺄﺳــﻠﻮب ﳐﺘﻠــﻒ‬
‫ﻋﻦ أﺳﻠﻮب ﺗﺮاﺑﻄﻬﺎ ﻣﻦ اﻟﻨﺎﺣﻴﺔ اﳌﻨﻄﻘﻴﺔ‪ .‬ﻟﻜﻞ ﺳﻠﺴﻠﺔ ﻋﺪد ﳏﺪد ﻣﻦ اﻟﻌﻨﺎﺻﺮ ﻳﻌﺮف ﺑﻄﻮل اﻟﺴﻠﺴﻠﺔ‪.‬‬
‫ﻟﻠﻮاﺋﺢ اﳌﱰاﺑﻄﺔ ﻋﺪة أﺷﻜﺎل ﻣﻨﻬﺎ اﻷﺣﺎدﻳـﺔ واﻟﺜﻨﺎﺋﻴـﺔ‪ ،‬ﻛﻤـﺎ أن ﻟﻜـﻞ ﻧـﻮع ﻣـﻦ ﻫـﺬﻩ اﻟﻠـﻮاﺋﺢ ﳎﻤﻮﻋـﺔ‬
‫ﻣــﻦ اﻟﻌﻤﻠﻴــﺎت اﻟﻌﺎﻣــﺔ اﻟــﱵ ﳝﻜــﻦ ﺗﻄﺒﻴﻘﻬــﺎ ﻋﻠﻴﻬــﺎ ﻛﺈﺿــﺎﻓﺔ ﻋﻨﺼــﺮ وﺣــﺬف ﻋﻨﺼــﺮ وﺗﺮﺗﻴــﺐ ﻋﻨﺎﺻــﺮ ﻻﺋﺤــﺔ‬
‫واﻟﺘﻨﻘــﻞ ﺿــﻤﻦ ﻋﻘــﺪﻫﺎ‪ .‬ﺳــﻨﺒﲔ ﻓﻴﻤــﺎ ﻳــﺄﰐ ﻧــﻮﻋﲔ ﻣــﻦ اﻟﻠـﻮاﺋﺢ اﻷﺣﺎدﻳــﺔ واﻟﺜﻨﺎﺋﻴــﺔ وﺑﻌــﺾ اﻟﺘﻄﺒﻴﻘــﺎت اﻟﱪﳎﻴــﺔ‬
‫ﻋﻠﻰ ﻫﺬﻩ اﻟﻠﻮاﺋﺢ‪.‬‬
‫ﺗﻨﻈﻢ اﻟﻼﺋﺤـﺔ اﳌﱰاﺑﻄـﺔ ﰲ اﻟـﺬاﻛﺮة اﻟﺪاﺧﻠﻴـﺔ ﻟﻠﺤﺎﺳـﻮب ‪ RAM‬وأرﻗـﺎم اﻟﺴـﺠﻼت ﻫـﻲ ﻋﻨـﺎوﻳﻦ ﰲ‬
‫اﻟﺬاﻛﺮة ﺗﻌﻄﻰ ﺗﻠﻘﺎﺋﻴﺎً ﰲ أﺛﻨﺎء اﻟﺘﻌﺎﻣﻞ ﻣـﻊ اﳌﺆﺷـﺮات ‪ .Pointers‬ﺗﺘﻜـﻮن ﻛـﻞ ﻋﻘـﺪة إذاً ﰲ اﻟﻼﺋﺤـﺔ اﳌﱰاﺑﻄـﺔ‬
‫ﻣﻦ ﳎﻤﻮﻋﺔ ﺑﻴﺎﻧﺎت إﺿﺎﻓﺔ إﱃ ﻣﺆﺷﺮ ﻳﺪل ﻋﻠﻰ ﻋﻨﻮان اﻟﻌﻘﺪة اﻵﺗﻴﺔ ﻛﻤﺎ ﰲ اﻟﺸﻜﻞ ‪.٢-١‬‬

‫‪١٢-١‬‬
‫‪Data‬‬ ‫ﺑﻴﺎﻧﺎت اﻟﻌﻘﺪة‬ ‫ﻣﺆﺷﺮ إﱃ اﻟﻌﻘﺪة اﻟﺘﺎﻟﻴﺔ‬
‫‪Node‬‬ ‫‪Pointer Node‬‬

‫اﻟﺸﻜﻞ ‪ ٢-١‬ﺗﻨﻈﻴﻢ ﺑﻴﺎﻧﺎت ﻋﻘﺪة‬


‫‪Data Node‬‬ ‫ﻛـﻞ ﻋﻨﺼــﺮ ﻣــﻦ ﻋﻨﺎﺻــﺮ اﻟﻼﺋﺤــﺔ )ﻛــﻞ ﻋﻘــﺪة ‪ (node‬ﻫــﻮ ﺳــﺠﻞ ﻣﻜــﻮن ﻣــﻦ ﺑﻴﺎﻧــﺎت اﻟﻌﻘــﺪة‬
‫إﺿﺎﻓﺔ إﱃ ﻣﺆﺷﺮ اﻟﻌﻘـﺪة ‪ ،Pointer Node‬ﻳﺄﺧـﺬ اﳌﺆﺷـﺮ اﻟﻘﻴﻤـﺔ ‪ NULL‬ﰲ ﺎﻳـﺔ اﻟﻼﺋﺤـﺔ‪ .‬أي أن اﻟﻌﻘـﺪة‬
‫اﻟﻮاﺣﺪة ﻫﻲ ﺳﺠﻞ ﻳﺄﺧﺬ اﲰﺎً ﳏﺪداً وﻣﻜﻮﻧﺎً ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪Node_Name=Node‬‬
‫‪Data Node‬‬
‫‪Pointer Node‬‬
‫‪End‬‬
‫ﰲ اﻟﻮاﻗﻊ‪ ،‬ﻟﻘﺪ رأﻳﻨﺎ ﺳﺎﺑﻘﺎً ﻋﻨﺪ اﳊﺪﻳﺚ ﻋـﻦ اﻟﺴـﺠﻼت ﺑﻠﻐـﺔ ‪ Visual C++‬أن ﻋﻨﺎﺻـﺮ اﻟﺴـﺠﻞ‪،‬‬
‫أي اﳊﻘــﻮل‪ ،‬ﻣــﺎ ﻫــﻲ إﻻ ﺑﻴﺎﻧــﺎت ﻣــﻦ اﻷﳕــﺎط اﻟﻘﻴﺎﺳــﻴﺔ اﳌﻌﺮﻓــﺔ ﻣﺴــﺒﻘﺎً أو ﻣــﺎ ﻳﻌﺮﻓــﻪ اﳌﺴــﺘﺨﺪم ﻋﻠــﻰ ﺷــﻜﻞ‬
‫ﺳﺠﻼت‪ ،‬وﻫﺬا ﻣﺎ ﻳﺴﻤﺢ ﺑﺎﻟﺘﻌﺮﻳﻒ ﻋﻦ ﺣﻘﻮل ﰲ اﻟﺴﺠﻞ ﻛﻤﺆﺷﺮات ﻟﺴﺠﻼت ﻣﻦ ﳕﻂ اﻟﺴﺠﻞ ﻧﻔﺴـﻪ‪.‬‬
‫وﻫﺬا ﻣـﺎ ﻳﺴـﻤﺢ ﺑﺘﻌﺮﻳـﻒ ﺑﻴﺎﻧـﺎت اﻟﺴـﺠﻞ إﺿـﺎﻓﺔ إﱃ ﻣﺆﺷـﺮ ﻳـﺪل ﻋﻠـﻰ ﺑﻴﺎﻧـﺎت ﺳـﺠﻞ ﻻﺣـﻖ وﻫﻜـﺬا‪....‬أو‬
‫ﻣﺎ ﳝﻜﻦ اﻟﺘﺼﺮﻳﺢ ﻋﻨﻪ ﺑﻠﻐﺔ ‪ Visual C++‬ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪struct tag_field‬‬
‫{‬
‫;‪member_type member1‬‬
‫;‪member_type member2‬‬
‫‪……………………….‬‬
‫;‪tag_field *successor‬‬
‫;}‬
‫ﺣﻴﺚ ‪ successor‬ﻳﺸﲑ إﱃ ﺳﺠﻞ ﺟﺪﻳﺪ‪.‬‬
‫ﺗـﺘﻢ ﻋﻤﻠﻴـﺔ اﻟـﺮﺑﻂ ﺑـﲔ ﺑﻴﺎﻧـﺎت اﻟﻼﺋﺤـﺔ ﻣـﻦ ﺧـﻼل ﻣﺆﺷـﺮ اﻟﻌﻘـﺪة ‪ Pointer Node‬اﻟـﺬي ﻳﺸـﲑ إﱃ‬
‫اﻟﻌﻨ ـﻮان ﰲ اﻟــﺬاﻛﺮة اﻟــﺬي ﻳﺘﻀــﻤﻦ ﺑﻴﺎﻧــﺎت اﻟﻌﻘــﺪة اﻟﺘﺎﻟﻴــﺔ‪ .‬وﳍــﺬا ﳚــﺐ ﻋﻨــﺪ ﺗﻜــﻮﻳﻦ ﻋﻘــﺪة ﺟﺪﻳــﺪة ﻣﻌﺮﻓــﺔ‬
‫اﻟﻌﻨـﻮان اﳌﺨﺼــﺺ ﻟﺘﺨـﺰﻳﻦ ﺑﻴﺎﻧــﺎت اﻟﻌﻘــﺪة‪ .‬ﳜﺼــﺺ ﻣﻮﻗــﻊ ﺗﻜــﻮﻳﻦ اﻟﻌﻘــﺪة اﳉﺪﻳــﺪة ﺗﻠﻘﺎﺋﻴـﺎً ﻣــﻦ ﻗﺒــﻞ أﻏﻠــﺐ‬
‫ﻟﻐــﺎت اﻟﱪﳎــﺔ ﰲ أﺛﻨــﺎء اﻟﺘﺼ ـﺮﻳﺢ ﻋــﻦ ﻋﻘــﺪة ﺟﺪﻳــﺪة )ﺳــﺠﻞ(‪ ،‬وﻫــﺬا ﻣــﺎ ﻳﺴــﻤﺢ ﺑﺘﻜــﻮﻳﻦ اﻟﻠ ـﻮاﺋﺢ اﳌﱰاﺑﻄــﺔ‬
‫‪ .Linked List‬وﻧﺸﲑ ﻫﻨﺎ إﱃ أﻧﻪ ﻻ ﳝﻜﻦ ﺗﻜﻮﻳﻦ اﻟﻠﻮاﺋﺢ اﳌﱰاﺑﻄﺔ ﺑﺎﺳﺘﺨﺪام ﻟﻐـﺎت اﻟﱪﳎـﺔ اﻟـﱵ ﻻ ﺗﺴـﻤﺢ‬
‫ﺑﺎﻟﺘﻌﺎﻣــﻞ ﻣــﻊ ﺑﻴﺎﻧــﺎت ﻣــﻦ ﻧــﻮع اﳌﺆﺷـﺮات ‪ ،Pointer‬ﻣﺜــﻞ ﺑﻌــﺾ اﻹﺻــﺪارات ﻣــﻦ ﻟﻐــﺔ ‪ Basic‬إﻻ ﺑﺎﺳــﺘﺨﺪام‬
‫ﻃﺮاﺋﻖ ﺧﺎﺻﺔ ﻗﺪ ﻻ ﺗﻜﻮن داﺋﻤﺎً ﻓﻌﺎﻟﺔ‪ ،‬وﻗﺪ رأﻳﻨﺎ أن ﻫﺬﻩ اﻟﻌﻤﻠﻴﺔ ﺗﻨﻔﺬ ﺑﻠﻐﺔ ‪ Visual C++‬ﺑﺎﻷﻣﺮ اﻵﰐ‪:‬‬

‫‪١٣-١‬‬
‫;‪new Node_Name‬‬
‫وﺑﺪاﻳﺔ اﻟﻼﺋﺤﺔ ﻣﺎ ﻫﻲ إﻻ ﻋﺒﺎرة ﻋﻦ ﻋﻘﺪة ﺟﺪﻳﺪة‪ ،‬وﳍـﺬا ﻧﺒـﺪأ ﺑﺘﻜـﻮﻳﻦ اﻟﻼﺋﺤـﺔ اﳉﺪﻳـﺪة ﺑـﺄﻣﺮ ﻣـﻦ اﻟﺸـﻜﻞ‬
‫اﻵﰐ‪:‬‬
‫;‪List_Name=new Node_Name‬‬
‫وﺗﺒﺪو اﻟﻼﺋﺤﺔ اﳌﱰاﺑﻄﺔ ﻛﻤﺎ ﰲ اﻟﺸﻜﻞ ‪:٣-١‬‬

‫ﺑﺪاﻳﺔ‬
‫اﻟﻼﺋﺤﺔ‬
‫ﺎﻳﺔ اﻟﻼﺋﺤﺔ‬

‫اﻟﺸﻜﻞ ‪ ٣-١‬ﻻﺋﺤﺔ ﻣﱰاﺑﻄﺔ‬

‫ﻣﺜﺎل ‪٧-١‬‬
‫ﻟــﺘﻜﻦ ﻟــﺪﻳﻨﺎ ﳎﻤﻮﻋــﺔ ﺑﻴﺎﻧــﺎت ﺗﺘﻀــﻤﻦ أﲰــﺎء ﻋﺸــﺮة ﻃــﻼب‪ ،‬ﺣﻴــﺚ ﺗﺘﻀــﻤﻦ ﻫــﺬﻩ اﻟﺒﻴﺎﻧــﺎت‪ :‬اﺳــﻢ‬
‫اﻟﻄﺎﻟﺐ ‪ Name‬ورﻗﻤﻪ ‪ Id_Number‬وﳘﺎ ﻋﻠﻰ ﺷﻜﻞ ﺳﻼﺳﻞ ﺣﺮﻓﻴﺔ‪.‬‬
‫‪Name‬‬ ‫ﻟﺘﻜــﻮﻳﻦ ﻻﺋﺤــﺔ ﻣﱰاﺑﻄــﺔ ﻣــﻦ ﻫــﺬﻩ اﻟﺒﻴﺎﻧــﺎت ﺳــﻨﻘﻮم ﺑﺘﻌﺮﻳــﻒ ﻋﻘــﺪة ﺗﺘﻀــﻤﻦ اﺳــﻢ اﻟﻄﺎﻟــﺐ‬
‫ورﻗﻤﻪ ‪ Id_Number‬إﺿﺎﻓﺔ إﱃ ﻣﺆﺷﺮ ‪ Pointer‬ﺑﺎﺳﻢ ‪ Successor‬ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫>‪#include <iostream.h‬‬
‫‪struct Student‬‬
‫{‬
‫;]‪char Name[50‬‬
‫;]‪char Id_Number[6‬‬
‫;‪Student *Successor‬‬
‫;}‬
‫)(‪void main‬‬
‫{‬
‫;‪int i‬‬
‫;‪Student *List_Student, *L‬‬
‫;‪L=new Student‬‬
‫;‪List_Student=L‬‬
‫)‪for (i=1;i<=10;i++‬‬
‫{‬
‫;"‪cout<<"Name:‬‬
‫;‪cin>> L->Name‬‬
‫;"‪cout<<"Id_Number:‬‬
‫;‪cin>> L->Id_Number‬‬
‫;‪L ->Successor=NULL‬‬

‫‪١٤-١‬‬
‫;‪L=L->Successor‬‬
‫}‬
‫}‬
‫‪*L-‬‬ ‫اﻟﻌﻨ ـ ـﻮان اﳌﺨﺼـ ــﺺ ﻟﻠﻌﻘـ ــﺪة اﳉﺪﻳـ ــﺪة ﻫـ ــﻮ ‪ .*L‬أﻣـ ــﺎ ﺑﻴﺎﻧـ ــﺎت اﻟﻌﻘـ ــﺪة ﻓﻬـ ــﻲ ‪ *L->Name‬و‬
‫‪ >Id_Number‬اﻟﻠﺘــﺎن ﺗﺸ ـﲑان ﻋﻠــﻰ اﻟﺘ ـﻮاﱄ إﱃ اﺳــﻢ اﻟﻄﺎﻟــﺐ ورﻗﻤــﻪ‪ ،‬أﻣــﺎ ﻋﻨ ـﻮان اﻟﻌﻘــﺪة اﻟﺘﺎﻟﻴــﺔ ﻓﻬــﻮ ‪*L-‬‬
‫‪ .>Successor‬ﻋﻨﺪ اﻟﻌﻘﺪة اﻟﺘﺎﻟﻴﺔ ﺗﻌﻤﺪﻧﺎ وﺿﻊ اﻟﻘﻴﻤﺔ ‪ NULL‬اﻟـﱵ ﺗﺸـﲑ إﱃ ﻻ ﺷـﻲء ﳍـﺬا ﻗﻤﻨـﺎ ﺑﺎﺧﺘﺒـﺎر‬
‫ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ﻫﺬﻩ اﻟﻌﻘﺪة ﻫﻲ اﻷﺧﲑة ﻟﺘﻼﰲ اﻟﻮﻗﻮع ﺑﺎﳋﻄﺄ ﺑﺘﻜﻮﻳﻦ ﻋﻘﺪة إﺿﺎﻓﻴﺔ ﻓﺎرﻏﺔ‪.‬‬

‫‪١٥-١‬‬
‫تطبيقات‬

‫ﺗﻄﺒﻴﻖ ‪:١‬‬
‫ﻋ ـ ــﺮف ﺳ ـ ــﺠﻼً ﺑﻠﻐ ـ ــﺔ ‪ Visual C++‬ﺑﺎﺳ ـ ــﻢ ‪ Client‬ﻟﺘﻤﺜﻴـ ـ ــﻞ زﺑ ـ ــﻮن ﻳﺘﻀ ـ ــﻤﻦ‪ :‬اﺳ ـ ــﻢ اﻟﺰﺑ ـ ــﻮن‬
‫‪ Client_Name‬ورﻗﻤــﻪ ‪ Id_Number‬وﳘــﺎ ﻋﻠــﻰ ﺷــﻜﻞ ﺳﻼﺳــﻞ ﺣﺮﻓﻴــﺔ‪ .‬وﺑــﲔ ﻛﻴﻔﻴــﺔ اﻟﻮﺻــﻮل إﱃ ﺣﻘــﻮل‬
‫ﻫﺬا اﻟﺴﺠﻞ ﰲ ﺣﺎﻟﺔ اﻟﺘﺼﺮﻳﺢ ﻣﺘﻐﲑ ﻋﺎدي‪.‬‬
‫اﻟﺤﻞ‪:‬‬
‫‪struct Client‬‬
‫{‬
‫;]‪char Name[50‬‬
‫;]‪char Id_Number[6‬‬
‫;}‬
‫ﻋﻨﺪ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺘﻐﲑ ﻣﻦ اﻟﺸﻜﻞ‪:‬‬
‫;‪Client Clients‬‬
‫ﳝﻜﻨﻨﺎ اﻟﻮﺻﻮل إﱃ ﻛﻞ ﺣﻘﻞ ﻣﻦ ﺣﻘﻮل ﻫﺬا اﻟﺴﺠﻞ ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;‪Clients.Name‬‬
‫;‪Clients.Id_Number‬‬

‫ﺗﻄﺒﻴﻖ ‪:٢‬‬
‫ﻛﻮن ﻣﺼﻔﻮﻓﺔ ﻣﻦ اﳌﺆﺷﺮات ﻟﻠﺴـﺠﻞ اﳌﻌـﺮف ﺑﺎﻟﺴـﺆال اﻟﺴـﺎﺑﻖ وﺑـﲔ ﻛﻴﻔﻴـﺔ اﻟﻮﺻـﻮل إﱃ ﻛـﻞ ﺣﻘـﻞ‬
‫ﻣﻦ ﺣﻘﻮل اﻟﺴﺠﻞ ﻟﻌﻨﺎﺻﺮ ﻫﺬﻩ اﳌﺼﻔﻮﻓﺔ‪.‬‬
‫اﻟﺤﻞ‪:‬‬
‫ﻳﺘﻢ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺼﻔﻮﻓﺔ اﻟﻌﺪد اﻷﻋﻈﻤﻲ ﻟﻌﻨﺎﺻﺮﻫﺎ ‪ 100‬ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;]‪Client *Clients[100‬‬
‫أﻣﺎ ﻋﻨﺎﺻﺮ ﻫﺬﻩ اﳌﺼﻔﻮﻓﺔ وﺣﻘﻮل اﻟﺴﺠﻞ ﻓﻴﻤﻜﻦ اﻟﻮﺻﻮل إﻟﻴﻬﺎ ﺑﺎﻟﺸﻜﻞ‪:‬‬
‫;‪Clients[0]->Name‬‬
‫;‪Clients[0]->Id_Number‬‬

‫;‪Clients[1]->Name‬‬
‫;‪Clients[1]->Id_Number‬‬
‫‪…..‬‬
‫‪…..‬‬

‫‪١٦-١‬‬
‫;‪Clients[100]->Name‬‬
‫;‪Clients[100]->Id_Number‬‬

‫ﺗﻄﺒﻴﻖ ‪:٣‬‬
‫أﻋﺪ ﺗﻌﺮﻳﻒ اﻟﺴﺠﻞ اﻟﺴﺎﺑﻖ ﻻﺳﺘﺨﺪاﻣﻪ ﻛﻌﻘﺪة ﻟﺘﻤﺜﻴﻞ ﻻﺋﺤﺔ ﺧﻄﻴﺔ ﻣﻦ اﻟﺰﺑﺎﺋﻦ‪.‬‬
‫اﻟﺤﻞ‪:‬‬
‫ﳝﻜﻨﻨــﺎ إﻋــﺎدة ﺗﻌﺮﻳــﻒ ﻫــﺬا اﻟﺴــﺠﻞ ﻟﻜــﻲ ﻳﻜــﻮن ﻋﻘــﺪة ﰲ ﻻﺋﺤــﺔ ﺑﺈﺿــﺎﻓﺔ ﺣﻘــﻞ ﻋﻠــﻰ ﺷــﻜﻞ ﻣﺆﺷــﺮ‬
‫ﺑﺎﺳﻢ ‪ Successor‬ﻋﻠﻰ ﺳﺒﻴﻞ اﳌﺜﺎل إﱃ اﻟﺴﺠﻞ ﻧﻔﺴﻪ ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪struct Client‬‬
‫{‬
‫;]‪char Name[50‬‬
‫;]‪char Id_Number[6‬‬
‫;‪Client *Successor‬‬
‫;}‬

‫ﺗﻄﺒﻴﻖ ‪:٤‬‬
‫اﺳــﺘﺨﺪم ﺗﻌﺮﻳــﻒ اﻟﻌﻘــﺪة ﰲ اﻟﺘﻄﺒﻴــﻖ اﻟﺴــﺎﺑﻖ ﰲ ﺗﻜــﻮﻳﻦ ﻻﺋﺤــﺔ ﺧﻄﻴــﺔ ﻣﱰاﺑﻄــﺔ ‪ .List‬ﻣﺒﻴﻨ ـﺎً ﻛﻴﻔﻴــﺔ‬
‫اﺳﺘﺨﺪام اﻷﻣﺮ ‪.new‬‬
‫اﻟﺤﻞ‪:‬‬
‫ﳝﻜﻨﻨــﺎ اﻟﺘﺼ ـﺮﻳﺢ ﻋــﻦ ﻻﺋﺤــﺔ ﺧﻄﻴــﺔ ﻣــﻦ ﳕــﻂ ‪ Client‬ﺑﺘﻌﺮﻳــﻒ ﻣﺘﻐــﲑ ﻣﺆﺷــﺮ ﻟﺒﺪاﻳــﺔ اﻟﺴﻠﺴــﻠﺔ ﺑﺎﺳــﻢ‬
‫‪ List_of_Clients‬ﻋﻠﻰ ﺳﺒﻴﻞ اﳌﺜﺎل‪ ،‬وﺑﺎﺳﺘﺨﺪام اﻷﻣﺮ ‪ new‬اﻟﺬي ﻳﻜﻮن ﻣﺆﺷﺮ‪ ،‬ﺑﺎﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;‪Client *List_of_Clients‬‬
‫;‪List_of_Clients=new Client‬‬

‫‪١٧-١‬‬
:٥ ‫ﺗﻄﺒﻴﻖ‬
‫ ﰒ اﻛﺘﺐ اﻟﺘﻌﻠﻴﻤـﺎت اﻟﻼزﻣـﺔ ﻟﻘـﺮاءة‬1 ‫ ﺳﺠﻞ ﻛﻤﺎ ﻫﻮ ﻣﻌﺮف ﰲ اﻟﺘﻄﺒﻴﻖ‬1000 ‫ﻛﻮن ﻣﺼﻔﻮﻓﺔ ﻣﻦ‬
.‫ زﺑﻮن ﰲ ﻫﺬﻩ اﳌﺼﻔﻮﻓﺔ وﺗﺮﺗﻴﺒﻬﺎ ﺗﺮﺗﻴﺒﺎً ﺗﺼﺎﻋﺪﻳﺎً ﲝﺴﺐ اﻻﺳﻢ وﻃﺒﺎﻋﺘﻬﺎ‬n ‫ﺑﻴﺎﻧﺎت‬
:‫اﻟﺤﻞ‬
#include <iostream>
using namespace std;

struct Client
{
char Name[50];
char Id_Number[6];
};
Client Clients[1000],C;
void main()
{
int n;
cin>>n;
for (int i=1;i<=n;i++)
{
cin>>Clients[i].Name;
cin>>Clients[i].Id_Number;
}
for (int i=1;i<n;i++)
for (int j=i+1;j<=n;j++)
if (strcmp(Clients[i].Name,Clients[j].Name)==1)
{
C=Clients[i];
Clients[i]=Clients[j];
Clients[j]=C;
}
for (int i=1;i<=n;i++)
cout<<Clients[i].Name<<" "<<Clients[i].Id_Number<<endl;
}

١٨-١
:٦ ‫ﺗﻄﺒﻴﻖ‬
‫ زﺑـﻮن‬n ‫ ﰒ اﻛﺘـﺐ اﻟﺘﻌﻠﻴﻤـﺎت اﻟﻼزﻣـﺔ ﻟﻘـﺮاءة ﺑﻴﺎﻧـﺎت‬1 ‫ ﻣﺆﺷﺮ ﺳﺠﻞ ﻛﻤﺎ ﻫﻮ ﻣﻌﺮف ﰲ اﻟﺘﻄﺒﻴﻖ‬1000 ‫ﻛﻮن ﻣﺼﻔﻮﻓﺔ ﻣﻦ‬
.‫ﰲ ﻫﺬﻩ اﳌﺼﻔﻮﻓﺔ وﺗﺮﺗﻴﺒﻬﺎ ﺗﺮﺗﻴﺒﺎً ﺗﺼﺎﻋﺪﻳﺎً ﲝﺴﺐ اﻻﺳﻢ وﻃﺒﺎﻋﺘﻬﺎ وﻣﻦ ﰒ إﻟﻐﺎء اﳌﺆﺷﺮات اﻟﱵ ﻳﺘﻢ ﺗﻜﻮﻳﻨﻬﺎ‬
:‫اﻟﺤﻞ‬
#include <iostream>
using namespace std;

struct Client
{
char Name[50];
char Id_Number[6];
};
Client *Clients[1000],*C;
void main()
{
int n;
cin>>n;
for (int i=1;i<=n;i++)
{
Clients[i]=new Client;
cin>>Clients[i]->Name;
cin>>Clients[i]->Id_Number;
}
for (int i=1;i<n;i++)
for (int j=i+1;j<=n;j++)
if (strcmp(Clients[i]->Name,Clients[j]->Name)==1)
{
C=new Client;
C=Clients[i];
Clients[i]=Clients[j];
Clients[j]=C;
}
for (int i=1;i<=n;i++)
{
cout<<Clients[i]->Name<<" "<<Clients[i]->Id_Number<<endl;
delete Clients[i];
}
}

١٩-١
‫‪ -٢‬ﺍﻹﺟﺮﺍءﺍﺕ ﺑﻠﻐﺔ ‪Visual C++‬‬

‫ﻟﻘﺪ ﺑﻴﻨﺎ ﺳــﺎﺑﻘﺎً أن ﻣﻦ أﻫﻢ ﻣﺎ ﺗﺘﺼــﻒ ﺑﻪ ﻟﻐﺔ اﻟﱪﳎﺔ ‪ C‬وﻣﺎ ﺗﻼﻫﺎ ﻫﻲ أ ﺎ ﻟﻐﺔ إﺟﺮاﺋﻴﺔ ‪،Procedural Language‬‬
‫وﻫﺬا ﻳﻌﲏ أن اﻟﱪ ﻣﺞ اﳌﻜﺘﻮب ﺬﻩ اﻟﻠﻐﺔ ﻣﻜﻮن ﻣﻦ ﻛﺘﻠﺔ ﻣﻦ اﻹﺟﺮاءات‪ .‬وﻟﻌﻞ ﻣﻦ أﻫﻢ ﻓﻮاﺋﺪ اﻟﱪﳎﺔ اﻹﺟﺮاﺋﻴﺔ ﻫﻲ ﲡﺰﺋﺔ‬
‫اﻟﱪ ﻣﺞ إﱃ ﻋﺪد ﻣﻦ اﻟﻮﻇﺎﺋﻒ ﺗﺼــﺎغ أواﻣﺮ ﻛﻞ وﻇﻴﻔﺔ ﺿــﻤﻦ إﺟﺮاء ) ﺑﻊ( ﻣﺴــﺘﻘﻞ ﺧﺬ ﺷــﻜﻞ اﻟﱪ ﻣﺞ ﻣﻦ ﺣﻴﺔ ﲢﺪﻳﺪ‬
‫ﻣﺪﺧﻼﺗﻪ وﳐﺮﺟﺎﺗﻪ وﻫﺬا ﻣﺎ ﻳﺘﻔﻖ ﻣﻊ اﳌﺒﺪأ اﻷﺳـ ــﺎﺳـ ــﻲ ﰲ اﻟﺘﺤﻠﻴﻞ اﻟﺬي ﻳﻌﺘﻤﺪ ﻋﻠﻰ ﲡﺰﺋﺔ اﳌﺴـ ــﺄﻟﺔ اﻟﻜﻠﻴﺔ اﻟﱵ ﻗﺪ ﻳﺼـ ــﻌﺐ‬
‫ﺣﻠﻬﺎ ﲨﻠﺔ واﺣﺪة إﱃ أﺟﺰاء ﻳﺴﻬﻞ ﺣﻠﻬﺎ‪.‬‬
‫ﳝﻜﻦ ﺑﻨﺎء اﻟﱪ ﻣﺞ ﺑﻠﻐﺔ ‪ C++‬ﲝﻴﺚ ﻳﺴ ــﺘﺪﻋﻲ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴ ــﻲ ﲨﻠﺔ ﻣﻦ اﻹﺟﺮاءات اﳌﺴ ــﺘﻘﻠﺔ‪ ،‬ﳝﻜﻦ ﻟﻜﻞ إﺟﺮاء‬
‫ﻣﻦ اﻹﺟﺮاءات اﳌﻜﻮﻧﺔ ﻟﻠﱪ ﻣﺞ أن ﻳﺴـ ــﺘﺪﻋﻲ إﺟﺮاءات أﺧﺮى وﻫﺬا ﻣﺎ ﳝﻜﻦ اﳌﱪﻣﺞ ﻣﻦ ﺗﻜﻮﻳﻦ ﺣﻞ ﻟﻠﻤﺴـ ــﺄﻟﺔ ﻋﻠﻰ ﺷ ـ ــﻜﻞ‬
‫ﻫﺮم ﻣﻦ اﻹﺟﺮاءات ﻛﻞ ﻣﻨﻬﺎ ﻣﻜﻠﻒ ﲝﻞ ﺟﺰء ﻣﻦ اﳌﺴـ ــﺄﻟﺔ اﻟﻜﻠﻴﺔ‪ .‬ﺗﺴـ ــﻤﺢ ﻫﺬﻩ اﳍﻴﻜﻠﻴﺔ ﰲ اﻟﱪﳎﺔ ﺑﺘﺼـ ــﻮر ﺑﻨﻴﺔ ﺗﺸ ـ ــﺎﺑﻜﻴﻪ‪،‬‬
‫ﲟﻌﲎ أﻧﻪ ﳝﻜﻦ ﻹﺟﺮاء أن ﻳﺴــﺘﺪﻋﻲ إﺟﺮاء آﺧﺮ ﻳﺴــﺘﺪﻋﻲ ﺑﺪورﻩ اﻹﺟﺮاء اﻷول وﻫﻜﺬا‪ ...‬ﻛﻤﺎ ﳝﻜﻦ ﺗﺼــﻮر إﺟﺮاء ﻳﺴــﺘﺪﻋﻲ‬
‫ﻧﻔﺴﻪ وﻣﻦ ﰒ اﻟﺪﺧﻮل ﰲ اﻟﱪﳎﺔ اﻟﺘﻌﺎودﻳﺔ ‪.Recursive Programming‬‬
‫ﻳﺴـ ـ ــﺘﺪﻋﻲ اﻹﺟﺮاء اﻟﺮﺋﻴﺴـ ـ ــﻲ ﰲ ﺑﺮ ﻣﺞ ‪Visual C++‬ﲨﻠﺔ إﺟﺮاءات ﺗﻜﻮن ﲟﺠﻤﻠﻬﺎ اﻟﱪ ﻣﺞ اﻟﻜﻠﻲ‪ .‬اﻹﺟﺮاء ﻫﻮ‬
‫ﻛﺘﻠﺔ ﻣﻦ اﻟﺘﻌﻠﻴﻤﺎت واﻷواﻣﺮ اﻟﱵ ﺗﻘﻮم ﲟﻬﻤﺔ ﳏﺪدة‪ ،‬ﺗﻌﺮف ﻫﺬﻩ اﻟﺘﻌﻠﻴﻤﺎت واﻷواﻣﺮ ﺳ ــﻢ ﳏﺪد ﻳﺴ ــﺘﺨﺪم ﻟﺘﻌﺮﻳﻒ اﻹﺟﺮاء‬
‫واﺳ ــﺘﺪﻋﺎؤﻩ‪ ،‬ﺗﻨﻔﺬ ﻫﺬﻩ اﻟﺘﻌﻠﻴﻤﺎت ﻋﻠﻰ ﲨﻠﺔ ﻣﻦ اﻟﺒﻴﺎ ت ﻗﺪ ﻳﺘﻢ ﺗﻌﺮﻳﻔﻬﺎ ﻛﻤﺪﺧﻼت ﻟﻺﺟﺮاء‪ ،‬ﻗﺪ ﻳﻐﲑ اﻹﺟﺮاء ﺣﺎﻟﺔ ﺑﻌﺾ‬
‫اﳌﺘﻐﲑات داﺧﻞ اﻟﱪ ﻣﺞ وﻗﺪ ﻳﻌﻴﺪ ﻧﺘﺎﺋﺞ ﳏﺪدة إﱃ اﻟﱪ ﻣﺞ اﳌﺴـ ــﺘﺪﻋﻲ‪ .‬وﻋﻨﺪﻣﺎ ﻳﺴـ ــﺘﺪﻋﻲ اﻹﺟﺮاء ﻧﻔﺴـ ــﻪ ﻳﺴـ ــﻤﻰ ﻹﺟﺮاء‬
‫اﻟﺘﻌﺎودي‪.‬‬
‫إﺿـ ـ ـ ـ ـ ــﺎﻓــﺔ إﱃ اﳍﻴﻜﻠﻴــﺔ اﻟﱵ ﻳﺘﻤﺘﻊ ــﺎ اﻟﱪ ﻣﺞ ﺑﻠﻐــﺔ ‪ Visual C++‬ﻳﻘﻠﺺ اﺳ ـ ـ ـ ـ ــﺘﺨــﺪام اﻹﺟﺮاءات ﺣﺠﻢ اﻟﱪ ﻣﺞ‬
‫ﻹﻗﻼل ﻣﻦ ﺗﻜﺮار اﻟﺘﻌﻠﻴﻤﺎت اﻟﱪﳎﻴﺔ اﻟﱵ ﻗﺪ ﳓﺘﺎﺟﻬﺎ ﰲ ﻣﻮاﺿﻊ ﳐﺘﻠﻔﺔ داﺧﻞ اﻟﱪ ﻣﺞ‪.‬‬
‫ﻳﺘﺄﻟﻒ اﻟﱪ ﻣﺞ ﺑﻠﻐﺔ ‪ Visual C++‬ﻣﻦ إﺟﺮاء واﺣﺪ ﻋﻠﻰ اﻷﻗﻞ‪ ،‬و ﺧﺬ ﻫﺬا اﻹﺟﺮاء اﲰﺎً ﳏﺪداً ﻣﺜﻞ‪ main :‬ﻛﻤﺎ‬
‫رأﻳﻨﺎ ﺳﺎﺑﻘﺎً‪ ،‬ﺣﻴﺚ ﻳﺘﻢ ﺗﻨﻔﻴﺬ ﺗﻌﻠﻴﻤﺎﺗﻪ ﺗﻠﻘﺎﺋﻴﺎً ﻋﻨﺪ اﻟﺒﺪء ﺑﺘﻨﻔﻴﺬ اﻟﱪ ﻣﺞ‪ .‬ﳝﻜﻦ ﳍﺬا اﻹﺟﺮاء اﺳﺘﺪﻋﺎء إﺟﺮاءات أﺧﺮى ﻳﻌﺮﻓﻬﺎ‬
‫اﳌﺴــﺘﺨﺪم‪ .‬و ﻟﺘﺎﱄ ﻓﺎﻟﱪ ﻣﺞ اﻟﻜﻠﻲ ﺑﻠﻐﺔ ‪ Visual C++‬ﻫﻮ ﲨﻠﺔ إﺟﺮاءات ﺗﻜﺘﺐ ﻣﻦ ﻗﺒﻞ اﳌﱪﻣﺞ ﻳﺘﻢ اﺳــﺘﺪﻋﺎؤﻫﺎ ﻣﻦ ﻗﺒﻞ‬
‫ﺑﻌﻀ ـ ــﻬﺎ اﻟﺒﻌﺾ‪ .‬ﻛﻤﺎ ﳝﻜﻦ ﺗﻀ ـ ــﻤﲔ اﻟﱪ ﻣﺞ ﲨﻠﺔ إﺟﺮاءات ذات وﻇﺎﺋﻒ ﳏﺪدة ﻣﺼ ـ ــﺮح ﻋﻨﻬﺎ ﰲ ﻣﻜﺘﺒﺎت ﺧﺎرﺟﻴﺔ‪ ،‬وﻳﺘﻢ‬
‫ﺗﻀﻤﲔ ﻫﺬﻩ اﳌﻜﺘﺒﺎت داﺧﻞ اﻟﱪ ﻣﺞ ﺑﺘﻌﻠﻴﻤﺎت ﺧﺎﺻﺔ ﲤﻜﻦ ﻣﻦ اﺳﺘﺨﺪاﻣﻬﺎ داﺧﻞ اﻟﱪ ﻣﺞ‪.‬‬

‫‪ -١-٢‬ﺗﻌﺮﻳﻒ اﻹﺟﺮاء‬
‫ﻳﻌﺮف اﻹﺟﺮاء ﻋﻠﻰ أﻧﻪ ﻛﺘﻠﺔ ﳏﺪدة ﻣﻦ اﻷواﻣﺮ ﺗﻌﺮف ﺳ ـ ــﻢ ﳏﺪد "اﺳ ـ ــﻢ اﻹﺟﺮاء )أو اﻟﺪاﻟﺔ( ‪"Function Name‬‬
‫ﻳﻄﻠﻖ ﻋﻠﻴﻬﺎ اﺳـ ـ ـ ــﻢ ﺗﺮوﻳﺴـ ـ ـ ــﺔ اﻹﺟﺮاء‪ .‬ﲢﺎط أواﻣﺮ اﻹﺟﺮاء ﻷﻗﻮاس اﻟﻜﺒﲑة‪ ،‬ﺣﻴﺚ ﺗﺒﺪأ ﻟﻘﻮس "{" وﺗﻨﺘﻬﻲ ﻟﻘﻮس "}"‪.‬‬
‫وﻳﻄﻠﻖ ﻋﻠﻰ ﲨﻠﺔ اﻟﺘﻌﻠﻴﻤﺎت اﺳﻢ ﺟﺴﻢ اﻹﺟﺮاء "‪ ."body of function‬وﻳﻌﺮف ﻟﺸﻜﻞ اﻟﻌﺎم ﻋﻠﻰ اﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫)‪void|Return_type Function_Name(argument_types Name‬‬
‫‪١-٢‬‬
‫{‬
‫)‪(data declarations and body of Function‬‬
‫‪return Expression‬‬
‫}‬
‫ﺣﻴﺚ‪:‬‬
‫‪ :Return_type‬ﳕﻂ اﻟﺒﻴﺎ ت اﻟﱵ ﺳﻴﻌﻴﺪﻫﺎ اﻟﺘﺎﺑﻊ ﺑﻌﺪ اﻧﺘﻬﺎء اﻟﺘﻨﻔﻴﺬ أو ‪ void‬ﻟﻠﺪﻻﻟﺔ ﻋﻠﻰ ﻋﺪم إﻋﺎدة أي ﻗﻴﻤﺔ‪.‬‬
‫‪ :Function_Name‬اﺳﻢ اﻟﺘﺎﺑﻊ‪ ،‬وﲣﻀﻊ ﺗﺴﻤﻴﺔ اﻟﺘﺎﺑﻊ ﻟﻘﻮاﻋﺪ ﺗﺴﻤﻴﺔ اﳌﺘﻐﲑات ﺑﻠﻐﺔ ‪.Visual C++‬‬
‫‪ :argument_types‬أﳕﺎط وﺳﻄﺎء اﻟﺘﺎﺑﻊ‪.‬‬
‫‪ :Name‬أﲰﺎء وﺳﻄﺎء اﻟﺘﺎﺑﻊ‪ ،‬وﻫﻲ ﻣﺘﻐﲑات ﻣﻦ اﻷﳕﺎط اﳌﻌﺮوﻓﺔ‪.‬‬
‫‪ :return‬ﻳﻨﻬﻲ اﻹﺟﺮاء وﻳﺴﻨﺪ ﻗﻴﻤﺔ اﻟﺘﻌﺒﲑ ‪ Expression‬إﱃ اﺳﻢ اﻹﺟﺮاء‪.‬‬
‫ﺗﺴ ـ ـ ــﺘﺨﺪم ﺗﻌﻠﻴﻤﺔ ‪ return Expression‬ﻟﺘﻮﻗﻴﻒ ﺗﻨﻔﻴﺬ اﻹﺟﺮاء واﻟﻌﻮدة إﱃ اﻹﺟﺮاء اﳌﺴ ـ ـ ــﺘﺪﻋﻲ ﺑﻌﺪ اﺳ ـ ـ ــﻨﺎد ﻗﻴﻤﺔ‬
‫اﻟﺘﻌﺒﲑ ‪ Expression‬إﱃ اﺳ ـ ـ ـ ـ ــﻢ اﻹﺟﺮاء‪ .‬اﻟﺘﻌﺒﲑ ‪ Expression‬اﺧﺘﻴــﺎري‪ ،‬إي إﻧــﻪ ﳝﻜﻦ اﻻﻛﺘﻔــﺎء ﺑﻜﺘــﺎﺑــﺔ ﺗﻌﻠﻴﻤــﺔ ‪return‬‬
‫ﻟﺘﻮﻗﻴﻒ ﺗﻨﻔﻴﺬ اﻹﺟﺮاء‪ ،‬وﻫﻲ ﺣﺎﻟﺔ ﻋﺪم ﲢﺪﻳﺪ ﳕﻂ ﻟﻠﻘﻴﻤﺔ اﻟﱵ ﺳـ ـ ـ ــﻴﻌﻴﺪﻫﺎ اﻹﺟﺮاء‪ .‬ﳑﺎ ﺳـ ـ ـ ــﺒﻖ ﳝﻜﻦ أن ﻧﺴـ ـ ـ ــﺘﻨﺘﺞ أﻧﻪ ﳝﻜﻦ‬
‫اﺳ ـ ـ ـ ـ ـ ـ ــﺘﺨﺪام ﺗﻌﻠﻴﻤﺔ ‪ return‬ﰲ أي ﻣﻮﻗﻊ داﺧﻞ اﻹﺟﺮاء ﻟﺘﻮﻗﻴﻒ ﺗﻨﻔﻴﺬ اﻹﺟﺮاء ﺑﻘﻴﻤﺔ ﻣﻌﺎدة أو ﺑﺪون ﻗﻴﻤﺔ‪ ،‬وﰲ ﺣﺎل ﻋﺪم‬
‫اﺳﺘﺨﺪام ﺗﻌﻠﻴﻤﺔ ‪ return‬ﺳﻴﺘﻢ ﺗﻨﻔﻴﺬ ﻛﺎﻣﻞ ﺗﻌﻠﻴﻤﺎت اﻹﺟﺮاء‪.‬‬

‫‪ -٢-٢‬اﺳﺘﺪﻋﺎء اﻹﺟﺮاء‬
‫ﻳﺘﻢ اﺳـ ــﺘﺪﻋﺎء اﻹﺟﺮاء ﻣﻦ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴـ ــﻲ )اﻟﺘﺎﺑﻊ اﻟﺮﺋﻴﺴـ ــﻲ(‪ ،‬أو ﰲ أي إﺟﺮاء أﺧﺮ ﺑﻜﺘﺎﺑﺔ اﺳـ ــﻢ اﻹﺟﺮاء وﲢﺪﻳﺪ‬
‫اﻟﻮﺳﻄﺎء اﻟﻔﻌﻠﻴﺔ ﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫)(‪void main‬‬
‫{‬
‫‪.............‬‬
‫;)‪Function_Name(Expressions‬‬
‫‪.............‬‬
‫}‬
‫ﺣﻴﺚ ‪ Expressions‬ﲤﺜﻞ وﺳ ـ ــﻄﺎء اﻟﻔﻌﻞ ﻟﻺﺟﺮاء‪ ،‬وﻫﻲ اﻟﻘﻴﻢ اﻟﱵ ﺳ ـ ــﺘﺴ ـ ــﺘﺒﺪل ﺑﻮﺳ ـ ــﻄﺎء اﻟﻔﻌﻞ أﺛﻨﺎء ﺗﻨﻔﻴﺬ أواﻣﺮ اﻹﺟﺮاء‪.‬‬
‫وﳚﺐ ﻋﻠﻰ ﻫﺬﻩ اﻟﻮﺳﻄﺎء أن ﺗﺘﺴﺎوى ﻣﻦ ﺣﻴﺔ اﻟﻌﺪد ﻣﻊ وﺳﻄﺎء اﻟﺸﻜﻞ‪ ،‬وﳚﺐ أﻳﻀﺎً أن ﺗﺘﻮاﻓﻖ ﻣﻌﻬﺎ ﻣﻦ ﺣﻴﺔ اﻟﻨﻤﻂ‪.‬‬
‫إذا ﻛﺎن اﻹﺟﺮاء ﻳﻌﻴﺪ ﻗﻴﻤﺔ ﳝﻜﻨﻨﺎ اﺳﺘﺨﺪاﻣﻪ ﻛﺎﺳﺘﺨﺪام أي ﺗﻌﺒﲑ‪.‬‬

‫ﻣﺜﺎل ‪١-٢‬‬
‫َﻛﻮن إﺟﺮاءً ﺑﻠﻐﺔ ‪ Visual C++‬ﻳﻌﻴﺪ اﻟﻘﻴﻤﺔ اﻷﺻـ ـ ــﻐﺮ ﻣﻦ ﺑﲔ ﺛﻼث ﻗﻴﻢ ﺻـ ـ ــﺤﻴﺤﺔ ﻳﺘﻢ إدﺧﺎﳍﺎ ﻛﻮﺳـ ـ ــﻄﺎء‪ ،‬ﰒ ﻗﻢ‬
‫ﺳﺘﺪﻋﺎﺋﻪ ﻣﻦ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻲ‪.‬‬

‫‪٢-٢‬‬
:‫اﳊﻞ‬
:‫ﻓﻴﻤﺎ ﻳﻠﻲ ﺗﻌﺮﻳﻒ اﻹﺟﺮاء‬
int minmum(int x, int y, int z)
{
int min;
min=x;
if (y<min) min=y;
if (z<min) min=z;
return min;
}
:‫ وﳝﻜﻦ اﺳﺘﺪﻋﺎء ﻫﺬا اﻹﺟﺮاء ﻣﻦ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻲ ﻋﻠﻰ اﻟﺸﻜﻞ اﻟﺘﺎﱄ‬،minimum ‫ إﱃ‬min ‫ﻳﻌﻴﺪ ﻫﺬا اﻹﺟﺮاء ﻗﻴﻤﺔ‬
#include <iostream>
using namespace std;
void main()
{
int min;
int a, b, c;
cin>>a>>b>>c;
min=minimum(a,b,c);
cout<<"The minimum is"<<min<<endl;
}
‫ ﺗﺮﺗﻴﺐ أواﻣﺮ اﻹﺟﺮاء‬-‫أ‬
:‫ﳝﻜﻦ وﺿﻊ ﺗﻌﺮﻳﻒ ﻫﺬا اﻹﺟﺮاء ﰲ اﻟﱪ ﻣﺞ ﺣﺪ اﻷﺳﺎﻟﻴﺐ اﻟﺘﺎﻟﻴﺔ‬
‫ﻟﺸــﻜﻞ‬ main ‫ أي ﻗﺒﻞ ﺗﻌﺮﻳﻒ اﻹﺟﺮاء اﻟﺮﺋﻴﺴــﻲ‬،‫اﻷﺳــﻠﻮب اﻷول ﻳﺘﻢ ﺑﻮﺿــﻊ ﻛﺎﻣﻞ أواﻣﺮ اﻹﺟﺮاء ﻗﺒﻞ اﺳــﺘﺪﻋﺎﺋﻪ‬
:‫اﻟﺘﺎﱄ‬
Void|Return_type Function_Name(argument_types Name)
{
(data declarations and body of Function)
return Expression
}

void main()
{
.............
Function_Name(Expression);
.............
}

٣-٢
‫ وﻣﻦ ﰒ ﺗﻮﺿﻊ‬،‫ أي ﻗﺒﻞ ﺗﻌﺮﻳﻒ اﻹﺟﺮاء اﻟﺮﺋﻴﺴﻲ‬،‫اﻷﺳﻠﻮب اﻟﺜﺎﱐ ﻳﺘﻢ وﺿﻊ ﺗﺮوﻳﺴﺔ ﺗﻌﺮﻳﻒ اﻹﺟﺮاء ﻗﺒﻞ اﺳﺘﺪﻋﺎﺋﻪ‬
:‫ ﻛﻤﺎ ﰲ اﻟﺸﻜﻞ اﻟﺘﺎﱄ‬،‫أواﻣﺮ اﻟﺘﺎﺑﻊ ﺑﻌﺪ ﺗﻌﺮﻳﻒ اﻟﺘﺎﺑﻊ اﻟﺮﺋﻴﺴﻲ‬
void|Return_type Function_Name(argument_types Name)
void main()
{
.............
Function_Name(Expression);
.............
}
void|Return_type Function _Name(argument_types Name)
{
(data declarations and body of Function)
return Expression
}

٢-٢ ‫ﻣﺜﺎل‬
:‫ ﻋﻠﻰ اﻟﺸﻜﻞ اﻟﺘﺎﱄ‬١-٢ ‫ﳝﻜﻦ ﺗﻜﻮﻳﻦ اﻟﱪ ﻣﺞ ﰲ اﳌﺜﺎل‬
#include <iostream>
using namespace std;
int minmum(int x, int y, int z)
{
int min;
min=x;
if (y<min) min=y;
if (z<min) min=z;
return min;
}
void main()
{
int min;
int a, b, c;
cin>>a>>b>>c;
min=minimum(a,b,c);
cout<<"The minimum is"<<min<<endl;
}
:‫أو ﻟﺸﻜﻞ‬
#include <iostream>
using namespace std;
int minimum(int, int, int);
void main()
{

٤-٢
‫;‪int min‬‬
‫;‪int a, b, c‬‬
‫;‪cin>>a>>b>>c‬‬
‫;)‪min=minimum(a,b,c‬‬
‫;‪cout<<"The minimum is"<<min<<endl‬‬
‫}‬
‫)‪int minimum(int x, int y, int z‬‬
‫{‬
‫;‪int min‬‬
‫;‪min=x‬‬
‫;‪if (y<min) min=y‬‬
‫;‪if (z<min) min=z‬‬
‫;‪return min‬‬
‫}‬
‫ب‪ -‬ﲤﺮﻳﺮ اﳌﺘﻐﲑات إﱃ اﻹﺟﺮاءات ﻟﻌﻨﻮان‬
‫ﻟﻘﺪ ﺑﻴﻨﺎ ﺳ ـ ـ ـ ـ ــﺎﺑﻘﺎً أن اﳌﺆﺷ ـ ـ ـ ـ ـﺮات ﻫﻲ ﻣﺘﻐﲑات ﻳﺘﻢ اﻟﺘﻌﺎﻣﻞ ﻣﻌﻬﺎ ﻛﺎﳌﺘﻐﲑات اﻷﺧﺮى‪ ،‬وﻫﺬا ﻣﺎ ﻳﺴ ـ ـ ـ ـ ــﻤﺢ ﺑﺘﻌﺮﻳﻔﻬﺎ‬
‫ﻛﻤﺘﻐﲑات وﺳ ـ ــﻄﺎء ﺷ ـ ــﻜﻠﻴﺔ ﰲ أﺛﻨﺎء ﺗﻌﺮﻳﻒ اﻹﺟﺮاءات واﺳـ ـ ــﺘﺨﺪاﻣﻬﺎ أﻳﻀـ ـ ـﺎً ﻛﻤﺘﻐﲑات ﻓﻌﻠﻴﺔ وﻛﻘﻴﻤﺔ ﻣﻌﺎدة ﻣﻦ اﺳ ـ ــﺘﺪﻋﺎء‬
‫اﻹﺟﺮاء‪ .‬وﻫــﺬا ﻣــﺎ ﻳﺴ ـ ـ ـ ـ ــﻤﺢ ﻟﻨــﺎ ﺑﺘﻤﺮﻳﺮ اﳌﺘﻐﲑات ﻟﻌﻨﻮان وﺗﻐﻴﲑ ﻗﻴﻢ ﻫــﺬﻩ اﳌﺘﻐﲑات دون ﺗﻐﻴﲑ ﻋﻨــﺎوﻳﻨﻬــﺎ‪ .‬ﺗﻔﻴــﺪ ﻋﻤﻠﻴــﺔ ﲤﺮﻳﺮ‬
‫اﳌﺘﻐﲑات ﻟﻌﻨﻮان ﺑﺸــﻜﻞ أﺳــﺎﺳــﻲ ﺑﺘﻘﻠﻴﻞ ﺣﺠﻢ اﻟﺬاﻛﺮة اﻟﻼزﻣﺔ ﻟﺘﻨﻔﻴﺬ اﻟﱪ ﻣﺞ‪ ،‬ﻓﺈذا ﻛﺎن ﺣﺠﻢ اﻟﺒﻴﺎ ت اﻟﱵ ﺳــﻴﺘﻢ ﺗﺪاوﳍﺎ‬
‫ﰲ اﻹﺟﺮاء ﻛﺒﲑاً ﻳﺘﻄﻠﺐ ﺣﺠﺰ ﺣﻴﺰاً ﻣﻦ اﻟﺬاﻛﺮة ﳍﺎ ﰲ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴـ ـ ـ ــﻲ إﺿـ ـ ـ ــﺎﻓﺔ إﱃ ﺣﻴﺰ ﺧﺎص ﳊﺠﺰ ﻧﻔﺲ اﻟﺒﻴﺎ ت ﰲ‬
‫اﻟﱪ ﻣﺞ اﳉﺰﺋﻲ‪ ،‬أﻣﺎ ﺳﺘﺪﻋﺎﺋﻬﺎ ﻟﻌﻨﻮان ﺗﺒﻘﻲ اﻟﺒﻴﺎ ت ﰲ اﳊﻴﺰ اﶈﺠﻮز وﳚﺮي اﻹﺟﺮاء اﻟﺘﻌﺪﻳﻼت ﻋﻠﻰ ﻫﺬﻩ اﻟﺒﻴﺎ ت‪.‬‬

‫ﻣﺜﺎل ‪٣-٢‬‬
‫ﻟﻌﻮدة إﱃ اﻟﱪ ﻣﺞ ﰲ اﳌﺜﺎل ‪ ١-٢‬اﳌﺘﻀﻤﻦ ﺗﻌﺮﻳﻒ إﺟﺮاء ﻟﺘﺤﺪﻳﺪ اﻟﻘﻴﻤﺔ اﻟﺪﻧﻴﺎ ﺑﲔ ﺛﻼث ﻗﻴﻢ ﺳﻨﻌﻴﺪ ﺗﻌﺮﻳﻒ ﻫﺬا‬
‫اﻹﺟﺮاء ﲝﻴﺚ ﻳﺘﻢ ﲤﺮﻳﺮ اﳌﺘﻐﲑات ﻟﻌﻨﻮان وﻟﻴﺲ ﻟﻘﻴﻢ‪ ،‬ﻛﻤﺎ ﻳﻌﻴﺪ ﻗﻴﻤﺔ ﲤﺜﻞ ﻋﻨﻮان اﻟﻘﻴﻤﺔ اﻟﺪﻧﻴﺎ ﺑﲔ اﻟﻘﻴﻢ اﻟﺜﻼث‪:‬‬
‫>‪#include <iostream.h‬‬
‫)‪int *Minimum_Reference_By_Reference(int *x, int *y, int *z‬‬
‫{‬
‫;‪int *min‬‬
‫;‪min=x‬‬
‫;‪if (*y<*min) min=y‬‬
‫;‪if (*z<*min) min=z‬‬
‫;‪return min‬‬
‫}‬

‫)‪int Minimum_Value_By_Reference(int *x, int *y, int *z‬‬


‫{‬
‫;‪int min‬‬
‫;‪min=*x‬‬

‫‪٥-٢‬‬
if (*y<min) min=*y;
if (*z<min) min=*z;
return min;
}

int Minimum_Value_By_Value(int x, int y, int z)


{
int min;
min=x;
if (y<min) min=y;
if (z<min) min=z;
return min;
}

int* Minimum_Reference_By_Value(int x, int y, int z)


{
int *min;
min=&x;
if (y<*min) min=&y;
if (z<*min) min=&z;
return min;
}
void main()
{
int *min, m;
int a, b, c;
a=30;
b=20;
c=10;
min=Minimum_Reference_By_Reference(&a,&b,&c);
cout<<"The Minimum_Reference_By_Reference is: "
<<*min<<endl;

*min=Minimum_Value_By_Reference(&a,&b,&c);
cout<<"The Minimum_Value_By_Reference is: "
<<*min<<endl;

m=Minimum_Value_By_Value(a,b,c);
cout<<"The Minimum_Value_By_Value is: "<<m<<endl;

min=Minimum_Reference_By_Value(a,b,c);
cout<<"The Minimum_Reference_By_Value is: "
<<*min<<endl;

٦-٢
‫}‬
‫ﺑﻔﺮض ﻟﺪﻳﻨﺎ اﻟﻘﻴﻢ اﻵﺗﻴﺔ‪ a=30 :‬و ‪ b=10‬و ‪ ،c=20‬وﺑﻔﺮض ﲣﺰﻳﻦ ﻫﺬﻩ اﻟﻘﻴﻢ ﰲ اﳌﻮاﻗﻊ ﻣﻦ اﻟﺬاﻛﺮة ﻋﻠﻰ اﻟﺸﻜﻞ‬
‫اﻵﰐ‪ &a=1×0012F6D0 ::‬و ‪ &b=1×0012F6D4‬و ‪.&c=1×0012F6D8‬‬
‫ﻳﻌﻴﺪ اﻹﺟﺮاء ‪ Minimum_Reference_By_Reference‬ﻋﻨﻮان اﻟﻘﻴﻤﺔ اﻷﻗﻞ ﺑﲔ اﻟﻘﻴﻢ اﻟﺜﻼث وﻫﻮ ﻋﻨﻮان ‪ b‬أي‬
‫‪ .1×0012F6D4‬اﻟﻮﺳﻄﺎء اﻟﺸﻜﻠﻴﺔ ﻟﻺﺟﺮاء ﻫﻲ ﻣﺆﺷﺮات ﻣﻦ ﳕﻂ اﻟﺼﺤﻴﺢ ‪ int‬وﻫﻲ ‪ x, y, z‬ﻋﺒﺎرة ﻋﻦ ﻋﻨﺎوﻳﻦ ﰲ‬
‫ﻷﻣﺮ‬ ‫اﻟﺬاﻛﺮة ﻟﺘﺨﺰﻳﻦ ﻗﻴﻢ ﺻﺤﻴﺤﺔ ﻣﻦ اﻟﻨﻤﻂ ‪ .int‬ﻋﻨﺪ اﺳﺘﺪﻋﺎء اﻹﺟﺮاء‬
‫)‪ Minimum_Reference_By_Reference(&a,&b,&c‬ﺳﻴﺘﻢ اﺳﺘﺒﺪال اﻟﻮﺳﻄﺎء اﻟﺸﻜﻠﻴﺔ ‪ x, y, z‬ﺑﻌﻨﺎوﻳﻦ ‪a, b, c‬‬
‫وﻫﻲ ﻋﻠﻰ اﻟﺘﻮاﱄ ‪ ،&a, &b, &c‬أي أﻧﻪ ﺳﺘﺘﻢ ﻋﻤﻠﻴﺎت اﻹﺳﻨﺎد اﻵﺗﻴﺔ ‪ x=&a‬و ‪ y=&b‬و ‪ z=&c‬وﻣﻦ ﰒ ﻓﺈن ‪*x=30‬‬
‫و ‪ *y=10‬و ‪ .*z=20‬ﲡﺮى ﻋﻤﻠﻴﺔ اﳌﻘﺎرﻧﺔ ﻋﻠﻰ ﻗﻴﻢ ‪ x, y, z‬أي ﻋﻠﻰ ‪ *x, *y, *z‬وﺗﻌﻴﺪ ﻋﻨﻮان اﻟﻘﻴﻤﺔ اﻷﻗﻞ ‪.min‬‬
‫ﻳﻌﻴﺪ اﻹﺟﺮاء ‪ Minimum_Value_By_Reference‬اﻟﻘﻴﻤﺔ اﻷﻗﻞ ﺑﲔ اﻟﻘﻴﻢ اﻟﺜﻼث وﻫﻲ ﻗﻴﻤﺔ ‪ .b‬اﻟﻮﺳﻄﺎء اﻟﺸﻜﻠﻴﺔ‬
‫ﻟﻺﺟﺮاء ﻫﻲ ﻣﺆﺷﺮات ﻣﻦ ﳕﻂ اﻟﺼﺤﻴﺢ ‪ int‬وﻫﻲ ‪ x, y, z‬ﻋﺒﺎرة ﻋﻦ ﻋﻨﺎوﻳﻦ ﰲ اﻟﺬاﻛﺮة ﻟﺘﺨﺰﻳﻦ ﻗﻴﻢ ﺻﺤﻴﺤﺔ ﻣﻦ اﻟﻨﻤﻂ‬
‫‪ .int‬ﻋﻨﺪ اﺳﺘﺪﻋﺎء اﻹﺟﺮاء ﻷﻣﺮ‪:‬‬
‫)‪Minimum_Value_By_Reference(&a,&b,&c‬‬
‫ﺳﻴﺘﻢ اﺳﺘﺒﺪال اﻟﻮﺳﻄﺎء اﻟﺸﻜﻠﻴﺔ ‪ x, y, z‬ﺑﻌﻨﺎوﻳﻦ ‪ a, b, c‬وﻫﻲ ﻋﻠﻰ اﻟﺘﻮاﱄ ‪ ،&a, &b, &c‬أي أﻧﻪ ﺳﺘﺘﻢ ﻋﻤﻠﻴﺎت‬
‫اﻹﺳﻨﺎد اﻵﺗﻴﺔ ‪ x=&a‬و ‪ y=&b‬و ‪ z=&c‬وﻣﻦ ﰒ ﻓﺈن ‪ *x=30‬و ‪ *y=10‬و ‪ .*z=20‬ﲡﺮى ﻋﻤﻠﻴﺔ اﳌﻘﺎرﻧﺔ ﻋﻠﻰ‬
‫ﻗﻴﻢ ‪ x, y, z‬أي ﻋﻠﻰ ‪ *x, *y, *z‬وﺗﻌﻴﺪ اﻟﻘﻴﻤﺔ اﻷﻗﻞ ﰲ ‪.min‬‬
‫ﻳﻌﻴﺪ اﻹﺟﺮاء ‪ Minimum_Value_By_Value‬اﻟﻘﻴﻤﺔ اﻷﻗﻞ ﺑﲔ اﻟﻘﻴﻢ اﻟﺜﻼث وﻫﻲ ﻗﻴﻤﺔ ‪ .b‬اﻟﻮﺳﻄﺎء اﻟﺸﻜﻠﻴﺔ ﻟﻺﺟﺮاء‬
‫ﻫﻲ ﻣﺘﻐﲑات ﻣﻦ ﳕﻂ اﻟﺼﺤﻴﺢ ‪ int‬وﻫﻲ ‪ .x, y, z‬ﻋﻨﺪ اﺳﺘﺪﻋﺎء اﻹﺟﺮاء ﻷﻣﺮ ‪Minimum_Value_By_Value(a,‬‬
‫)‪ b, c‬ﺳﻴﺘﻢ اﺳﺘﺒﺪال اﻟﻮﺳﻄﺎء اﻟﺸﻜﻠﻴﺔ ‪ x, y, z‬ﺑﻘﻴﻢ ‪ a, b, c‬وﻣﻦ ﰒ ﻓﺈن ‪ x=30‬و ‪ y=10‬و ‪ .z=20‬ﲡﺮى ﻋﻤﻠﻴﺔ اﳌﻘﺎرﻧﺔ‬
‫ﻋﻠﻰ ﻗﻴﻢ ‪ x, y, z‬وﺗﻌﻴﺪ اﻟﻘﻴﻤﺔ اﻷﻗﻞ ﰲ ‪.min‬‬
‫ﻳﻌﻴﺪ اﻹﺟﺮاء ‪ Minimum_Reference_By_Value‬ﻋﻨﻮان اﻟﻘﻴﻤﺔ اﻷﻗﻞ ﺑﲔ اﻟﻘﻴﻢ اﻟﺜﻼث ‪ ،x, y, z‬أي ﻟﻴﺲ ﻋﻨﻮان‬
‫اﻟﻘﻴﻤﺔ اﻷﻗﻞ ﻣﻦ ﻋﻨﺎوﻳﻦ اﻟﻘﻴﻢ ‪ .a, b, c‬اﻟﺴﺒﺐ ﰲ ذﻟﻚ ﻫﻲ أن اﻟﻮﺳﻄﺎء اﻟﺸﻜﻠﻴﺔ ﻟﻺﺟﺮاء ﻫﻲ ﻣﺘﻐﲑات ﳕﻂ ‪ int‬وﻫﻲ‬
‫‪ x, y, z‬ﻳﺘﻢ ﺣﺠﺰ أﻣﺎﻛﻦ ﺟﺪﻳﺪة ﻣﻦ اﻟﺬاﻛﺮة ﻟﺘﺨﺰﻳﻦ ﻫﺬﻩ اﻟﻘﻴﻢ ﻋﻨﺪ اﺳﺘﺪﻋﺎء اﻹﺟﺮاء‪ ،‬وﺳﻴﻌﻴﺪ ﻫﺬا اﻹﺟﺮاء ﻋﻨﻮان‬
‫اﻟﺬاﻛﺮة اﻟﺬي ﻳﺘﻀﻤﻦ اﻟﻘﻴﻤﺔ اﻷﻗﻞ‪ ،‬أي أﻧﻪ ﺳﻴﻌﻴﺪ ﻋﻨﻮان ‪ y‬وﻟﻴﺲ ﻋﻨﻮان ‪.b‬‬
‫‪Overload‬‬ ‫ت‪ -‬ز دة ﲢﻤﻴﻞ اﻹﺟﺮاءات‬
‫ﻻ ﺗﻘﺒﻞ ﻟﻐﺔ ‪ C‬ﺗﺴــﻤﻴﺔ ﻋﺪة إﺟﺮاءات ﺑﻨﻔﺲ اﻻﺳــﻢ‪ .‬أﻣﺎ ﰲ إﺻــﺪارات ‪ C++‬ﻳُﺴــﻤﺢ ﺑﺘﻌﺮﻳﻒ ﻋﺪة إﺟﺮاءات ﺳــﻢ‬
‫واﺣﺪ ﺷـ ـ ـ ــﺮط أن ﲣﺘﻠﻒ ﻓﻴﻤﺎ ﺑﻴﻨﻬﺎ ﻟﻮﺳـ ـ ـ ــﻄﺎء ﻓﻘﻂ‪ .‬اﳌﺜﺎل اﻟﺘﺎﱄ ﻳﺒﲔ ﺗﻌﺮﻳﻒ إﺟﺮاﺋﲔ ﺳـ ـ ـ ــﻢ واﺣﺪ ﻣﻊ اﻻﺧﺘﻼف ﺑﻨﻤﻂ‬
‫اﻟﻮﺳﻄﺎء‪:‬‬
‫)‪float test(int i, int j‬‬
‫{‬
‫;‪return (float) i+j‬‬
‫}‬

‫‪٧-٢‬‬
‫)‪float test(float i, float j‬‬
‫{‬
‫;‪return i*j‬‬
‫}‬
‫ﳛﻤﻞ ﻫﺬﻳﻦ اﻹﺟﺮاﺋﲔ ﻧﻔﺲ اﻻﺳ ـ ـ ــﻢ‪ ،‬وﻋﻨﺪ اﺳ ـ ـ ــﺘﺪﻋﺎء )‪ test(2,3‬ﺳ ـ ـ ــﻴﺘﻢ اﺳ ـ ـ ــﺘﺪﻋﺎء اﻹﺟﺮاء اﳌﻌﺮف أوﻻً واﻟﻨﺘﻴﺠﺔ‬
‫ﺳﺘﻜﻮن ‪ ،5‬أﻣﺎ ﻋﻨﺪ اﻻﺳﺘﺪﻋﺎء ﻟﺸﻜﻞ )‪ text(2.5,3‬ﻋﻠﻰ ﺳﺒﻴﻞ اﳌﺜﺎل ﻓﺈﻧﻪ ﺳﻴﺘﻢ ﲢﻮﻳﻞ ‪ 2.5‬إﱃ ﻗﻴﻤﺔ ﺻﺤﻴﺤﺔ أي إﱃ ‪2‬‬
‫وﻧﺘﻴﺠﺔ اﻻﺳ ـ ــﺘﺪﻋﺎء ﺳ ـ ــﺘﻜﻮن ‪ .5‬أﻣﺎ إذا ﰎ ﺗﻐﻴﲑ ﺗﺮﺗﻴﺐ ﺗﻌﺮﻳﻒ ﻫﺬﻩ اﻹﺟﺮاءات ﻓﺈﻧﻪ ﺳ ـ ــﻴﺘﻢ ﲢﻮﻳﻞ اﻟﻘﻴﻤﺔ ‪ 3‬ﰲ اﻻﺳ ـ ــﺘﺪﻋﺎء‬
‫)‪ test(2.5,3‬إﱃ ﳕﻂ ‪ float‬واﻟﻨﺘﻴﺠــﺔ ﺳ ـ ـ ـ ـ ــﺘﻜﻮن ‪ .7.5‬وﳍــﺬا ﳚــﺐ اﻻﻧﺘﺒــﺎﻩ إﱃ ﺗﻌﺮﻳﻒ اﻹﺟﺮاءات ﻣﻦ ﻫــﺬا اﻟﻨﻮع ﻟﺘﺤــﺪﻳــﺪ‬
‫اﻷﺳﺒﻘﻴﺔ ﰲ اﻟﺘﻨﻔﻴﺬ‪.‬‬
‫‪inline‬‬ ‫‪ -١‬اﻹﺟﺮاء‬
‫ﻋﻨﺪ اﺳ ـ ــﺘﺪﻋﺎء أي إﺟﺮاء ﺳ ـ ــﻴﻘﻮم اﳌﻨﻀ ـ ــﺪ ﺑﺘﻜﻮﻳﻦ ﻧﺴ ـ ــﺨﺔ ﻣﻦ ﺗﻌﻠﻴﻤﺎﺗﻪ ﰲ ﻣﻮﻗﻊ ﳐﺼ ـ ــﺺ ﻟﺘﻨﻔﻴﺬ ﺗﻌﻠﻴﻤﺎت ﻫﺬا اﻹﺟﺮاء‪ ،‬وﻫﺬا ﳚﻌﻞ‬
‫اﻟﱪ ﻣﺞ أﻛﺜﺮ ﺑﻄﺄً ﰲ اﻟﺘﻨﻔﻴﺬ‪ .‬ﻟﺘﻼﰲ اﻟﺒﻂء ﻟﺘﻨﻔﻴﺬ ﳝﻜﻦ ﺗﻌﺮﻳﻒ اﻹﺟﺮاء ﲝﻴﺚ ﻳﺘﻢ ﺗﻨﻔﻴﺬ ﺗﻌﻠﻴﻤﺎﺗﻪ ﻣﺒﺎﺷﺮة‪ .‬وﻳﺘﻢ ذﻟﻚ ﺑﻮﺿﻊ اﻟﻜﻠﻤﺔ اﶈﺠﻮزة‬
‫‪ inline‬ﰲ ﻣﻘﺪﻣﺔ اﻟﺘﺼﺮﻳﺢ ﻋﻦ اﻹﺟﺮاء‪ .‬اﳌﺜﺎل اﻟﺘﺎﱄ ﻳﱭ ﻛﻴﻔﻴﺔ اﻟﺘﺼﺮﻳﺢ ﻋﻦ إﺟﺮاء ‪:inline‬‬
‫)‪inline int Max(int i, int j‬‬
‫{‬
‫;‪if (i>j) return i‬‬
‫;‪else return j‬‬
‫}‬
‫ﻳﺘﻢ اﺳ ـ ـ ــﺘﺪﻋﺎء ﻫﺬا اﻹﺟﺮاء ﻣﺮة واﺣﺪة ﻓﻘﻂ‪ ،‬وإذا أرد اﺳ ـ ــﺘﺪﻋﺎؤﻩ ﻣﺮة أﺧﺮى ﻳﺘﻮﺟﺐ ﻋﻠﻴﻨﺎ ﺗﻌﺮﻳﻔﻪ ﻣﺮة أﺧﺮى‪ ،‬أي‬
‫إﻧﻪ ﳚﺐ إﻋﺎدة ﺗﻌﺮﻳﻒ اﻹﺟﺮاء ﻋﻨﺪ ﻛﻞ ﻣﺮة ﻧﺮﻳﺪ اﺳ ـ ـ ــﺘﺪﻋﺎؤﻩ ﻓﻴﻬﺎ وﻫﺬا ﻣﺎ ﺳ ـ ـ ــﻴﺠﻌﻞ ﺗﻨﻔﻴﺬ اﻟﱪ ﻣﺞ أﺳ ـ ـ ــﺮع إﻻ أن ﺗﻌﻠﻴﻤﺎﺗﻪ‬
‫ﺳﺘﻜﻮن أﻃﻮل ﻟﺘﻜﺮار ﺗﻌﻠﻴﻤﺎت اﻹﺟﺮاء‪.‬‬
‫‪static‬‬ ‫‪ -٢‬اﻹﺟﺮاء‬
‫ﻋﻨﺪ اﻟﺘﺼ ـ ـﺮﻳﺢ ﻋﻦ إﺟﺮاء ﰲ ﻣﻠﻒ ﻣﻦ ﻣﻠﻔﺎت ‪ C++‬ﳝﻜﻦ اﺳ ـ ــﺘﺨﺪاﻣﻪ ﰲ أي ﺑﺮ ﻣﺞ ﺷـ ــﺮط إﺷ ـ ـﺮاك ﻫﺬا اﳌﻠﻒ ﰲ‬
‫اﻟﱪ ﻣﺞ ﺑﺘﻌﻠﻴﻤﺔ ‪ ،include‬ﻳﺴ ـ ـ ــﻤﻰ ﻋﻨﺪﺋﺬ اﻹﺟﺮاء ﻹﺟﺮاء اﳋﺎرﺟﻲ‪ .‬وﻗﺪ ﻳﻜﻮن ﻣﻦ اﳌﻔﻴﺪ ﺗﻌﺮﻳﻒ إﺟﺮاء داﺧﻠﻲ ﻟﻨﺴـ ـ ــﺒﺔ‬
‫ﻟﻠﻤﻠﻒ‪ ،‬ﲟﻌﲎ أﻧﻪ ﻳﻘﺘﺼـ ـ ـ ــﺮ اﺳـ ـ ـ ــﺘﺨﺪام اﻹﺟﺮاء اﻟﺪاﺧﻠﻲ ﻋﻠﻰ اﳌﻠﻒ اﻟﺬي ﻳﺘﻀـ ـ ـ ــﻤﻦ ﻫﺬا اﻹﺟﺮاء‪ .‬إذا أﺧﺬ ﺑﻌﲔ اﻻﻋﺘﺒﺎر‬
‫أوﻟﻮﻳﺔ ﺗﻨﻔﻴﺬ اﻹﺟﺮاءات اﶈﻠﻴﺔ ﻋﻠﻰ اﻹﺟﺮاءات اﳋﺎرﺟﻴﺔ ﻓﻴﻤﻜﻦ اﺳ ـ ـ ـ ــﺘﺨﺪم ﻫﺬا اﻷﺳ ـ ـ ـ ــﻠﻮب ﰲ اﻟﺘﺼـ ـ ـ ـ ـﺮﻳﺢ ﻋﻦ اﻹﺟﺮاءات‬
‫اﻟﺪاﺧﻠﻴﺔ ﳊﻞ ﺑﻌﺾ ﻣﺸـ ـ ــﺎﻛﻞ اﻟﺘﻌﺎرﺿ ـ ـ ــﺎت ﺑﲔ اﻹﺟﺮاءات اﻟﱵ ﲢﻤﻞ ﻧﻔﺲ اﻻﺳـ ـ ــﻢ اﻟﱵ ﳝﻜﻦ أن ﺗﻜﻮن ﻣﻌﺮﻓﺔ ﰲ أﻛﺜﺮ ﻣﻦ‬
‫ﻣﻠﻒ‪ .‬وﻳﺘﻢ اﻟﺘﺼ ـ ـﺮﻳﺢ ﻋﻦ إﺟﺮاءات ﻣﻦ ﻫﺬا اﻟﻨﻮع ﺑﻮﺿ ـ ــﻊ ﻛﻠﻤﺔ ‪ static‬ﰲ ﺑﺪاﻳﺔ ﺗﻌﺮﻳﻒ اﻹﺟﺮاء ﻟﺸ ـ ــﻜﻞ اﻟﺬي ﻳﺒﻴﻨﻪ اﳌﺜﺎل‬
‫اﻟﺘﺎﱄ‪:‬‬
‫;)‪static int locale1(void‬‬

‫)‪static int locale2(int i, float j‬‬


‫{‬

‫‪٨-٢‬‬
‫;‪return i*i+j‬‬
‫}‬
‫‪ -٣‬إﺟﺮاءات ﺗﻘﺒﻞ ﻋﺪد ﻣﺘﻐﲑ ﻣﻦ اﻟﻮﺳﻄﺎء‬
‫ﻋﺎدة ﻣﺎ ﺧﺬ اﻹﺟﺮاء ﻋﺪد ﳏﺪد ﻣﻦ اﻟﻮﺳ ـ ــﻄﺎء‪ ،‬إﻻ أن ﻟﻐﺔ ‪ C++‬ﺗﺴ ـ ــﻤﺢ ﺑﺘﻌﺮﻳﻒ إﺟﺮاءات ﺧﺬ ﻋﺪد وﺳ ـ ــﻄﺎء‬
‫ﻣﺘﻐﲑ‪ ،‬وإﺟﺮاءات اﻹدﺧﺎل واﻹﺧﺮاج ﻣﺜﻞ ‪ print‬و ‪ scan‬ﻫﻲ إﺟﺮاءات ﺧﺬ ﻋﺪد ﻣﺘﻐﲑ ﻣﻦ اﻟﻮﺳـ ـ ـ ــﻄﺎء‪ .‬ﻟﻺﺷـ ـ ـ ــﺎرة إﱃ أن‬
‫اﻹﺟﺮاء ﺧﺬ ﻋﺪد ﻣﺘﻐﲑ ﻣﻦ اﻟﻮﺳﻄﺎء ﻧﻀﻊ ﻧﻘﺎط ﰲ ﻗﺎﺋﻤﺔ اﻟﻮﺳﻄﺎء أﺛﻨﺎء اﻟﺘﻌﺮﻳﻒ ﻋﻦ ﻫﺬا اﻟﻨﻮع ﻣﻦ اﻹﺟﺮاءات ﺷﺮط أن‬
‫ﻳﺘﻀــﻤﻦ ﺗﻌﺮﻳﻒ اﻹﺟﺮاء اﻟﺘﺼ ـﺮﻳﺢ ﻋﻦ وﺳــﻴﻂ واﺣﺪ ﻋﻠﻰ اﻷﻗﻞ‪ .‬اﻟﺼــﻌﻮﺑﺔ اﻷﺳــﺎﺳــﻴﺔ ﰲ اﺳــﺘﺨﺪام ﻣﺜﻞ ﻫﺬﻩ اﻹﺟﺮاءات ﻫﻲ‬
‫ﰲ ﲤﺮﻳﺮ ﻗﻴﻢ ﻫﺬﻩ اﻟﻮﺳــﻄﺎء‪ .‬وﺗﻌﺘﻤﺪ آﻟﻴﺔ ﲤﺮﻳﺮ اﻟﻘﻴﻢ ﻋﻠﻰ ﻃﺒﻴﻌﺔ اﳊﺎﺳــﻮب وﻣﻨﻀــﺪ اﻟﻠﻐﺔ ‪ .Compiler‬وﳍﺬا ﰎ ﺗﻌﺮﻳﻒ وﺣﺪة‬
‫ﳕﻄﻴﺔ ‪ macros‬ﰲ ﻣﻠﻒ اﻟﱰوﻳﺴـ ـ ـ ــﺔ ‪ stdarg.h‬ﻟﺘﺴـ ـ ـ ــﻬﻴﻞ ﲤﺮﻳﺮ ﻗﺎﺋﻤﺔ اﻟﻮﺳـ ـ ـ ــﻄﺎء‪ ،‬وﳚﺐ إﺿـ ـ ـ ــﺎﻓﺔ اﳌﻜﺘﺒﺔ ‪ stdarg.h‬ﰲ ﺑﺪاﻳﺔ‬
‫اﻟﱪ ﻣﺞ ﻟﺘﻌﻠﻴﻤﺔ‪:‬‬
‫>‪#include <stdarg.h‬‬
‫وﻫﺬا ﻳﺴ ـ ـ ــﻤﺢ ﺳ ـ ـ ــﺘﺨﺪام ‪ va_list‬و اﻟﺘﻌﺎﺑﲑ ‪ va_star‬و ‪ va_arg‬و ‪ va_end‬ﻟﺘﻤﺮﻳﺮ اﻟﻮﺳ ـ ـ ــﻄﺎء ﻣﻦ اﻟﻼﺋﺤﺔ اﳌﺘﻐﲑة‪ .‬ﳍﺬا‬
‫ﳚﺐ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺘﻐﲑ ﻣﻦ ﳕﻂ ‪ va_list‬وﻣﻦ ﰒ ﻴﺌﺔ ﻫﺬا اﳌﺘﻐﲑ ﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫;)‪va_start(variable, parameter‬‬
‫ﺣﻴﺚ ‪ variable‬ﻫﻮ اﺳـ ــﻢ اﳌﺘﻐﲑ ﻣﻦ ﳕﻂ ‪ va_list‬اﻟﺬي ﺳـ ــﻴﺘﻢ ﺗﻜﻮﻳﻨﻪ‪ ،‬و ‪ parameter‬ﻫﻮ أﺧﺮ وﺳـ ــﻴﻂ ﰲ اﻹﺟﺮاء‪ .‬وﻋﻨﺪ‬
‫ﻴﺌﺔ ‪ variable‬ﳝﻜﻦ ﲤﺮﻳﺮ اﻟﻮﺳﻄﺎء اﻟﻮاﺣﺪ ﺗﻠﻮ اﻵﺧﺮ ﻟﺘﻌﻠﻴﻤﺔ‪:‬‬
‫)‪va_arg(variable, type‬‬
‫واﳌﺜﺎل اﻟﺘﺎﱄ ﻳﺒﲔ ﻛﻴﻔﻴﺔ ﺗﻌﺮﻳﻒ إﺟﺮاء ﳚﻤﻊ ﻗﻴﻢ وﺳﻄﺎﺋﻪ ﻣﺘﻐﲑة اﻟﻌﺪد‪:‬‬
‫)‪double somme(int compte, ...‬‬
‫{‬
‫;‪double result=0‬‬ ‫‪ */‬ﻣﺘﻐﲑ ﻟﻠﺘﺠﻤﻴﻊ *‪/‬‬
‫;‪va_list varg‬‬ ‫‪. */‬ﻣﺘﻐﲑ ﻳﺸﲑ إﱃ اﻟﻮﺳﻴﻂ اﻟﺘﺎﱄ *‪/‬‬
‫‪ . */‬ﻴﺌﺔ اﻟﻼﺋﺤﺔ *‪va_start(varg, compte); /‬‬
‫)‪while (compte!=0‬‬ ‫‪ */‬اﺳﺘﻌﺮاض اﻟﻼﺋﺤﺔ *‪/‬‬
‫{‬
‫;)‪result=result+va_arg(varg, double‬‬
‫;‪compte=compte-1‬‬
‫}‬
‫;)‪va_end(varg‬‬ ‫‪ */‬ﺎﻳﺔ اﻹﺟﺮاء *‪/‬‬
‫;‪return result‬‬
‫}‬

‫‪٩-٢‬‬
‫‪Recursive Programming‬‬ ‫‪ -٣-٢‬اﻟﱪﳎﺔ اﻟﻌﻮدﻳﺔ‬
‫اﻟﱪﳎﺔ اﻟﺘﻌﺎودﻳﺔ ﻫﻲ ﻛﻤﺎ ذﻛﺮ ﰲ اﻟﻔﺼــﻮل اﻟﺴــﺎﺑﻘﺔ اﺳــﺘﺪﻋﺎء اﻹﺟﺮاء ﻟﻨﻔﺴــﻪ‪ .‬ﺗﺘﻢ ﻋﻤﻠﻴﺔ اﻻﺳــﺘﺪﻋﺎء ﳌﺆﺷـﺮات أو‬
‫ﻟﻘﻴﻢ‪ .‬إن ﺗﻨﻔﻴﺬ ﺑﺮ ﻣﺞ ﻣﻊ اﳌﻌﺎودة ﳛﺘﺎج إﱃ ﺣﻴﺰ أﻛﱪ ﻣﻦ اﻟﺬاﻛﺮة ﻣﻘﺎرﻧﺔ ﻟﱪ ﻣﺞ اﳋﻄﻲ ﻛﻤﺎ ذﻛﺮ ﺳ ـ ـ ـ ـ ــﺎﺑﻘﺎً‪ .‬إن ﻣﺎ‬
‫ﳛﺪث ﻓﻌﻠﻴﺎً ﰲ اﻻﺳ ــﺘﺪﻋﺎء اﻟﺬاﰐ أو اﻟﱪﳎﺔ اﻟﺘﻌﺎودﻳﺔ ﻫﻮ أن اﳊﺎﺳــﻮب ﺳ ــﻴﺴــﺘﺪﻋﻲ اﻹﺟﺮاء ﻣﻦ ﺟﺪﻳﺪ ﰲ ﻛﻞ ﻣﺮة ﻳﺘﻢ ﻓﻴﻬﺎ‬
‫ﺗﻨﻔﻴﺬ أﻣﺮ اﻻﺳ ــﺘﺪﻋﺎء اﻟﺬاﰐ ﰲ ﺣﻴﺰ ﻣﻨﻔﺼ ــﻞ ﻣﻦ اﻟﺬاﻛﺮة اﻟﺪاﺧﻠﻴﺔ‪ ،‬وﻟﻦ ﻳﺼ ــﻞ إﱃ ﺎﻳﺔ اﻹﺟﺮاء إﻻ ﻋﻨﺪ اﻟﺘﻮﻗﻒ ﻋﻦ إﻋﺎدة‬
‫اﺳ ـ ـ ــﺘﺪﻋﺎء اﻹﺟﺮاء‪ ،‬ﳍﺬا ﳚﺐ ﻋﻠﻴﻨﺎ دوﻣﺎً إﺟﺮاء اﺧﺘﺒﺎر ﻟﺸ ـ ـ ــﺮط اﳋﺮوج ﻣﻦ ﻫﺬا اﻻﺳ ـ ـ ـ ــﺘﺪﻋﺎء‪ ،‬ﲤﺎﻣﺎً ﻛﺤﺎﻟﺔ ﺗﻜﻮﻳﻦ اﳊﻠﻘﺎت‬
‫اﻟﺸ ـ ــﺮﻃﻴﺔ ﺣﻴﺚ أن ﻟﻜﻞ ﺣﻠﻘﺔ ﺷ ـ ــﺮط ﻟﻠﺘﻮﻗﻒ ﻋﻦ ﺗﻨﻔﻴﺬ اﻷواﻣﺮ اﳌﻜﻮﻧﺔ ﳉﺴ ـ ــﻢ اﳊﻠﻘﺔ‪ .‬ﻋﻨﺪ ﻋﺪم إﻋﺎدة اﺳ ـ ــﺘﺪﻋﺎء اﻹﺟﺮاء‬
‫ﺳﻴﻘﻮم اﳊﺎﺳﻮب ﺳﺘﻜﻤﺎل ﺗﻨﻔﻴﺬ اﻷواﻣﺮ اﳌﺘﺒﻘﻴﺔ ﻣﻦ اﻹﺟﺮاء ﻣﻦ أﺟﻞ ﲨﻴﻊ اﻻﺳﺘﺪﻋﺎءات اﻟﱵ ﰎ ﺗﻨﻔﻴﺬﻫﺎ‪.‬‬
‫إذا أﺧﺬ ﺑﻌﲔ اﻻﻋﺘﺒﺎر أﻧﻪ ﰲ ﻛﻞ ﻣﺮة ﻳﺘﻢ ﻓﻴﻬﺎ اﺳـ ـ ـ ـ ــﺘﺪﻋﺎء إﺟﺮاء ﻣﺎ ﺳـ ـ ـ ـ ــﻴﺘﻢ ﲣﺼـ ـ ـ ـ ــﻴﺺ ﺣﻴﺰ ﺧﺎص ﻣﻦ اﻟﺬاﻛﺮة‬
‫اﻟﺪاﺧﻠﻴﺔ ﻟﺘﻨﻔﻴﺬ أواﻣﺮ اﻹﺟﺮاء‪ ،‬وﺳ ــﺘﺨﺼ ــﺺ أﻳﻀ ـﺎً ﻣﻮاﻗﻊ ﻣﻦ اﻟﺬاﻛﺮة ﻟﺘﺨﺰﻳﻦ اﳌﺘﻐﲑات اﳌﺼ ــﺮح ﻋﻨﻬﺎ داﺧﻞ اﻹﺟﺮاء ﺑﺸ ــﻜﻞ‬
‫ﻣﻨﻔﺼ ـ ـ ـ ــﻞ ﻋﻦ ﻣﻮاﻗﻊ ﲣﺰﻳﻦ اﳌﺘﻐﲑات ﻧﻔﺴ ـ ـ ـ ــﻬﺎ ﻻﺳ ـ ـ ـ ــﺘﺪﻋﺎء آﺧﺮ‪ ،‬ﻧﺪرك ﻣﻘﺪار ﺣﺠﻢ اﻟﺬاﻛﺮة اﻟﺪاﺧﻠﻴﺔ اﻟﻼزﻣﺔ ﻟﺘﻨﻔﻴﺬ إﺟﺮاء‬
‫ﺗﻌﺎودي‪ .‬إﻻ أن ﺻـ ــﻴﺎﻏﺔ اﻟﱪ ﻣﺞ ﺬا اﻷﺳـ ــﻠﻮب ﻓﻴﻬﺎ ﺳـ ــﻬﻮﻟﺔ أﻛﱪ وأواﻣﺮ ﳐﺘﺼـ ــﺮة ﻣﻘﺎرﻧﺔ ﻷﺳـ ــﻠﻮب اﻵﺧﺮ اﻟﺬي ﻳﺴـ ــﻤﻰ‬
‫ﻷﺳﻠﻮب اﳋﻄﻲ‪.‬‬

‫ﻣﺜﺎل ‪٤-٢‬‬
‫اﳌﺜﺎل اﻷﻛﺜﺮ ﺷﻴﻮﻋﺎً ﺣﻮل ﻛﺘﺎﺑﺔ ﺑﺮ ﻣﺞ ﺬا اﻷﺳﻠﻮب ﻫﻮ ﺑﺮ ﻣﺞ ﺣﺴﺎب ﻋﺎﻣﻠﻲ ﻋﺪد ﺻﺤﻴﺢ واﻟﺬي رأﻳﻨﺎ ﺳﺎﺑﻘﺎً‬
‫ﻛﻴﻔﻴﺔ ﺻ ـ ـ ـ ـ ــﻴﺎﻏﺔ ﺧﻮارزﻣﻴﺘﻪ‪ ،‬أﻣﺎ ﻓﻴﻤﺎ ﻳﺘﻌﻠﻖ ﺑﺼ ـ ـ ـ ـ ــﻴﺎﻏﺔ ﻫﺬﻩ اﳋﻮارزﻣﻴﺔ اﻟﺘﻌﺎودﻳﺔ ﺑﻠﻐﺔ ‪ Visual C++‬ﻓﻴﻤﻜﻦ أن ﻳﻜﻮن ﻋﻠﻰ‬
‫اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫>‪#include <iostream.h‬‬
‫;)‪long factorial(int n‬‬
‫{‬
‫;)‪if (n>0) return n*factorial(n-1‬‬
‫;‪if (n==0) return 1‬‬
‫}‬
‫)(‪void main‬‬
‫{‬
‫;‪int n‬‬
‫;‪cin>>n‬‬
‫;‪cout<<factorial(n)<<endl‬‬
‫}‬
‫اﺳﺘﺪﻋﺎء اﻹﺟﺮاء ‪ factorial‬ﻣﻦ أﺟﻞ ‪ n=5‬ﻷﻣﺮ )‪ factorial(5‬ﻋﻠﻰ ﺳﺒﻴﻞ اﳌﺜﺎل ﻳﺆدي إﱃ‪:‬‬
‫أوﻻً اﺳﺘﺒﺪال وﺳﻴﻂ اﻹﺟﺮاء ‪ n‬ﻟﻘﻴﻤﺔ ‪ 5‬واﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ‪ n>0‬وﲟﺎ أن اﻟﺸﺮط ﳏﻘﻖ ﻓﺴﻴﻌﺎود اﻹﺟﺮاء اﺳﺘﺪﻋﺎء‬
‫ذاﺗﻪ ﻟﻠﻤﺮة اﻷوﱃ ﻣﻦ أﺟﻞ‪:‬‬
‫‪n=n-1=5-1=4‬‬

‫‪١٠-٢‬‬
‫ﻟﻘﻴﻤﺔ ‪ 4‬واﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ‪ n>0‬وﲟﺎ أن اﻟﺸﺮط ﳏﻘﻖ ﺳﻴﻌﺎود اﻹﺟﺮاء اﺳﺘﺪﻋﺎء ذاﺗﻪ‬ ‫اﻹﺟﺮاء ‪n‬‬ ‫ﻧﻴﺎً اﺳﺘﺒﺪال وﺳﻴﻂ‬
‫ﻟﻠﻤﺮة اﻟﺜﺎﻧﻴﺔ ﻣﻦ أﺟﻞ‪:‬‬
‫‪n=n-1=4-1=3‬‬
‫ﻟﻘﻴﻤﺔ ‪ 3‬واﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ‪ n>0‬وﲟﺎ أن اﻟﺸﺮط ﳏﻘﻖ ﺳﻴﻌﺎود اﻹﺟﺮاء اﺳﺘﺪﻋﺎء ذاﺗﻪ‬ ‫وﺳﻴﻂ اﻹﺟﺮاء ‪n‬‬ ‫ﻟﺜﺎً اﺳﺘﺒﺪال‬
‫ﻟﻠﻤﺮة اﻟﺜﺎﻟﺜﺔ ﻣﻦ أﺟﻞ‪:‬‬
‫‪n=n-1=3-1=2‬‬
‫ﻟﻘﻴﻤﺔ ‪ 2‬واﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ‪ n>0‬وﲟﺎ أن اﻟﺸﺮط ﳏﻘﻖ ﺳﻴﻌﺎود اﻹﺟﺮاء اﺳﺘﺪﻋﺎء‬ ‫‪n‬‬ ‫راﺑﻌﺎً اﺳﺘﺒﺪال وﺳﻴﻂ اﻹﺟﺮاء‬
‫ذاﺗﻪ ﻟﻠﻤﺮة اﻟﺮاﺑﻌﺔ ﻣﻦ أﺟﻞ‪:‬‬
‫‪n=n-1=2-1=1‬‬
‫ﻟﻘﻴﻤﺔ ‪ 1‬واﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ‪ n>0‬وﲟﺎ أن اﻟﺸﺮط ﳏﻘﻖ ﺳﻴﻌﺎود اﻹﺟﺮاء اﺳﺘﺪﻋﺎء‬ ‫‪n‬‬ ‫ﺧﺎﻣﺴﺎً اﺳﺘﺒﺪال وﺳﻴﻂ اﻹﺟﺮاء‬
‫ذاﺗﻪ ﻟﻠﻤﺮة اﳋﺎﻣﺴﺔ ﻣﻦ أﺟﻞ‪:‬‬
‫‪n=n-1=1-1=0‬‬
‫ﺳﺎدﺳﺎً اﺳﺘﺒﺪال وﺳﻴﻂ اﻹﺟﺮاء ‪ n‬ﻟﻘﻴﻤﺔ ‪ 0‬واﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ‪ n>0‬وﲟﺎ أن اﻟﺸﺮط ﻏﲑ ﳏﻘﻖ ﻓﺴﻴﺘﺎﺑﻊ اﳊﺎﺳﻮب‬
‫ﺗﻨﻔﻴﺬ أواﻣﺮ اﻹﺟﺮاء وﺳﻴﺨﺘﱪ ﻓﻴﻤﺎ إذا ‪ n=0‬وﲟﺎ أن اﻟﺸﺮط ﳏﻘﻖ ﻟﺬا ﺳﻴﻌﻴﺪ اﻹﺟﺮاء اﻟﻘﻴﻤﺔ ‪ 1‬وﻳﻨﺘﻬﻲ ﻣﻦ اﻻﺳﺘﺪﻋﺎء‬
‫اﳋﺎﻣﺲ ﺑﻮﺿﻊ ‪.factorial(0)=1‬‬
‫إﲤﺎم ﻋﻤﻠﻴﺔ اﻻﺳﺘﺪﻋﺎء اﻟﺬاﰐ ﻟﻠﻤﺮة اﻟﺮاﺑﻌﺔ ﺑﻌﺪ ﺗﻌﻮﻳﺾ ﻗﻴﻤﺔ ‪ factorial(0)=1‬وﻳﻌﻴﺪ ﻗﻴﻤﺔ ‪ factorial(1)=1*1=1‬وﻣﻦ ﰒ‬
‫اﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ‪ n=0‬وﲟﺎ أن ﻧﺘﻴﺠﺔ اﻻﺧﺘﺒﺎر ﻫﻲ اﳋﻄﺄ وﻟﺬﻟﻚ ﻟﻦ ﻳﺘﻢ ﺗﻨﻔﻴﺬ أي أﻣﺮ‪.‬‬
‫إﲤﺎم ﻋﻤﻠﻴﺔ اﻻﺳﺘﺪﻋﺎء اﻟﺬاﰐ ﻟﻠﻤﺮة اﻟﺜﺎﻟﺜﺔ ﺑﻌﺪ ﺗﻌﻮﻳﺾ ﻗﻴﻤﺔ ‪ factorial(1)=1‬وﻳﻌﻴﺪ ﻗﻴﻤﺔ ‪ factorial(2)=2*1=2‬وﻣﻦ ﰒ‬
‫اﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ‪ n=0‬وﳌﺎ ﻛﺎﻧﺖ ﻧﺘﻴﺠﺔ اﻻﺧﺘﺒﺎر ﻫﻲ اﳋﻄﺄ وﻟﺬﻟﻚ ﻟﻦ ﻳﺘﻢ ﺗﻨﻔﻴﺬ أي أﻣﺮ‪.‬‬
‫إﲤﺎم ﻋﻤﻠﻴﺔ اﻻﺳﺘﺪﻋﺎء اﻟﺬاﰐ ﻟﻠﻤﺮة اﻟﺜﺎﻧﻴﺔ ﺑﻌﺪ ﺗﻌﻮﻳﺾ ﻗﻴﻤﺔ ‪ factorial(2)=2‬وﻳﻌﻴﺪ ﻗﻴﻤﺔ ‪ factorial(3)=3*2=6‬وﻣﻦ ﰒ‬
‫اﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ‪ n=0‬وﲟﺎ أن ﻧﺘﻴﺠﺔ اﻻﺧﺘﺒﺎر ﻫﻲ اﳋﻄﺄ وﻟﺬﻟﻚ ﻟﻦ ﻳﺘﻢ ﺗﻨﻔﻴﺬ أي أﻣﺮ‪.‬‬
‫إﲤﺎم ﻋﻤﻠﻴﺔ اﻻﺳﺘﺪﻋﺎء اﻟﺬاﰐ ﻟﻠﻤﺮة اﻷوﱃ ﺑﻌﺪ ﺗﻌﻮﻳﺾ ﻗﻴﻤﺔ ‪ factorial(3)=6‬وﻳﻌﻴﺪ ﻗﻴﻤﺔ ‪ factorial(4)=4*6=24‬وﻣﻦ‬
‫ﰒ اﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ‪ n=0‬وﲟﺎ أن ﻧﺘﻴﺠﺔ اﻻﺧﺘﺒﺎر ﻫﻲ اﳋﻄﺄ وﻟﺬﻟﻚ ﻟﻦ ﻳﺘﻢ ﺗﻨﻔﻴﺬ أي أﻣﺮ‪.‬‬
‫إﲤﺎم ﻋﻤﻠﻴﺔ اﻻﺳﺘﺪﻋﺎء اﻷﺳﺎﺳﻲ ﺑﻌﺪ ﺗﻌﻮﻳﺾ ﻗﻴﻤﺔ ‪ factorial(4)=24‬وﻳﻌﻴﺪ ﻗﻴﻤﺔ ‪ factorial(5)=5*24=120‬وﻣﻦ ﰒ‬
‫اﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎﻧﺖ ‪ n=0‬وﲟﺎ أن ﻧﺘﻴﺠﺔ اﻻﺧﺘﺒﺎر ﻫﻲ اﳋﻄﺄ ﻟﺬﻟﻚ ﻟﻦ ﻳﺘﻢ ﺗﻨﻔﻴﺬ أي أﻣﺮ‪.‬‬
‫ﻟﻘﺪ ﰎ اﺳﺘﺪﻋﺎء اﻹﺟﺮاء ﲬﺲ ﻣﺮات ﻏﲑ اﻻﺳﺘﺪﻋﺎء اﻷﺳﺎﺳﻲ وﰲ ﻛﻞ اﺳﺘﺪﻋﺎء ﺳﻴﺘﻢ ﺗﻨﻔﻴﺬ أواﻣﺮ اﻹﺟﺮاء ﺑﺸﻜﻞ‬
‫ﻣﻨﻔﺼـ ـ ــﻞ ﻋﻦ اﻻﺳ ـ ــﺘﺪﻋﺎء اﻵﺧﺮ ﻛﻤﺎ ﰲ اﻟﺸـ ــﻜﻞ ‪ ،١-٢‬وﳍﺬا ﻓﺈن ﺗﻨﻔﻴﺬ إﺟﺮاء ﺗﻌﺎودي ﻳﺆدي إﱃ اﻻﺳ ـ ــﺘﻨﺰاف اﻟﺴ ـ ـﺮﻳﻊ ﻟﻠﺬاﻛﺮة‬
‫اﻟﺪاﺧﻠﻴﺔ‪.‬‬

‫‪١١-٢‬‬
‫!‪5×4‬‬ ‫‪24×5=120‬‬

‫!‪4×3‬‬ ‫‪6×4=24‬‬

‫!‪3×2‬‬ ‫‪3×2=6‬‬

‫!‪2×1‬‬ ‫‪2×1‬‬

‫!‪1×0‬‬ ‫‪1×1‬‬

‫‪1‬‬

‫اﻟﺸﻜﻞ ‪ ١-٢‬ﺧﻄﻮات ﺗﻨﻔﻴﺬ إﺟﺮاء ﺗﻌﺎودي‬

‫‪Modular Programming‬‬ ‫‪ -٤-٢‬اﻟﱪﳎﺔ اﻟﻜﺘﻠﻴﺔ‬


‫ﻳﻘﺼ ــﺪ ﻟﱪﳎﺔ اﻟﻜﺘﻠﻴﺔ ﺗﻮزﻳﻊ رزم اﻟﱪاﻣﺞ ﻋﻠﻰ ﻋﺪة ﻣﻠﻔﺎت ﺑﺪﻻً ﻣﻦ ﻛﺘﺎﺑﺘﻬﺎ ﻛﻠﻬﺎ ﰲ ﻣﻠﻒ واﺣﺪ‪ .‬ﻟﻘﺪ رأﻳﻨﺎ ﺳ ــﺎﺑﻘﺎً‬
‫أن ﻫﻨﺎك أﺳـﻠﻮﺑﲔ ﻟﻠﺘﺼـﺮﻳﺢ ﻋﻦ اﻹﺟﺮاءات ﺑﻠﻐﺔ ‪ C++‬وﻫﻲ ﻛﺘﺎﺑﺔ أواﻣﺮ اﻟﱪ ﻣﺞ اﳉﺰﺋﻲ ﰲ ﻣﻨﻄﻘﺔ ﺗﺴـﺒﻖ اﺳـﺘﺪﻋﺎؤﻩ ﻣﻦ ﻗﺒﻞ‬
‫اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴﻲ ‪ main‬أو ﻣﻦ ﻗﺒﻞ أي إﺟﺮاء أﺧﺮ‪ ،‬أو إﺿﺎﻓﺔ ﺗﺮوﻳﺴﺔ اﻹﺟﺮاء ﰲ اﻟﺒﺪاﻳﺔ وﻣﻦ ﰒ ﻛﺘﺎﺑﺔ أواﻣﺮﻩ ﰲ ﻣﻨﻄﻘﺔ ﺗﻠﻲ‬
‫ﻣﻨﻄﻘﺔ اﺳـ ــﺘﺪﻋﺎﺋﻪ‪ .‬ﰲ اﻟﻮاﻗﻊ‪ ،‬ﳝﻜﻨﻨﺎ أﻳﻀـ ـﺎً وﺿـ ــﻊ أواﻣﺮ اﻹﺟﺮاء ﰲ ﻣﻠﻒ آﺧﺮ ﻏﲑ اﳌﻠﻒ اﻟﺬي ﻳﺘﻀـ ــﻤﻦ اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴـ ــﻲ‪،‬‬
‫وﳝﻜﻨﻨﺎ أﻳﻀﺎً وﺿﻊ ﺗﺮوﻳﺴﺔ اﻹﺟﺮاءات ﰲ ﻣﻠﻒ ﺧﺎص ﻳﺴﻤﻰ ﲟﻠﻒ اﻟﱰوﻳﺴﺔ ‪ header‬و ﺧﺬ اﻻﻣﺘﺪاد "‪ ".h‬وﻧﻜﺘﻔﻲ ﲟﻠﻒ‬
‫اﻟﱪ ﻣﺞ اﻟﺮﺋﻴﺴ ـ ــﻲ‪ ،‬أو ي وﺣﺪة ﺑﺮﳎﻴﺔ أﺧﺮى‪ ،‬ﺷ ـ ـﺮاك اﻟﻮﺣﺪة اﻟﱪﳎﻴﺔ ﺳـ ــﺘﺨﺪام اﳌﻮﺟﻪ "‪.#include "unite_name.h‬‬
‫وﻫﺬا ﻣﺎ ﻧﻔﻌﻠﻪ ﻋﻨﺪ اﺳﺘﺪﻋﺎء اﻹﺟﺮاءات اﳌﻌﺮﻓﺔ ﻣﺴﺒﻘﺎً ﰲ ﻣﻜﺘﺒﺎت اﻟﱪاﻣﺞ اﳉﺎﻫﺰة اﳌﺮﻓﻘﺔ ﻣﻊ ﻣﱰﺟﻢ اﻟﻠﻐﺔ‬
‫ﻳﻔﻴﺪ ﻫﺬا اﻷﺳـ ــﻠﻮب ﰲ اﻟﱪﳎﺔ ﻣﻦ ﺣﻴﺔ أوﱃ ﺑﺘﺠﺰﺋﺔ اﻟﱪاﻣﺞ اﻟﻀـ ــﺨﻤﺔ ﺿـ ــﻤﻦ وﺣﺪات ﺑﺮﳎﻴﺔ ﻳﺴـ ــﻬﻞ اﻟﺘﺤﻜﻢ ﺎ‬
‫ﻣﻦ ﻗﺒﻞ ﻓﺮﻳﻖ اﳌﱪﳎﲔ‪ ،‬وﻳﻔﻴﺪ ﻣﻦ ﺣﻴﺔ ﻧﻴﺔ ﺑﺘﺠﺰﺋﺔ ﻣﻌﺎﳉﺔ أواﻣﺮ اﻟﱪ ﻣﺞ ﲝﻴﺚ ﺗﺴ ـ ـ ـ ـ ــﺘﺪﻋﻰ اﻟﻮﺣﺪات اﻟﱪﳎﻴﺔ إﱃ اﻟﺬاﻛﺮة‬
‫اﻟﺪاﺧﻠﻴﺔ ﻟﺘﻨﺎوب ﲝﺴـ ــﺐ اﻹﺟﺮاءات اﻟﱵ ﻳﺘﻢ اﺳـ ــﺘﺪﻋﺎؤﻫﺎ ﳑﺎ ﻳﺴـ ــﻬﻞ ﻋﻤﻠﻴﺔ ﺗﻨﻔﻴﺬ اﻟﱪاﻣﺞ اﻟﱵ ﲢﺘﺎج إﱃ ذاﻛﺮة ﻗﺪ ﺗﺘﺠﺎوز‬
‫اﳌﺘﺎح ﻋﻠﻰ ﺟﻬﺎز اﳊﺎﺳـ ـ ــﻮب‪ .‬وﻫﻲ ﻣﻔﻴﺪة أﻳﻀ ـ ـ ـﺎً ﻣﻦ اﻟﻨﺎﺣﻴﺔ اﻟﺘﺠﺎرﻳﺔ ﺣﻴﺚ ﳝﻜﻦ ﻟﻠﻤﱪﳎﲔ ﺑﻨﺎء وﺣﺪات ﺑﺮﳎﻴﺔ ﺗﺘﻀـ ـ ــﻤﻦ‬
‫إﺟﺮاءات ﻣﻔﻴﺪة وﺗﺴﻮﻳﻘﻬﺎ‪.‬‬

‫ﻣﺜﺎل ‪٥-٢‬‬
‫ﻟﻨﻌﺪ ﺻـ ــﻴﺎﻏﺔ اﻟﱪ ﻣﺞ ﰲ ﻣﺜﺎل ﺣﺴـ ــﺎب ﻋﺎﻣﻠﻲ ﻋﺪد ﲝﻴﺚ ﻧﻀـ ــﻊ ﺗﺮوﻳﺴـ ــﺔ اﻹﺟﺮاء "‪ "factorial‬ﰲ ﻣﻠﻒ ﺗﺮوﻳﺴـ ــﺔ‬
‫"‪ "fact.h‬ﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;)‪int factorial(int‬‬
‫ﻟﺸﻜﻞ اﻵﰐ‪:‬‬ ‫"‪"fact.cpp‬‬ ‫وأواﻣﺮ اﻹﺟﺮاء ﰲ ﻣﻠﻒ‬
‫"‪#include "fact.h‬‬

‫‪١٢-٢‬‬
‫"‪#include "stdafx.h‬‬
‫)‪int factorial(int n‬‬
‫{‬
‫;‪int i, fac‬‬
‫;‪fac=1‬‬
‫;‪for (i=1; i<=n; i++) fac*=i‬‬
‫;‪return fac‬‬
‫}‬
‫ﻻﺳـ ـ ــﺘﺪﻋﺎء إﺟﺮاء ﺣﺴ ـ ــﺎب ﻋﺎﻣﻠﻲ ﻋﺪد ‪ factorial‬ﳚﺐ إدراج اﳌﻠﻒ اﻟﺬي ﻳﺘﻀـ ـ ــﻤﻦ ﺗﺮوﻳﺴ ـ ــﺔ ﻫﺬا اﻹﺟﺮاء ﲝﻴﺚ‬
‫ﻳﺼﺒﺢ اﳌﻠﻒ اﻟﺮﺋﻴﺴﻲ ﻋﻠﻰ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫>‪#include <iostream.h‬‬
‫"‪#include "fact.h‬‬
‫)(‪void main‬‬
‫{‬
‫;‪int n‬‬
‫;‪cin>>n‬‬
‫;‪cout<<factorial(n)<<endl‬‬
‫}‬

‫‪Variables Scoop‬‬ ‫‪ -٥-٢‬ﻣﺪى اﳌﺘﻐﲑات ﰲ اﻟﱪاﻣﺞ‬


‫ﻟﻘﺪ ذﻛﺮ ﺳ ــﺎﺑﻘﺎً أن اﻟﱪ ﻣﺞ ﰲ ﻟﻐﺔ ‪ Visual C++‬ﻣﻜﻮن ﻣﻦ ﻛﺘﻞ ﺑﺮﳎﻴﺔ ﺗﻀ ــﻢ ﳎﻤﻮﻋﺔ أواﻣﺮ‪ ،‬وﲢﺪد ﻫﺬﻩ اﻟﻜﺘﻞ‬
‫ﻷﻗﻮاس اﳌﺘﻮﺳﻄﺔ "}" و "{"‪ .‬وﳝﻜﻦ ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑات ﰲ ﻛﻞ ﻛﺘﻠﺔ ﻣﻦ ﻛﺘﻞ اﻟﱪ ﻣﺞ‪ .‬اﳌﺘﻐﲑ اﻟﺬي ﻳﻌﺮف ﰲ إﺣﺪى اﻟﻜﺘﻞ‬
‫ﻻ ﻳﺴﺘﺨﺪم ﰲ اﻟﻜﺘﻠﺔ اﳌﻨﻔﺼﻠﺔ‪ .‬إن ﺗﻌﺮﻳﻒ اﳌﺘﻐﲑات اﻟﻌﺎﻣﺔ ﰲ اﻟﱪ ﻣﺞ ﻳﺆدي إﱃ ﺗﻌﺮﻳﻔﻬﺎ ﰲ ﻛﻞ اﻟﻜﺘﻞ اﻟﻔﺮﻋﻴﺔ‪ ،‬أو ﺑﺸﻜﻞ‬
‫أﻋﻢ اﳌﺘﻐﲑ اﳌﻌﺮف ﰲ ﻛﺘﻠﺔ ﺗﺘﻀ ـ ـ ـ ـ ــﻤﻦ ﻛﺘﻞ ﺟﺰﺋﻴﺔ ﻳﺴ ـ ـ ـ ـ ــﺘﺨﺪم ﰲ ﻛﻞ اﻟﻜﺘﻞ اﻟﻔﺮﻋﻴﺔ‪ .‬وﳝﻜﻦ ﺗﻠﺨﻴﺺ ﻗﻮاﻋﺪ ﻣﺪى اﳌﺘﻐﲑات‬
‫)ﳎﺎﻻت اﻟﺮؤﻳﺔ( ﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫إذا ﰎ ﺗﻌﺮﻳﻒ أي ﻣﺘﻐﲑ ﻋﻠﻰ ﻣﺴﺘﻮى اﳌﻠﻒ‪ ،‬أي ﺧﺎرج ﻧﻄﺎق أي إﺟﺮاء وﻣﻨﻬﺎ ‪ main‬ﻳﻜﻮن ﳎﺎل اﻟﺮؤﻳﺔ ﻟﻪ ﻋﻠﻰ ﻣﺴﺘﻮى‬
‫اﳌﻠﻒ وﻳﻜﻮن ﻫﺬا اﳌﺘﻐﲑ ﻣﻌﺮوﻓﺎً ﻣﻦ ﻗﺒﻞ ﲨﻴﻊ اﻹﺟﺮاءات اﻧﻄﻼﻗﺎً ﻣﻦ اﻟﻨﻘﻄﺔ اﻟﱵ ﻳﻈﻬﺮ ﻓﻴﻬﺎ ﺗﻌﺮﻳﻒ ﻫﺬا اﳌﺘﻐﲑ‪ ،‬ﺗﺪﻋﻰ‬
‫ﻫﺬﻩ اﳌﺘﻐﲑات ﳌﺘﻐﲑات اﻟﻌﺎﻣﺔ ‪.Global Variables‬‬
‫ﺗﺘﻤﺘﻊ اﳌﺘﻐﲑات اﳌﺼﺮح ﻋﻨﻬﺎ ﺿﻤﻦ ﻛﺘﻠﺔ ﺑﺮﳎﻴﺔ ﻣﺎ ﲟﺪى ﻋﻠﻰ ﻣﺴﺘﻮى ﻫﺬﻩ اﻟﻜﺘﻠﺔ اﺑﺘﺪاءً ﻣﻦ ﻧﻘﻄﺔ ﺗﻌﺮﻳﻒ أي ﻣﻨﻬﺎ وﺣﱴ‬
‫ﺎﻳﺔ اﻟﻜﺘﻠﺔ واﶈﺪدة ﻟﻘﻮس‪ .‬ﻣﻦ اﳌﺘﻐﲑات اﻟﱵ ﳍﺎ اﳌﺪى ﻧﻔﺴﻪ ﻟﻠﻤﺘﻐﲑات اﳌﺼﺮح ﻋﻨﻬﺎ ﰲ ﺑﺪاﻳﺔ اﻹﺟﺮاء ووﺳﻄﺎء اﻹﺟﺮاء‬
‫وﺗﺪﻋﻰ ﲨﻴﻌﻬﺎ ﳌﺘﻐﲑات اﶈﻠﻴﺔ ‪ ،Local Variables‬وﻫﻲ ﻣﺘﻐﲑات ﻻ ﳝﻜﻦ اﺳﺘﺨﺪاﻣﻬﺎ ﺧﺎرج ﻧﻄﺎق اﻹﺟﺮاء أو اﻟﻜﺘﻠﺔ‬
‫اﻟﱪﳎﻴﺔ اﳌﻌﺮﻓﺔ ﻓﻴﻬﺎ‪ ،‬وﺗﻌﺮف ﻓﻘﻂ اﺑﺘﺪاءً ﻣﻦ اﻟﻨﻘﻄﺔ اﻟﱵ ﰎ ﺗﻌﺮﻳﻔﻬﺎ ﻓﻴﻬﺎ‪.‬‬
‫إذا ﰎ ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑ ﰲ ﻛﺘﻠﺔ ﻣﺎ وﲢﺘﻮي ﻫﺬﻩ اﻟﻜﺘﻠﺔ ﺑﺪورﻫﺎ ﻛﺘﻼً داﺧﻠﻴﺔ وﰎ اﻟﺘﺼﺮﻳﺢ ﻋﻦ اﳌﺘﻐﲑ ﻧﻔﺴﻪ داﺧﻞ ﻫﺬﻩ اﻟﻜﺘﻞ‬
‫ﻓﺈﻧﻪ ﻳﺘﻢ إﺧﻔﺎء اﳌﺘﻐﲑ ﰲ اﻟﻜﺘﻠﺔ اﳋﺎرﺟﻴﺔ ﺣﱴ ﺎﻳﺔ اﻟﺘﻨﻔﻴﺬ اﳌﺘﻌﻠﻖ ﻟﻜﺘﻞ اﻟﺪاﺧﻠﻴﺔ‪ .‬أي أﻧﻪ ﰲ أﺛﻨﺎء اﻟﺘﻨﻔﻴﺬ اﳌﺘﻌﻠﻖ‬

‫‪١٣-٢‬‬
‫ﻟﻜﺘﻠﺔ اﻟﺪاﺧﻠﻴﺔ ﻓﺈ ﺎ ﺗﺮى ﻓﻘﻂ اﳌﺘﻐﲑات اﶈﻠﻴﺔ اﳋﺎﺻﺔ ﺎ وﻻ ﺗﺮى اﳌﺘﻐﲑات اﳌﻮﺟﻮدة ﰲ اﻟﻜﺘﻞ اﻟﱵ ﲢﺘﻮﻳﻬﺎ إن وﺟﺪت‬
‫ﻣﺘﻐﲑات ﳏﻠﻴﺔ ﻻﺳﻢ ﻧﻔﺴﻪ‪.‬‬
‫اﳌﺘﻐﲑات اﻟﻮﺣﻴﺪة اﻟﱵ ﻳﻄﺎل ﻣﺪاﻫﺎ ﻣﺴﺘﻮى ﳕﻮذج اﻹﺟﺮاء ﻫﻲ وﺳﻄﺎء اﻹﺟﺮاء‪ .‬وﳕﺎذج اﻹﺟﺮاءات ﻻ ﲢﺘﺎج إﱃ ذﻛﺮ أﲰﺎء‬
‫اﻟﻮﺳﻄﺎء ﻋﻨﺪ اﺳﺘﺪﻋﺎﺋﻬﺎ ﺑﻞ ﳝﻜﻦ اﻻﻛﺘﻔﺎء ﺑﺬﻛﺮ أﳕﺎط ﻫﺬﻩ اﻟﻮﺳﻄﺎء‪ ،‬وإذا ﻣﺎ ذﻛﺮت أﲰﺎء اﻟﻮﺳﻄﺎء ﻓﺴﻴﺘﻢ ﲡﺎﻫﻠﻬﺎ ﻣﻦ‬
‫ﻗﺒﻞ اﳌﱰﺟﻢ وﻣﻦ ﰒ ﳝﻜﻦ اﺳﺘﻌﻤﺎل ﻫﺬﻩ اﻷﲰﺎء ﰲ ﻣﻜﺎن آﺧﺮ ﰲ اﻟﱪ ﻣﺞ دون أي ﺛﲑ ﰲ ﺗﻨﻔﻴﺬ اﻹﺟﺮاء‪.‬‬

‫ﻣﺜﺎل ‪٦-٢‬‬
‫اﻟﱪ ﻣﺞ اﻵﰐ ﻳﺒﲔ ﻣﺪى اﳌﺘﻐﲑات ﰲ اﻟﱪ ﻣﺞ ﺑﻠﻐﺔ ‪:Visual C++‬‬
‫>‪#include <iostream.h‬‬
‫;‪int r ,*k‬‬
‫)(‪void main‬‬
‫{‬
‫;‪r=300; k=&r‬‬
‫{‬
‫;‪int r ,*k; r=100; k=&r‬‬
‫"<<‪cout<<"k="<<k‬‬ ‫;‪r="<<r<<endl‬‬
‫}‬
‫{‬
‫;‪int r, *k; r=200;k=&r‬‬
‫"<<‪cout<<"k="<<k‬‬ ‫;‪r="<<r<<endl‬‬
‫}‬
‫"<<‪cout<<"k="<<k‬‬ ‫;‪r="<<r<<endl‬‬
‫}‬
‫ﺗﺞ ﺗﻨﻔﻴﺬ اﻟﱪ ﻣﺞ ﻫﻮ‪:‬‬
‫‪k=0x0012FF7C‬‬ ‫‪r=100‬‬
‫‪k=0x0012FF74‬‬ ‫‪r=200‬‬
‫‪k=0x00428BF8‬‬ ‫‪r=300‬‬
‫ﻧﻼﺣﻆ ﻣﻦ ﺧﻼل ﻫــﺬا اﳌﺜــﺎل أن اﳌﺘﻐﲑات ‪ k‬و ‪ r‬اﳌﻌﺮﻓــﺔ ﰲ ﺑــﺪاﻳــﺔ اﻟﱪ ﻣﺞ ﲣﺘﻠﻒ ﻋﻦ اﳌﺘﻐﲑات اﳌﻌﺮﻓــﺔ ﰲ اﻟﻜﺘـﻞ‬
‫اﻟﱪﳎﻴــﺔ اﳉﺰﺋﻴــﺔ‪ .‬إن ﻋــﺪم إﻋــﺎدة ﺗﻌﺮﻳﻒ ﻫــﺬﻩ اﳌﺘﻐﲑات ﰲ إﺣــﺪى اﻟﻮﺣــﺪات ﻳﺆدي إﱃ اﺳ ـ ـ ـ ـ ــﺘﺨــﺪام ﻫــﺬﻩ اﳌﺘﻐﲑات ﰲ ﻫــﺬﻩ‬
‫اﻟﻮﺣﺪة‪ ،‬ﻓﺈذا ﻏﲑ ﻟﻮﺣﺪة اﻷوﱃ ﲝﻴﺚ ﺗﺼﺒﺢ أواﻣﺮ ﻫﺬﻩ اﻟﻮﺣﺪة ﻋﻠﻰ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫{‬
‫;‪r=100; k=&r‬‬
‫"<<‪cout<<"k="<<k‬‬ ‫;‪r="<<r<<endl‬‬
‫}‬
‫ﺳﺘﻜﻮن ﻧﺘﺎﺋﺞ ﺗﻨﻔﻴﺬ ﻫﺬا اﻟﱪ ﻣﺞ ﻋﻠﻰ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫‪k=0x00428BF8‬‬ ‫‪r=100‬‬
‫‪k=0x0012FF74‬‬ ‫‪r=200‬‬

‫‪١٤-٢‬‬
‫‪k=0x00428BF8‬‬ ‫‪r=100‬‬

‫ﻣﺜﺎل ‪٧-٢‬‬
‫ﳝﻜﻨﻨﺎ إﻋﺎدة ﺻــﻴﺎﻏﺔ الﻣﺜﺎل ‪ ٦-٢‬ﺑﺘﺼـﺮﻳﺢ إﺟﺮاءات ‪ first‬و ‪ second‬و ﺗﺞ ﺗﻨﻔﻴﺬ ﻫﺬا اﻟﱪ ﻣﺞ ﻳﺸــﺒﻪ ﺗﺞ ﺗﻨﻔﻴﺬ‬
‫اﻟﱪ ﻣﺞ ﰲ ﺣﺎﻟﺔ اﻟﱪ ﻣﺞ ﰲ اﳌﺜﺎل اﻟﺴﺎﺑﻖ‪:‬‬
‫>‪#include <iostream.h‬‬
‫;‪int r ,*k‬‬
‫)(‪void first‬‬
‫{‬
‫;‪int r ,*k; r=100;k=&r‬‬
‫"<<‪cout<<"k="<<k‬‬ ‫;‪r="<<r<<endl‬‬
‫}‬
‫)(‪void second‬‬
‫{‬
‫;‪int r, *k; r=200;k=&r‬‬
‫"<<‪cout<<"k="<<k‬‬ ‫;‪r="<<r<<endl‬‬
‫}‬
‫)(‪void main‬‬
‫{‬
‫;)(‪r=300; k=&r; first();second‬‬
‫"<<‪cout<<"k="<<k‬‬ ‫;‪r="<<r<<endl‬‬
‫}‬

‫‪ -٦-٢‬ﻓﻀﺎءات اﻟﺘﺴﻤﻴﺎت‬
‫ﻳﺘﻢ اﻟﺘﺼ ـﺮﻳﺢ ﻋﻦ اﳌﺘﻐﲑات إﻣﺎ ﰲ ﺑﺪاﻳﺔ اﻟﱪ ﻣﺞ ﺣﻴﺚ ﺗﺼ ــﺒﺢ ﻣﺘﻐﲑات ﻋﺎﻣﺔ ﰲ اﻟﱪ ﻣﺞ أو أن ﻳﺘﻢ اﻟﺘﺼ ـﺮﻳﺢ ﻋﻨﻬﺎ‬
‫ﰲ ﻣﻠﻔﺎت ﻳﺘﻢ اﺳ ـ ــﺘﺪﻋﺎﺋﻬﺎ ﰲ اﻟﱪ ﻣﺞ‪ ،‬إﻻ أن اﻟﺘﺼـ ـ ـﺮﻳﺢ ﻋﻦ ﻣﺘﻐﲑات ﰲ ﻣﻠﻔﺎت ﳐﺘﻠﻔﺔ ﻗﺪ ﻳﺆدي إﱃ ﺗﻌﺎرﺿـ ــﺎت ﲡﺔ ﻋﻦ‬
‫ﺗﺴﻤﻴﺔ ﻋﺪة ﻣﺘﻐﲑات ﺳﻢ واﺣﺪ‪ ،‬ﻛﺄن ﻳﺘﻢ ﻣﻨﺢ ﺗﺴﻤﻴﺔ واﺣﺪة ﳌﺘﻐﲑﻳﻦ اﺛﻨﲔ ﻣﻦ ﻗﺒﻞ ﻣﱪﳎﲔ اﺛﻨﲔ ﰲ ﻣﻠﻔﲔ ﳐﺘﻠﻔﲔ‪ ،‬وﻋﻨﺪ‬
‫اﺳ ـ ـ ــﺘﺪﻋﺎء ﻫﺬﻳﻦ اﳌﻠﻔﲔ ﻣﻦ ﻗﺒﻞ اﻟﱪ ﻣﺞ ﺳ ـ ـ ــﻴﺠﺪ اﳌﻨﻀ ـ ـ ــﺪ ﻣﺘﻐﲑﻳﻦ ﺧﺬان اﲰﺎً واﺣﺪاً‪ .‬ﳌﻨﻊ ﻣﺜﻞ ﻫﺬﻩ اﻟﺘﻌﺎرﺿ ـ ـ ــﺎت ﳝﻜﻦ‬
‫اﻟﺘﺼ ـﺮﻳﺢ ﻋﻦ ﻣﺎ ﻳﺴــﻤﻰ ﺑﻔﻀــﺎءات اﻟﺘﺴــﻤﻴﺎت‪ ،‬ﻫﻲ ﻣﻨﺎﻃﻖ ﺗﺼ ـﺮﻳﺢ ﺗﺴــﻤﺢ ﺑﺘﻘﻴﻴﺪ اﻟﺒﺤﺚ ﻋﻦ ﺗﺴــﻤﻴﺎت اﳌﺘﻐﲑات ﻣﻦ ﻗﺒﻞ‬
‫اﳌﻨﻀ ــﺪ‪ .‬واﳍﺪف اﻷﺳ ــﺎﺳ ــﻲ ﻣﻦ ﻫﺬﻩ اﻟﺘﺴ ــﻤﻴﺎت ﻫﻮ ﲡﻤﻴﻊ اﻟﺘﺴ ــﻤﻴﺎت ﻣﻨﻄﻘﻴﺎً ﻟﺘﺠﻨﺐ اﻟﺘﻌﺎرض ﻓﻴﻤﺎ ﺑﻴﻨﻬﺎ‪ .‬ﻳﺪﻋﻰ ﻓﻀ ــﺎء‬
‫اﻷﲰﺎء اﻟﺬي ﻳﻌﺮﻓﻪ اﳌﺴﺘﺨﺪم ﺑﻔﻀﺎء ﻣﺴﻤﻰ‪ ،‬وﻳﻌﺮف ﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫‪namespace name‬‬
‫{‬
‫‪declarations | definitions‬‬
‫}‬

‫‪١٥-٢‬‬
‫ﺣﻴﺚ ‪ name‬ﻫﻮ اﺳ ـ ـ ــﻢ اﻟﻔﻀ ـ ـ ــﺎء و ‪ declarations‬و ‪ definition‬ﻫﻲ ﺗﺼ ـ ـ ــﺮﳛﺎت ﻋﻦ ﻣﺘﻐﲑات أو ﺗﻌﺮﻳﻔﻬﺎ‪ .‬ﻳﺘﻢ‬
‫اﻟﺘﺼ ـ ـ ـﺮﻳﺢ ﻋﻦ ﻓﻀـ ـ ــﺎء أﲰﺎء ﺟﺪﻳﺪ ﻟﻜﻠﻤﺔ اﶈﺠﻮزة ‪ namespace‬واﳌﺜﺎل اﻟﺘﺎﱄ ﻳﻐﺮف ﻓﻀـ ـ ــﺎﺋﻲ أﲰﺎء ‪ A‬و ‪ ،B‬وﻳﻀـ ـ ــﻴﻒ‬
‫ﺗﻌﺮﻳﻒ ﺟﺪﻳﺪ إﱃ اﻟﻔﻀﺎء ‪:A‬‬
‫اﻷﲰﺎء ‪namespace A // A‬‬ ‫اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻓﻀﺎء‬
‫{‬
‫;‪int i‬‬
‫}‬

‫اﻷﲰﺎء ‪namespace B // B‬‬ ‫اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻓﻀﺎء‬


‫{‬
‫;‪int i‬‬
‫}‬

‫‪namespace A // A‬‬ ‫اﻣﺘﺪاد ﻟﻔﻀﺎء اﻷﲰﺎء‬


‫{‬
‫;‪int j‬‬
‫}‬
‫ﻳﺘﻢ اﻟﻮﺻـ ــﻮل إﱃ اﳌﻌﺮﻓﺎت ﰲ ﻓﻀـ ــﺎء اﻷﲰﺎء ﻣﻦ ﺧﺎرﺟﻪ ﺳـ ــﺘﺨﺪام اﻟﻌﻤﻠﻴﺔ "‪ "::‬أﻣﺎ ﻣﻦ داﺧﻞ اﻟﻔﻀـ ــﺎء ﻓﻠﻴﺲ ﻣﻦ‬
‫اﻟﻀﺮوري اﺳﺘﺨﺪام "‪ "::‬ﻟﻠﻮﺻﻮل إﱃ ﻣﻌﺮف ﻣﺼﺮح ﻋﻨﻪ داﺧﻞ اﻟﻔﻀﺎء‪ ،‬واﳌﺜﺎل اﻟﺘﺎﱄ ﻳﺒﲔ ﻛﻴﻔﻴﺔ اﻟﻮﺻﻮل إﱃ اﳌﻌﺮﻓﺎت‪:‬‬
‫;‪int i=1‬‬ ‫‪// i‬‬ ‫‪.‬ﻣﺘﻐﲑ ﻛﻠﻲ‬

‫‪namespace A‬‬
‫{‬
‫;‪int i=2‬‬
‫;‪int j=i‬‬
‫}‬

‫)‪int main(void‬‬
‫{‬
‫;‪i=1‬‬ ‫اﻟﻜﻠﻲ‪//‬‬ ‫اﳌﻌﺮف ﰲ اﺠﻤﻟﺎل‬ ‫‪i‬‬ ‫اﳌﺘﻐﲑ‬
‫‪A::i=3; //A‬‬ ‫اﳌﺘﻐﲑ ‪ i‬اﳌﻌﺮف ﰲ اﻟﻔﻀﺎء‬
‫;‪return 0‬‬
‫}‬
‫ﺑﻨﻔﺲ اﻟﻄﺮﻳﻘﺔ ﳝﻜﻦ ﺗﻌﺮﻳﻒ اﻹﺟﺮاءات واﺳﺘﺨﺪاﻣﻬﺎ ﰲ ﻓﻀﺎءات اﻷﲰﺎء ﻛﻤﺎ ﰲ اﳌﺜﺎل اﻟﺘﺎﱄ‪:‬‬
‫‪namespace A‬‬
‫{‬

‫‪١٦-٢‬‬
‫ﺗﻌﺮﻳﻒ ‪int f(void); // A::f‬‬
‫}‬

‫)‪int A::f(void‬‬ ‫ﺗﻌﺮﻳﻒ ‪// A::f‬‬


‫{‬
‫;‪return 0‬‬
‫}‬
‫وﳝﻜﻦ ﺗﻌﺮﻳﻒ ﻓﻀ ـ ـ ــﺎء أﲰﺎء داﺧﻞ ﻓﻀ ـ ـ ــﺎء أﺧﺮ‪ ،‬ﻋﻨﺪﻫﺎ ﻧﺴ ـ ـ ــﺘﺨﺪم "‪ "::‬ﺑﺸ ـ ـ ــﻜﻞ ﻣﺘﺘﺎﱄ ﻟﻠﻮﺻ ـ ـ ــﻮل إﱃ اﻟﺘﻌﺮﻳﻔﺎت‬
‫اﳌﻄﻠﻮﺑﺔﻛﻤﺎ ﰲ اﳌﺜﺎل اﻟﺘﺎﱄ‪:‬‬
‫‪namespace Container‬‬
‫{‬
‫;‪int i‬‬ ‫‪// Container::i.‬‬
‫‪namespace Content‬‬
‫{‬
‫;‪int j‬‬ ‫‪// container::content::j.‬‬
‫}‬
‫}‬
‫ﳝﻜﻦ ﺗﻌﺮﻳﻒ ﻓﻀﺎء ﺗﺴﻤﻴﺎت ﺑﺪون اﺳﻢ ﳊﺠﺐ ﺗﻌﺮﻳﻔﺎت ﺳﺎﺑﻘﺔ ﰲ ﻓﻀﺎءات ﺗﺴﻤﻴﺎت أﺧﺮى‪.‬‬

‫‪using‬‬ ‫‪ -٧-٢‬اﺳﺘﺨﺪام‬
‫ﺳــﺘﺨﺪام اﳌﻌﺮﻓﺎت اﳌﺼــﺮح ﻋﻨﻬﺎ ﰲ ﻓﻀــﺎءات اﻷﲰﺎء‪ .‬واﳌﺜﺎل اﻟﺘﺎﱄ ﻳﺒﲔ ﻛﻴﻔﻴﺔ اﺳــﺘﺨﺪام‬ ‫‪using‬‬ ‫ﻳﺴــﻤﺢ اﻟﺘﺼـﺮﻳﺢ‬
‫ﻫﺬا اﻟﺘﺼﺮﻳﺢ‪:‬‬
‫‪namespace A‬‬
‫{‬
‫;‪int i‬‬ ‫‪// A::i‬‬ ‫ﺗﻌﺮﻳﻒ‬
‫;‪int j‬‬ ‫ﻳﻌﺮف ‪// A::j‬‬
‫}‬

‫)‪void f(void‬‬
‫{‬
‫‪using A::i; // A::i‬‬ ‫‪.‬ﻳﺴﻤﺢ ﻫﺬا اﻟﺘﺼﺮﻳﺢ ﺳﺘﺨﺪام‬
‫;‪i=1‬‬ ‫ﺗﻌﻠﻴﻤﺔ ‪// A::i=1‬‬ ‫‪.‬ﺗﻜﺎﻓﺊ ﻫﺬﻩ اﻟﻌﻠﻴﻤﺔ‬
‫;‪j=1‬‬ ‫ﻣﻌﺮف‪//‬‬ ‫ﺧﻄﺄ ﻷن ‪ j‬ﻏﲑ‬
‫; ‪return‬‬
‫}‬

‫‪١٧-٢‬‬
‫ﺗﺴﻤﺢ ﻋﺒﺎرة اﻟﺘﻮﺟﻴﻪ ‪ using‬اﺳﺘﺨﺪام ﻓﻀﺎء اﻷﲰﺎء ﺑﻜﻞ ﻣﻌﺮﻓﺎﺗﻪ‪ ،‬وﺗﺴﺘﺨﺪم ﻟﺼﻴﻐﺔ اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫;‪Using namespace name‬‬
‫ﺣﻴﺚ ‪ name‬ﻫﻮ اﺳﻢ ﻓﻀﺎء اﻷﲰﺎء‪ ،‬واﳌﺜﺎل اﻟﺘﺎﱄ ﻳﺒﲔ ﻛﻴﻔﻴﺔ اﺳﺘﺨﺪام ﻫﺬا اﻟﺘﻌﺒﲑ‪:‬‬
‫‪namespace A‬‬
‫{‬
‫;‪int i‬‬ ‫ﻳﻌﺮف ‪// A::i‬‬

‫;‪int j‬‬ ‫ﻳﻌﺮف ‪// A::j‬‬


‫}‬

‫)‪void f(void‬‬
‫{‬
‫;‪using namespace A‬‬
‫;‪i=1‬‬ ‫ﺗﻌﻠﻴﻤﺔ ‪// A::i=1‬‬ ‫‪.‬ﺗﻜﺎﻓﺊ ﻫﺬﻩ اﻟﻌﻠﻴﻤﺔ‬
‫;‪j=1‬‬ ‫ﺗﻌﻠﻴﻤﺔ ‪// A::j=1‬‬ ‫‪.‬ﺗﻜﺎﻓﺊ ﻫﺬﻩ اﻟﻌﻠﻴﻤﺔ‬
‫; ‪return‬‬
‫}‬
‫ﻋﻨﺪ اﺳ ــﺘﺨﺪام ﻋﺒﺎرة اﻟﺘﻮﺟﻴﻪ ‪ using‬ﻳﺼ ــﺒﺢ ﻣﻦ اﳌﻤﻜﻦ اﺳ ــﺘﺨﺪام ﻛﻞ اﲰﺎء ﻣﻌﺮﻓﺎت ﻓﻀ ــﺎء اﻷﲰﺎء‪ ،‬وﻫﻲ ﺻ ــﺎﳊﺔ‬
‫اﺑﺘﺪاءً ﻣﻦ ﻧﻘﻄﺔ وﺿ ـ ـ ــﻊ اﳌﻮﺟﻪ ‪ using‬وﺣﱴ ﺎﻳﺔ ﳎﻤﻮﻋﺔ اﻟﺘﻌﻠﻴﻤﺎت اﻟﱵ ﺗﺘﻀ ـ ـ ــﻤﻦ ﻫﺬا اﻟﺘﻌﺮﻳﻒ‪ .‬وإذا ﰎ إﺿ ـ ـ ــﺎﻓﺔ ﻣﻌﺮﻓﺎت‬
‫ﺟﺪﻳﺪة إﱃ ﻓﻀﺎء اﻷﲰﺎء ﺑﻌﺪ اﺳﺘﺨﺪام ‪ using‬ﺳﺘﺴﺘﺨﺪم أﻳﻀﺎً ﻛﻤﺎ ﻟﻮ أﻧﻪ ﻣﻌﺮﻓﺔ ﺳﺎﺑﻘﺎً‪ ،‬واﳌﺜﺎل اﻟﺘﺎﱄ ﻳﻮﺿﺢ ذﻟﻚ‪:‬‬
‫‪namespace A‬‬
‫{‬
‫;‪int i‬‬
‫}‬

‫;‪using namespace A‬‬

‫‪namespace A‬‬
‫{‬
‫;‪int j‬‬
‫}‬

‫)‪void f(void‬‬
‫{‬
‫;‪i=0‬‬
‫;‪j=0‬‬
‫; ‪return‬‬
‫}‬

‫‪١٨-٢‬‬
‫‪ -٣‬ﺍﻟﺴﻼﺳﻞ ﺍﳊﺮﻓﻴﺔ‬

‫ﺗﺸــﺒﻪ اﻟﺴﻼﺳــﻞ اﳊﺮﻓﻴــﺔ ﺑﻠﻐــﺔ ‪ C++‬اﳌﺼــﻔﻮﻓﺎت‪ ،‬وﻫــﻲ ﻟﻮاﻗــﻊ ﺻــﻒ ﻣــﻦ اﳊــﺮوف ﻣــﻦ اﻟــﻨﻤﻂ ‪ char‬ﻳﻨﺘﻬــﻲ ﻟﺮﻣــﺰ‬
‫اﳋﺎص "‪ ."\0‬ﻳــﺘﻢ اﻟﻮﺻــﻮل إﱃ ﻛــﻞ ﺣــﺮف ﻣــﻦ ﺣــﺮوف اﻟﺴﻠﺴــﻠﺔ ﺑــﺮﻗﻢ ﻳﺸــﲑ إﱃ ﺗﺮﺗﻴــﺐ اﳊــﺮف ﰲ اﻟﺴﻠﺴــﻠﺔ‪ .‬ﺧــﺬ اﻟﺘﺼـﺮﻳﺢ‬
‫ﻋﻦ ﺳﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ ﻣﺼﻔﻮﻓﺔ ﺣﺪ اﻷﺷﻜﺎل اﻵﺗﻴﺔ‪:‬‬

‫أ‪ -‬اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﺳﻠﺴﻠﺔ ﺑﻄﻮل ﳏﺪد‬


‫اﻟﺸﻜﻞ اﻟﻌﺎم ﻟﻠﺘﺼﺮﻳﺢ ﻋﻦ ﺳﻠﺴﻠﺔ ﺑﻄﻮل ﳏﺪد ﺧﺬ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;]‪char Name[n‬‬
‫ﺣﻴﺚ أن ‪ char‬ﻫﻮ ﳕﻂ اﳌﺘﻐــﲑ اﳌﺴــﺒﻖ اﻟﺘﻌﺮﻳــﻒ اﳌﺴــﺘﺨﺪم ﻟﻠﺘﺼـﺮﻳﺢ ﻋــﻦ ﺣــﺮف‪ ،‬و ‪ Name‬اﺳــﻢ اﳌﺘﻐــﲑ‪ ،‬و ‪ n‬ﻋــﺪد ﺻــﺤﻴﺢ‬
‫ﳝﺜﻞ ﻋﺪد اﻷﺣﺮف ﺿﻤﻦ ﻣﺼﻔﻮﻓﺔ اﻷﺣﺮف‪ .‬أي أن اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﺳﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ ﻳﻌﲏ اﻟﺘﺼﺮﻳﺢ ﻋــﻦ ﻣﺼــﻔﻮﻓﺔ ﻣــﻦ اﻷﺣــﺮف‪،‬‬
‫ﻋﺪد اﻷﺣﺮف اﻟﱵ ﳝﻜﻦ إﺳﻨﺎدﻫﺎ ﳍﺬﻩ اﳌﺼﻔﻮﻓﺔ ﻫﻮ ‪ n-1‬ﺣﻴﺚ ﺧﺬ أﺧﺮ ﻋﻨﺼﺮ ﰲ اﳌﺼﻔﻮﻓﺔ اﻟﻘﻴﻤﺔ '‪ '\0‬وﻳﺒﺪأ دﻟﻴﻞ اﻟﻘــﻴﻢ‬
‫ﻣﻦ اﻟﺮﻗﻢ ‪.0‬‬
‫ﻣﺜﺎل ‪١-٣‬‬
‫ﻛﻤﺜﺎل ﻋﻠﻰ اﺳﺘﺨﺪام ﻫﺬا اﻟﺸﻜﻞ ﻟﻠﺘﺼﺮﻳﺢ ﻋﻦ ﺳﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ ﳝﻜﻨﻨﺎ أن ﻧﺼﺮح ﻋﻦ ﻣﺘﻐــﲑ ﻳﺘﻀــﻤﻦ أﲰــﺎء )ﻃــﻼب‬
‫أو أﲰﺎء ز ﺋﻦ( ﰲ ﺑﺮ ﻣﺞ ﻣﺎ ﻋﻠﻰ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;]‪char name[21‬‬
‫ﻋﺪد اﳊﺮوف اﻟﱵ ﳝﻜﻦ إﺳﻨﺎدﻫﺎ ﳍﺬﻩ اﻟﺴﻠﺴﻠﺔ ﻫﻮ ‪ 20‬و ﺧﺬ اﻟﺸﻜﻞ‪:‬‬
‫]‪name[0], name[1], name[2],…., name[20‬‬
‫وﻗﻴﻤﺔ ]‪ name[20‬ﻫﻲ '‪.'\0‬‬

‫ب‪ -‬اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﺳﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ ﺑﻄﻮل ﻏﲑ ﳏﺪد‬


‫ﻳﺘﻢ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺼﻔﻮﻓﺔ أﺣﺮف ﺑﻄــﻮل ﻏــﲑ ﳏــﺪد ﻟﺸــﻜﻞ اﻟﺴــﺎﺑﻖ ﻟﻜــﻦ دون ﲢﺪﻳــﺪ ﻋــﺪد ﻋﻨﺎﺻــﺮ ﻫــﺬﻩ اﳌﺼــﻔﻮﻓﺔ‬
‫ﺑﺸﻜﻞ ﻣﺒﺎﺷﺮ‪ ،‬وﻳﺘﻢ ﲢﺪﻳﺪ ﻃﻮل ﻫﺬﻩ اﳌﺼﻔﻮﻓﺔ ﻣﻦ ﺧﻼل اﻷﺣﺮف اﳌﺴﻨﺪة ﳍﺬﻩ اﳌﺼﻔﻮﻓﺔ ﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;"‪char color[]="blue‬‬
‫ﻛﻤﺎ ﳝﻜﻨﻨﺎ أﻳﻀﺎً اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺼﻔﻮﻓﺔ أﺣﺮف ﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;}'‪char color[]={'b', 'l', 'u', 'e', '\0‬‬
‫ﺗﻌﺮف ﻫﺬﻩ اﻷواﻣﺮ ﺳﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ ﺑﻄﻮل ﻳﺴﺎوي ﻋﺪد اﻷﺣﺮف ﻳﺘﻢ اﻟﻮﺻﻮل إﱃ ﻛﻞ ﺣﺮف ﻣﻨﻬﺎ ﻟﺸﻜﻞ‪:‬‬
‫‪color[0], color[1], color[2],….‬‬

‫‪١-٣‬‬
‫ت‪ -‬اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺆﺷﺮ إﱃ ﺳﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ‬
‫ﳝﻜــﻦ أﻳﻀـﺎً اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ ﻣﺘﻐــﲑ ﻳﺸــﲑ إﱃ ﺳﻠﺴــﻠﺔ ﺣﺮﻓﻴــﺔ ﺳــﺘﺨﺪام اﳌﺆﺷـﺮات‪ ،‬وﻳــﺘﻢ اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ اﻟﺴﻼﺳــﻞ اﳊﺮﻓﻴــﺔ‬
‫اﳌﺼﺮح ﻋﻨﻬﺎ ﺬﻩ اﻟﻄﺮﻳﻘﺔ ﲤﺎﻣﺎً ﻛﺎﻟﺘﻌﺎﻣﻞ ﻣﻊ ﻣﺼﻔﻮﻓﺔ اﳌﺆﺷﺮات‪ .‬ﻳﺘﻢ اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ ﻣﺼــﻔﻮﻓﺔ أﺣــﺮف ﻟﻄــﻮل اﶈــﺪد ﻟﻄﺮﻳﻘــﺔ‬
‫اﻵﺗﻴﺔ‪:‬‬
‫;]‪char *Name[n‬‬
‫وﺗﺴــﻨﺪ اﻟﻘــﻴﻢ إﱃ اﳌﺼــﻔﻮﻓﺎت اﳌﻌﺮﻓــﺔ ــﺬﻩ اﻟﻄﺮﻳﻘــﺔ ﺑــﻨﻔﺲ أﺳــﻠﻮب إﺳــﻨﺎد اﻟﻘــﻴﻢ إﱃ اﳌﺆﺷ ـﺮات ﻧﻔﺴــﻪ‪ .‬ﻛﻤــﺎ ﳝﻜﻨﻨــﺎ‬
‫اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺆﺷﺮ ﻟﺴﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ ﳛﺪد ﻃﻮﳍﺎ ﻣﻦ ﺧﻼل ﻋﻤﻠﻴﺔ اﻹﺳﻨﺎد ﻛﻤﺎ ﰐ‪:‬‬
‫;"‪char *color="blue‬‬

‫‪ -١-٣‬ﺗﺪاول اﻟﺴﻼﺳﻞ اﳊﺮﻓﻴﺔ‬


‫ﳝﻜﻦ إﺳــﻨﺎد ﺳﻠﺴــﻠﺔ ﺣﺮﻓﻴــﺔ إﱃ ﻣﺼــﻔﻮﻓﺔ ﺳــﺘﺨﺪام أﻣــﺮ اﻟــﺪﺧﻞ ‪ ،cin‬ﻓﻌﻠــﻰ ﺳــﺒﻴﻞ اﳌﺜــﺎل‪ ،‬ﺗﺴــﺘﺨﺪم اﻟﺘﻌﻠﻴﻤــﺔ اﻵﺗﻴــﺔ‬
‫ﻹﺳﻨﺎد ﺳﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ إﱃ اﳌﺼﻔﻮﻓﺔ ]‪:word[20‬‬
‫;‪cin>>word‬‬
‫ﺣﻴﺚ ﳜﺰن اﳌﺴﺘﺨﺪم اﻟﺴﻠﺴــﻠﺔ اﳌﺪﺧﻠــﺔ ﰲ اﳌﺼــﻔﻮﻓﺔ ‪ .word‬ﺗﻘــﻮم ﻫــﺬﻩ اﻟﺘﻌﻠﻴﻤــﺔ ﺑﻘـﺮاءة اﳊــﺮوف اﳌﺪﺧﻠــﺔ ﺣــﱴ اﻟﻮﺻــﻮل إﱃ‬
‫ﻓـﺮاغ أو ﺣــﺮف ﺟﺪوﻟــﺔ ‪ tab‬أو ﺣــﺮف اﻟﻌــﻮدة ﻋﻠــﻰ اﻟﺴــﻄﺮ أو ﺣــﺮف ﺎﻳــﺔ ﻣﻠــﻒ‪ .‬ﳝﻜــﻦ إﺧـﺮاج ﻗﻴﻤــﺔ اﻟﺴﻠﺴــﻠﺔ ﻋﻠــﻰ اﻟﺸﺎﺷــﺔ‬
‫ﺳﺘﺨﺪام أﻣﺮ اﻹﺧﺮاج ‪ cout‬ﺣﻴﺚ ﳝﻜﻦ إﺧﺮاج ﻗﻴﻤﺔ اﻟﺴﻠﺴﻠﺔ ﻟﻜﺎﻣﻞ ﻷﻣﺮ‪:‬‬
‫;‪cout<<word‬‬
‫أو ﺳﺘﺨﺪام ﺣﻠﻘﺔ ﻹﺧﺮاج ﺣﺮوف اﻟﺴﻠﺴﻠﺔ ﺑﺸﻜﻞ ﻣﺘﺘﺎل ﻷﻣﺮ‪:‬‬
‫)‪for (i=0;i<=19;i++‬‬
‫;‪cout<<word[i]<<"\n"<<endl‬‬
‫ﳝﻜﻨﻨــﺎ أﻳﻀـﺎً إدﺧــﺎل ﺳــﻄﺮ ﻛﺎﻣــﻞ إﱃ ﻣﺼــﻔﻮﻓﺔ‪ ،‬ﻧﺴــﺘﺨﺪم ﻟــﺬﻟﻚ إﺟـﺮاء ‪ cin.getline‬اﻟــﱵ ﲢﺘــﺎج إﱃ ﺛﻼﺛــﺔ وﺳــﻄﺎء‬
‫ﻫــﻲ‪ :‬اﳌﺼــﻔﻮﻓﺔ وﻃﻮﳍــﺎ واﳊــﺮف اﻟــﺬي ﳛــﺪد ﺎﻳــﺔ اﻟﺴــﻄﺮ‪ ،‬ﻛــﺄن ﻧﻜﺘــﺐ ﻋﻠــﻰ ﺳــﺒﻴﻞ اﳌﺜــﺎل اﻷواﻣــﺮ اﻵﺗﻴــﺔ ﻟﻘـﺮاءة ﻗــﻴﻢ ﻣﺼــﻔﻮﻓﺔ‬
‫أﺣﺮف ‪ sentence‬ﻣﻜﻮﻧﺔ ﻣﻦ ‪ 50‬ﺣﺮﻓﺎً‪:‬‬
‫;]‪char sentence[50‬‬
‫;)'‪cin.getline(sentence, 50, '\n‬‬
‫أو ﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫;]‪char sentence[50‬‬
‫;)‪cin.getline(sentence, 50‬‬
‫ﺗﻌــﲏ ﻫــﺬﻩ اﻷواﻣــﺮ اﻟﺘﺼ ـﺮﻳﺢ ﻋــﻦ ﻣﺼــﻔﻮﻓﺔ اﻷﺣــﺮف ‪ sentence‬ﻣﺆﻟﻔــﺔ ﻣــﻦ ‪ 50‬ﺣﺮﻓ ـﺎً وﻣــﻦ ﰒ ﻗ ـﺮاءة ﺳــﻄﺮ ﻣــﻦ ﻧــﺺ‬
‫ﻣﺪﺧﻞ ﺑﻮاﺳﻄﺔ ﻟﻮﺣــﺔ اﳌﻔــﺎﺗﻴﺢ إﱃ اﳌﺼــﻔﻮﻓﺔ‪ .‬ﻳﻨﺘﻬــﻲ اﻹﺟـﺮاء ﻻﺳــﺘﺪﻋﺎء ﻣــﻦ اﻟﺸــﻜﻞ اﻷول ﻋﻨــﺪﻣﺎ ﻳﻘــﻮم اﳌﺴــﺘﺨﺪم دﺧــﺎل‬
‫اﳊــﺮف ‪ \n‬أو ﻋﻨــﺪﻣﺎ ﻳﺼــﺎدف ﺣــﺮف اﻟﻌــﻮدة ﻋﻠــﻰ اﻟﺴــﻄﺮ أو ﲡــﺎوز ﻋــﺪد اﻹدﺧــﺎﻻت ‪ 49‬ﺣﺮﻓ ـﺎً‪ .‬ﰲ اﻟﺸــﻜﻞ اﻟﺜــﺎﱐ ﱂ ﻳــﺘﻢ‬
‫اﺳﺘﺨﺪام اﻟﻮﺳﻴﻂ اﻟﺜﺎﻟﺚ ﺣﻴﺚ ﳝﻜﻦ اﻋﺘﺒﺎرﻩ ﻗﻴﻤﺔ اﻓﱰاﺿﻴﺔ‪.‬‬

‫‪٢-٣‬‬
‫ﺗﺘﻀــﻤﻦ ﻣﻜﺘﺒــﺔ اﻹﺟـﺮاءات ‪ String‬ﺑﻠﻐــﺔ ‪ C++‬اﻟﻌﺪﻳــﺪ ﻣــﻦ اﻹﺟـﺮاءات اﻟــﱵ ﺗﺴــﺘﺨﺪم ﰲ ﺗــﺪاول اﻟﺴﻼﺳــﻞ اﳊﺮﻓﻴــﺔ‪،‬‬
‫ﺳﻨﺒﲔ ﻓﻴﻤﺎ ﰐ ﺑﻌﺾ ﻫﺬﻩ اﻹﺟﺮاءات‪:‬‬

‫أ‪ -‬ﺣﺴﺎب ﻃﻮل ﺳﻠﺴﻠﺔ ‪:strlen‬‬


‫ﺧﺬ اﻹﺟﺮاء ‪ strlen‬ﺳﻠﺴﻠﺔ ﺣﺮوف ﻛﻮﺳﻴﻂ ﳍﺎ وﺗﻌﻴﺪ ﻋﺪد اﻟﺮﻣﻮز ﳍﺬﻩ اﻟﺴﻠﺴﻠﺔ دون اﻟﺮﻣﺰ ذي اﻟﺮﻗﻢ ‪ .0‬و ﺧــﺬ‬
‫ﻫﺬا اﻹﺟﺮاء اﻟﺼﻴﻐﺔ اﻵﺗﻴﺔ‪:‬‬
‫)‪strlen(string‬‬

‫ب‪ -‬ﻧﺴﺦ ﺳﻠﺴﻠﺔ إﱃ أﺧﺮى ‪ strcpy‬و ‪:strncpy‬‬


‫ﺗﻜﺘﺐ ﻟﺼﻴﻐﺔ اﻟﻌﺎﻣﺔ ﻋﻠﻰ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫)‪strcpy(string1,string2‬‬
‫‪strcpy‬‬ ‫ﻳﻘــﻮم ﻫــﺬﻩ اﻹﺟ ـﺮاء ﺑﻨﺴــﺦ اﻟﺴﻠﺴــﻠﺔ ‪ string2‬إﱃ اﻟﺴﻠﺴــﻠﺔ ‪ .string1‬وﻳﻜــﺎﻓﺊ اﻹﺟ ـﺮاء ‪ strncpy‬اﻹﺟ ـﺮاء‬
‫ﻣﻊ إﺿﺎﻓﺔ وﺳﻴﻂ ﻟﺚ ‪ n‬ﳛﺪد ﻋﺪد اﻷﺣﺮف اﻟﱵ ﺳﺘﻨﺴﺦ ﻣﻦ اﻟﻮﺳﻴﻂ اﻟﺜﺎﱐ إﱃ اﻟﻮﺳﻴﻂ اﻷول‪.‬‬
‫)‪strncpy(string1,string2, n‬‬

‫ﻣﺜﺎل ‪٢-٣‬‬
‫>‪#include <iostream.h‬‬
‫>‪#include <string.h‬‬
‫)(‪main‬‬
‫{‬
‫;"‪char x[]=" Happy Birthday to you‬‬
‫;]‪char y[25], z[15‬‬
‫;‪cout<<"this string in array x is:"<<x<<endl‬‬
‫;‪cout<<"this string in array y is:"<<strcpy(y,x)<<endl‬‬
‫;)‪strncpy(z,x,14‬‬
‫;'‪z[14]='\0‬‬
‫;‪cout<<"this string in array z is:"<<z<<endl‬‬
‫;‪return 0‬‬
‫}‬
‫ﳐﺮﺟﺎت ﻫﺬا اﻟﱪ ﻣﺞ ﻫﻲ‪:‬‬
‫‪this string in array x is: Happy Birthday to you‬‬
‫‪this string in array y is: Happy Birthday to you‬‬
‫‪this string in array z is: Happy Birthday‬‬

‫‪strncat‬‬ ‫ت‪ -‬إﺿﺎﻓﺔ ﺳﻠﺴﻠﺔ إﱃ أﺧﺮى ‪ strcat‬و‬


‫ﺗﻜﺘﺐ ﻟﺼﻴﻐﺔ اﻟﻌﺎﻣﺔ ﻋﻠﻰ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫)‪strcat(string1,string2‬‬

‫‪٣-٣‬‬
‫ﻳﻘ ــﻮم ﻫ ــﺬﻩ اﻹﺟـ ـﺮاء ﺿ ــﺎﻓﺔ اﻟﺴﻠﺴ ــﻠﺔ ‪ string2‬إﱃ ﺎﻳ ــﺔ اﻟﺴﻠﺴ ــﻠﺔ ‪ .string1‬وﻳﻜ ــﺎﻓﺊ اﻹﺟـ ـﺮاء ‪ strncat‬اﻹﺟـ ـﺮاء‬
‫‪ strcat‬ﻣﻊ إﺿﺎﻓﺔ وﺳﻴﻂ ﻟﺚ ‪ n‬ﳛﺪد ﻋﺪد اﻷﺣﺮف اﻟﱵ ﺳﺘﻨﺴﺦ ﻣﻦ اﻟﻮﺳﻴﻂ اﻟﺜﺎﱐ إﱃ اﻟﻮﺳﻴﻂ اﻷول‪.‬‬
‫)‪strncat(string1,string2, n‬‬

‫ﻣﺜﺎل ‪٣-٣‬‬
‫>‪#include <iostream.h‬‬
‫>‪#include <string.h‬‬
‫)(‪int main‬‬
‫{‬
‫;" ‪char s1[20]="Happy‬‬
‫;" ‪char s2[]=" New Year‬‬
‫;""=]‪char s3[40‬‬
‫;‪cout<<"s1= "<<s1<<endl‬‬
‫;‪cout<<"s2= "<<s2<<endl‬‬
‫;‪cout<<"strcat(s1,s2) = "<<strcat(s1,s2)<<endl‬‬
‫;‪cout<<"strncat(s3,s1,6) = "<<strncat(s3,s1,6)<<endl‬‬
‫;‪cout<<"strcat(s3,s1) = "<<strcat(s3,s1)<<endl‬‬
‫;‪return 0‬‬
‫}‬
‫ﺗﺞ ﺗﻨﻔﻴﺬ ﻫﺬا اﻟﱪ ﻣﺞ ﻫﻮ‪:‬‬
‫‪s1= Happy‬‬
‫‪s2= New Year‬‬
‫‪strcat(s1,s2) = Happy New Year Happy‬‬
‫‪strncat(s3,s1,6) = Happy‬‬
‫‪strcat(s3,s1) = Happy Happy‬‬ ‫‪New Year‬‬

‫ث‪ -‬ﻣﻘﺎرﻧﺔ ﺳﻠﺴﻠﺘﲔ ‪ strcmp‬و ‪:strncmp‬‬


‫ﺗﻜﺘﺐ ﻫﺬﻩ اﻹﺟﺮاءات ﻟﺼﻴﻐﺔ اﻟﻌﺎﻣﺔ ﻋﻠﻰ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫)‪strcmp(string1,string2‬‬
‫ﻳﻌﻴﺪ ﻫﺬا اﻹﺟﺮاء اﻟﻘﻴﻤﺔ ‪ 0‬ﰲ ﺣﺎل ﺗﻄﺎﺑﻘﺖ اﻟﺴﻠﺴﻠﺘﲔ ‪ string1‬و ‪ string2‬وﻗﻴﻤﺔ ﺳﺎﻟﺒﺔ ﰲ ﺣﺎل ﻛﻮن اﻟﺴﻠﺴــﻠﺔ‬
‫‪ string1‬أﺻــﻐﺮ ﻣــﻦ اﻟﺴﻠﺴــﻠﺔ ‪ string2‬وﻗﻴﻤــﺔ ﻣﻮﺟﺒــﺔ ﰲ ﺣــﺎل ﻛــﻮن اﻟﺴﻠﺴــﻠﺔ ‪ string1‬أﻛــﱪ ﻣــﻦ اﻟﺴﻠﺴــﻠﺔ ‪.string2‬‬
‫وﻳﻜ ــﺎﻓﺊ اﻹﺟـ ـﺮاء ‪ strncmp‬اﻹﺟـ ـﺮاء ‪ strcmp‬ﻣ ــﻊ إﺿ ــﺎﻓﺔ وﺳ ــﻴﻂ ﻟ ــﺚ ‪ n‬ﳛ ــﺪد ﻋ ــﺪد اﻷﺣ ــﺮف اﻟﻮاﺟ ــﺐ ﻣﻘﺎرﻧﺘﻬ ــﺎ ﺑ ــﲔ‬
‫اﻟﺴﻠﺴﻠﺘﲔ‪.‬‬
‫)‪strncmp(string1,string2, n‬‬
‫ﺗــﺘﻢ ﻋﻤﻠﻴــﺔ اﳌﻘﺎرﻧــﺔ ﺑــﲔ اﻟﺴﻠﺴــﻠﺘﲔ ﲟﻘﺎرﻧــﺔ ﻛــﻞ ﺣــﺮﻓﲔ ﻣﺘﻘــﺎﺑﻠﲔ ﰲ اﻟﺴﻠﺴــﻠﺘﲔ‪ ،‬ﻓــﺈذا ﻛﺎﻧــﺖ ﻧﺘﻴﺠــﺔ ﻣﻘﺎرﻧــﺔ رﻣ ـﺰﻳﻦ‬
‫ﻣﺘﻘﺎﺑﻠﲔ ﰲ اﻟﺴﻠﺴﻠﺘﲔ ﺧﻄﺄ‪ ،‬أي ﻋﺪم ﺗﻄﺎﺑﻖ اﳊﺮﻓﲔ‪ ،‬ﺳﺘﻜﻮن ﻧﺘﻴﺠﺔ اﳌﻘﺎرﻧﺔ ﺑﲔ اﻟﺴﻠﺴﻠﺘﲔ ﺧﻄﺄ‪.‬‬

‫‪٤-٣‬‬
‫ﻣﺜﺎل ‪٤-٣‬‬
‫>‪#include <iostream.h‬‬
‫>‪#include <string.h‬‬
‫)(‪main‬‬
‫{‬
‫;"‪char *s1="Happy New Year‬‬
‫;"‪char *s2="Happy New Year‬‬
‫;"‪char *s3="Happy Holidays‬‬
‫;‪cout<<"s1="<<s1<<endl‬‬
‫;‪cout<<"s2="<<s2<<endl‬‬
‫;‪cout<<"s3="<<s3<<endl<<endl‬‬
‫;‪cout<<"strcmp(s1,s2)="<< strcmp(s1,s2)<<endl‬‬
‫;‪cout<<"strcmp(s1,s3)="<< strcmp(s1,s3)<<endl‬‬
‫;‪cout<<"strcmp(s3,s1)="<< strcmp(s3,s1)<<endl<<endl‬‬
‫;‪cout<<"strncmp(s1,s3,6)="<< strncmp(s1,s3,6)<<endl‬‬
‫;‪cout<<"strncmp(s1,s3,7)="<< strncmp(s1,s3,7)<<endl‬‬
‫;‪cout<<"strncmp(s3,s1,7)="<< strncmp(s3,s1,7)<<endl‬‬
‫;‪return 0‬‬
‫}‬
‫ﻧﺘﺎﺋﺞ ﺗﻨﻔﻴﺬ ﻫﺬﻩ اﻷواﻣﺮ ﻫﻲ‪:‬‬
‫‪s1=Happy New Year‬‬
‫‪s2=Happy New Year‬‬
‫‪s3=Happy Holidays‬‬

‫‪strcmp(s1,s2)=0‬‬
‫‪strcmp(s1,s3)=1‬‬
‫‪strcmp(s3,s1)=-1‬‬

‫‪strncmp(s1,s3,6)=0‬‬
‫‪strncmp(s1,s2,7)=0‬‬
‫‪strncmp(s3,s1,7)=-1‬‬

‫‪String‬‬ ‫‪ -٢-٣‬ﺳﻼﺳﻞ‬
‫‪Visual‬‬ ‫ﻳــﺘﻢ اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ ﻫــﺬا اﻟﻨــﻮع ﻣــﻦ اﻟﺴﻼﺳــﻞ اﳊﺮﻓﻴــﺔ ﺑﻄﺮﻳﻘــﺔ ﻣﺸــﺎ ﺔ ﻟﻄﺮﻳﻘــﺔ اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ اﻷﻏـﺮاض ﺑﻠﻐــﺔ‬
‫‪ C++‬أي أﻧــﻪ ﳝﻜــﻦ اﻟﺘﺼ ـﺮﻳﺢ ﻋﻨــﻪ ﻟﻄﺮﻳﻘــﺔ اﻟﺴــﺎﻛﻨﺔ ﲤﺎﻣ ـﺎً ﻛﺎﻟﺘﺼ ـﺮﻳﺢ ﻋــﻦ أي ﻣﺘﻐــﲑ‪ ،‬و ﻟﻄﺮﻳﻘــﺔ اﻟﺪﻳﻨﺎﻣﻴﻜﻴــﺔ ﺳــﺘﺨﺪام‬
‫اﳌﺆﺷﺮات‪ ،‬ﻛﻤﺎ ﳝﻜﻦ اﺳﺘﺨﺪام إﺟﺮاءات ﻫﺬﻩ اﻟﻔﺌﺔ ﻣﺒﺎﺷﺮة ﻛﻤﺎ ﰲ ﺣﺎﻟﺔ اﺳﺘﺨﺪام ‪ .Console‬وﻳﺘﻢ اﻟﺘﻌﺎﻣﻞ ﻣﻊ ﻫــﺬا اﻟــﻨﻤﻂ‬
‫ﻣﻦ اﻟﺴﻼﺳﻞ ﺳﺘﺨﺪام ﳎﻤﻮﻋﺔ ﻣﻦ اﻹﺟﺮاءات اﳌﻀﻤﻨﺔ ﰲ اﳌﻜﺘﺒﺔ‪ .‬ﺿﻤﻦ ﻓﻀــﺎء اﻷﲰــﺎء ‪ .System‬ﺗﺘﻀــﻤﻦ ﻓﺌــﺔ اﻷﻏـﺮاض‬
‫‪ String‬ﻋﺪداً ﻣﻦ اﻹﺟﺮاءات واﻟﺼﻔﺎت اﻟﱵ ﺗﺴﻤﺢ ﺑﺘﺪاول اﻟﺴﻼﺳﻞ اﳊﺮﻓﻴﺔ‪ .‬ﺳﻨﺒﲔ ﻓﻴﻤﺎ ﰐ ﺑﻌﺾ اﻟﻌﻤﻠﻴــﺎت اﳌﺪرﺟــﺔ ﰲ‬
‫إﺟﺮاءات ﻓﺌﺔ اﻷﻏﺮاض ‪:String‬‬
‫‪٥-٣‬‬
Length ‫ اﻟﺼﻔﺔ‬-‫أ‬
.‫ أي ﻋﺪد اﻟﺮﻣﻮز اﳌﻜﻮﻧﺔ ﻟﻠﺴﻠﺴﻠﺔ‬،‫ﺗﻌﻴﺪ ﻫﺬﻩ اﻟﺼﻔﺔ ﻃﻮل اﻟﺴﻠﺴﻠﺔ‬

:Copy ‫ إﺟﺮاء ﻧﺴﺦ ﺳﻠﺴﻠﺔ‬-‫ب‬


:‫ﺧﺬ ﻫﺬﻩ اﻹﺟﺮاءات اﻟﺼﻴﻐﺔ اﻵﺗﻴﺔ‬
Str=*Copy(String*)
.Str ‫ اﻟﺬي ﳝﻜﻦ وﺿﻌﻪ ﰲ ﺳﻠﺴﻠﺔ أﺧﺮى‬string ‫وﻫﻮ ﻳﻌﻴﺪ ﳏﺘﻮى اﻟﺴﻠﺴﻠﺔ‬
٥-٣ ‫ﻣﺜﺎل‬
s3‫ و‬s2 ‫ و‬s1 ‫ اﻵﰐ ﻋــﻦ ﺛﻼﺛــﺔ ﺳﻼﺳــﻞ ﺣﺮﻓﻴــﺔ‬Managed C++ Application ‫ﻳــﺘﻢ اﻟﺘﺼـﺮﻳﺢ ﰲ ﺑــﺮ ﻣﺞ ﻣــﻦ ﳕــﻂ‬
:Copy ‫وﻳﺒﲔ ﻛﻴﻔﻴﺔ اﺳﺘﺨﺪام اﻹﺟﺮاء‬
#include "stdafx.h"
#using <mscorlib.dll>
using namespace System;
#include <string.h>

void main()
{
String *s1="Happy ";
String *s2="New Year ";
String *s3;
Console::Write("s1=");
Console::WriteLine(s1);
Console::Write("s2=");
Console::WriteLine(s2);
s3=String::Copy(s1);
Console::Write("s3=");
Console::WriteLine(s3);
s3=String::Copy(s2);
Console::Write("s3=");
Console::WriteLine(s3);
}
:‫و ﺗﺞ ﺗﻨﻔﻴﺬ ﻫﺬا اﻟﱪ ﻣﺞ ﻫﻮ‬
s1=Happy
s2=New Year
s3=Happy
s3= New Year

٦-٣
‫ت‪ -‬إﺟﺮاء ﻣﻘﺎرﻧﺔ ﺳﻠﺴﻠﺘﲔ ‪:Compare‬‬
‫ﻳﻘﺎرن ﻫﺬا اﻹﺟﺮاء ﺑﲔ ﺳﻠﺴﻠﺘﲔ و ﺧﺬ ﻋﺪة أﺷﻜﺎل ﻣﻨﻬﺎ‪:‬‬
‫;)‪Compare(string, string‬‬
‫;)*‪Compare(String*, String‬‬
‫;)‪Compare(String*, String*, bool‬‬
‫;)‪Compare(String*, int, String*, int, int, bool‬‬
‫اﻟﺸــﻜﻞ اﻷول ﻳﻘــﺎرن ﺑــﲔ ﺳﻠﺴــﻠﺘﲔ ﻣﺼــﺮح ﻋﻨﻬﻤــﺎ ﻷﺳــﻠﻮب اﻟﺴــﺎﻛﻦ وﰲ اﻟﺸــﻜﻞ اﻟﺜــﺎﱐ ﻷﺳــﻠﻮب اﻟــﺪﻳﻨﺎﻣﻴﻜﻲ‪،‬‬
‫اﻟﺸﻜﻞ اﻟﺜﺎﻟﺚ ﻳﻘﺎرن ﺑﲔ ﺳﻠﺴﻠﺘﲔ دﻳﻨﺎﻣﻴﻜﻴﺘﲔ وﳝﻜﻦ ﻋﺪم اﻷﺧﺬ ﺑﻌــﲔ اﻻﻋﺘﺒــﺎر ﺣﺎﻟــﺔ اﳊــﺮف ﻛﺒــﲑ أو ﺻــﻐﲑ ﺑﻮﺿــﻊ ﻗﻴﻤــﺔ‬
‫‪ true‬ﻟﻠﻤﺘﻐﲑ ‪ bool‬أو ‪ false‬ﰲ ﺣﺎﻟﺔ اﻷﺧﺬ ﺑﻌــﲔ اﻻﻋﺘﺒــﺎر ﺣﺎﻟــﺔ اﳊــﺮف‪ ،‬أﻣــﺎ اﻟﺸــﻜﻞ اﻟﺮاﺑــﻊ ﻓﻴــﺘﻢ ﲢﺪﻳــﺪ رﻗــﻢ اﳊــﺮف اﻟــﺬي‬
‫ﺳﺘﺒﺪأ ﻣﻨﻪ ﻋﻤﻠﻴﺔ اﳌﻘﺎرﻧﺔ ﻟﻠﺴﻠﺴﻠﺔ اﻷوﱃ واﻟﺜﺎﻧﻴﺔ وﻋﺪد أﺣﺮف اﳌﻘﺎرﻧﺔ‪ .‬ﺗﻌﻴﺪ ﻫــﺬﻩ اﻹﺟـﺮاءات ﻗﻴﻤــﺔ ‪ 0‬ﰲ ﺣﺎﻟــﺔ اﻟﺘﻄــﺎﺑﻖ ﺑــﲔ‬
‫اﻟﺴﻠﺴــﻠﺘﲔ أو ﻗﻴﻤــﺔ ﺳــﺎﻟﺒﺔ ﰲ ﺣــﺎل ﻛــﻮن ﻗــﻴﻢ رﻣــﻮز اﻟﺴﻠﺴــﻠﺔ اﻷوﱃ أﻗــﻞ ﻣــﻦ رﻣــﻮز اﻟﺴﻠﺴــﻠﺔ اﻟﺜﺎﻧﻴــﺔ أو ﻗﻴﻤــﺔ ﻣﻮﺟﺒــﺔ إذا ﻛــﺎن‬
‫اﻟﻌﻜﺲ‪ ،‬أي إذا ﺻﺎدف رﻣﺰ ﻟﺴﻠﺴﻠﺔ اﻟﺜﺎﻧﻴﺔ أﻛﱪ ﻣﻦ اﻟﺮﻣﺰ اﳌﻘﺎﺑﻞ ﰲ اﻟﺴﻠﺴﻠﺔ اﻷوﱃ‪.‬‬
‫ﻣﺜﺎل ‪٦-٣‬‬
‫‪ s2‬و‪s3‬‬ ‫‪ Managed C++‬اﻵﰐ ﻋــﻦ ﺛﻼﺛــﺔ ﺳﻼﺳــﻞ ﺣﺮﻓﻴــﺔ ‪ s1‬و‬ ‫‪Application‬‬‫ﻳــﺘﻢ اﻟﺘﺼـﺮﻳﺢ ﰲ ﺑــﺮ ﻣﺞ ﻣــﻦ ﳕــﻂ‬
‫وﻧﺒﲔ ﻣﻦ ﺧﻼﻟﻪ ﻛﻴﻔﻴﺔ اﺳﺘﺨﺪام اﻹﺟﺮاء ‪:Compare‬‬
‫"‪#include "stdafx.h‬‬
‫>‪#using <mscorlib.dll‬‬
‫;‪using namespace System‬‬
‫>‪#include <string.h‬‬

‫)(‪void main‬‬
‫{‬
‫;" ‪String *s1="Happy‬‬
‫;" ‪String *s2="New Year‬‬
‫;" ‪String *s3="HAPPY‬‬
‫;)"=)‪Console::Write("Compare(s1,s2‬‬
‫;))‪Console::WriteLine(String::Compare(s1,s2‬‬
‫;)"=)‪Console::Write("Compare(s1,s3‬‬
‫;))‪Console::WriteLine(String::Compare(s1,s3‬‬
‫;)"=)‪Console::Write("Compare(s3,s1‬‬
‫;))‪Console::WriteLine(String::Compare(s3,s1‬‬
‫;)"=)‪Console::Write("Compare(s1,s3,false‬‬
‫;))‪Console::WriteLine(String::Compare(s1,s3,false‬‬
‫;)"=)‪Console::Write("Compare(s1,s3,true‬‬
‫;))‪Console::WriteLine(String::Compare(s1,s3,true‬‬
‫}‬

‫‪٧-٣‬‬
:‫ﺗﺞ ﺗﻨﻔﻴﺬ ﻫﺬا اﻟﱪ ﻣﺞ ﻫﻮ‬
Compare(s1,s2)=-1
Compare(s1,s3)=-1
Compare(s3,s1)=1
Compare(s1,s3,false)=-1
Compare(s1,s3,true)=0

Concat ‫ إﺿﺎﻓﺔ ﺳﻠﺴﻠﺔ إﱃ أﺧﺮى‬-‫ث‬


‫ و ﺧــﺬ‬،‫ﻳــﺪﻣﺞ ﻫــﺬا اﻹﺟ ـﺮاء ﺳﻠﺴــﻠﺔ إﱃ ﺳﻠﺴــﻠﺔ أﺧــﺮى واﻟﻨــﺎﺗﺞ ﻫــﻮ ﺳﻠﺴــﻠﺔ ﺟﺪﻳــﺪة ﺗﻌــﺎد ﲟﻮﺟــﺐ ﻫــﺬا اﻹﺟ ـﺮاء‬
:‫اﻟﺼﻴﻐﺔ اﻵﺗﻴﺔ‬
Concat(String1*, String2*,…);

٧-٣ ‫ﻣﺜﺎل‬
‫ وﻳــﺘﻢ‬s2 ‫ و‬s1 ‫ اﻵﰐ ﻋــﻦ ﺳﻠﺴــﻠﺘﲔ ﺣــﺮﻓﻴﺘﲔ‬Managed C++ Application ‫ﻳــﺘﻢ اﻟﺘﺼ ـﺮﻳﺢ ﰲ ﺑــﺮ ﻣﺞ ﻣــﻦ ﳕــﻂ‬
:‫اﻟﺪﻣﺞ ﻓﻴﻤﺎ ﺑﻴﻨﻬﻤﺎ‬
#include "stdafx.h"
#using <mscorlib.dll>
using namespace System;
#include <string.h>

void main()
{
String *s1="Happy ";
String *s2="New Year ";
Console::Write("s1=");Console::WriteLine(s1);
Console::Write("s2=");Console::WriteLine(s2);
Console::Write("Concat(s1,s2)=");
Console::WriteLine(String::Concat(s1,s2));
Console::Write("Concat(s2,s1)=");
Console::WriteLine(String::Concat(s2,s1));
}
:‫ﺗﺞ ﺗﻨﻔﻴﺬ ﻫﺬا اﻟﱪ ﻣﺞ ﻫﻮ‬
Happy
New Year
Concat(s1,s2)= Happy New Year
Concat(s2,s1)= New Year Happy

٨-٣
‫‪ -3‬ﺍﻟﱪﳎﺔ ﻏﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﻪ‬

‫‪Visual C++‬‬ ‫‪ -3-1‬ﺗﻌﺮﻳﻒ ﻓﺌﺎت اﻷﻏﺮاض ﺑﻠﻐﺔ‬


‫ﻳﺘﻢ ﺗﻌﺮﻳﻒ اﻟﻔﺌﺎت ﺑﻠﻐﺔ ‪ Visual C++‬ﺑﻮاﺳ ــﻄﺔ اﻟﻜﻠﻤﺔ اﶈﺠﻮزة ‪ .class‬وﲣﻀ ــﻊ ﻗﻮاﻋﺪ ﺗﺴ ــﻤﻴﺔ اﻟﻔﺌﺎت إﱃ ﻗﻮاﻋﺪ‬
‫ﺗﺴ ـ ـ ـ ـ ــﻤﻴﺔ اﻷﳕﺎط اﳉﺪﻳﺪة ﻟﻠﺒﻴﺎ ت اﻟﱵ رأﻳﻨﺎﻫﺎ ﺳ ـ ـ ـ ـ ــﺎﺑﻘﺎً‪ .‬واﻟﻮاﻗﻊ‪ ،‬إن ﻓﺌﺔ اﳌﻮاﺿ ـ ـ ـ ـ ــﻴﻊ ﻫﻲ ﳕﻂ ﺟﺪﻳﺪ ﻛﺎﻷﳕﺎط اﻟﱵ ﻳﻌﺮﻓﻬﺎ‬
‫اﳌﺴــﺘﺨﺪم‪ ،‬إﻻ أ ﺎ ﲢﺘﻮي إﺿــﺎﻓﺔ إﱃ اﻟﺒﻴﺎ ت ﺗﻮاﺑﻊ ﻳﻄﻠﻖ ﻋﻠﻴﻬﺎ اﺳــﻢ اﻟﻄﺮق ‪ .Methods‬ﻳﺴــﺘﺨﺪم اﺳــﻢ اﻟﻔﺌﺔ ﺑﻌﺪ ﺗﻌﺮﻳﻔﻬﺎ‬
‫ﻟﻠﺘﺼـﺮﻳﺢ ﻋﻦ اﳌﻮاﺿــﻴﻊ "اﻷﻏﺮاض" ﲤﺎﻣﺎً ﻛﺎﻟﺘﺼـﺮﻳﺢ ﻋﻦ اﳌﺘﻐﲑات‪ ،‬أي أن اﻟﻐﺮض ‪ Object‬ﻫﻮ ﻣﺘﻐﲑ ﻳﺮﺗﺒﻂ ﺑﻪ ﲨﻠﺔ اﻟﺒﻴﺎ ت‬
‫واﻟﺘﻮاﺑﻊ اﻟﱵ ﺗﺘﻀـ ـ ــﻤﻨﻬﺎ اﻟﻔﺌﺔ ‪ .Class‬ﳝﻜﻦ ﻟﻠﻔﺌﺔ أن ﺗﺘﻀ ـ ـ ــﻤﻦ ﻧﻮﻋﲔ ﻣﻦ اﻟﺒﻴﺎ ت واﻟﺘﻮاﺑﻊ ﲝﺴـ ـ ــﺐ ﺗﻮرﻳﺜﻬﺎ ﻟﻠﻔﺌﺎت اﻟﻼﺣﻘﺔ‬
‫وﻫﻲ ﺧﺎﺻﺔ ‪ private‬وﻋﺎﻣﺔ ‪.public‬‬
‫ﺳ ـ ـ ـ ـ ـ ـ ــﺘﺨﺪام اﻟﻜﻠﻤﺔ اﶈﺠﻮزة ‪،class‬‬ ‫‪struct‬‬ ‫ﺗﻌﺮف ﻓﺌﺔ اﻷﻏﺮاض ‪ Class‬ﺑﻠﻐﺔ ‪ Visual C++‬ﲤﺎﻣﺎً ﻛﺘﻌﺮﻳﻒ اﻟﺒﻨﻴﺔ‬
‫و ﺧﺬ اﻟﺘﺼﺮﻳﺢ اﻟﺸﻜﻞ اﻵﰐ‪:‬‬
‫]‪class Class_Name[:Class_base‬‬
‫{‬
‫‪Member_List‬‬
‫}‬
‫ﺣﻴﺚ‪:‬‬
‫‪ :Class_Name ‬ﻫﻮ اﺳﻢ اﻟﻔﺌﺔ وﲣﻀﻊ ﺑﺘﺴﻤﻴﺘﻬﺎ إﱃ ﻗﻮاﻋﺪ ﺗﺴﻤﻴﺔ اﳌﺘﻐﲑات ﺑﻠﻐﺔ ‪.Visual C++‬‬
‫‪ :Class_base ‬ﻫﻮ اﺳﻢ اﻟﻔﺌﺔ )أو اﻟﻔﺌﺎت( اﻷﺳﺎس اﻟﱵ ﺗ ﱠﻮرث ﺻﻔﺎ ﺎ ﻟﻠﻔﺌﺔ اﳉﺪﻳﺪة‪ ،‬وﻫﻮ اﺧﺘﻴﺎري ﲝﻴﺚ‬
‫ﳝﻜﻦ ﻟﻠﻔﺌﺔ أن ﺗﺘﻮارث ﺻﻔﺎت ﻓﺌﺔ أو ﻓﺌﺎت أﺧﺮى‪ ،‬أو ﳝﻜﻦ ﺗﻌﺮﻳﻔﻬﺎ ﻛﻔﺌﺔ اﺑﺘﺪاﺋﻴﺔ ﺑﺪون وراﺛﺔ ﺻﻔﺎت ﻓﺌﺎت‬
‫أﺧﺮى‪.‬‬
‫‪ :Member_List ‬ﻫﻲ ﻗﺎﺋﻤﺔ اﻟﺒﻴﺎ ت واﻟﻄﺮاﺋﻖ اﳌﻜﻮﻧﺔ ﻟﻠﻔﺌﺔ‪ ،‬ﺗﺘﻀﻤﻦ ﻫﺬﻩ اﻟﻘﺎﺋﻤﺔ ﺑﻴﺎ ت ﺗﻮاﺑﻊ )ﻃﺮاﺋﻖ(‬
‫ﺧﺎﺻﺔ ﺗﺒﺪأ ﻟﻜﻠﻤﺔ اﶈﺠﻮزة ‪ private:‬وأﺧﺮى ﻋﺎﻣﺔ ﺗﺒﺪأ ﻟﻜﻠﻤﺔ اﶈﺠﻮزة ‪.public:‬‬
‫ﺗﻜﺘﺐ أواﻣﺮ اﻟﺘﺎﺑﻊ اﳌﻌﺮف ﰲ اﻟﻔﺌﺔ ﺑﻌﺪ اﻟﺘﺼـ ـ ـ ـ ـﺮﻳﺢ ﻋﻨﻬﺎ ﲤﺎﻣﺎً ﻛﺄواﻣﺮ اﻟﺘﺎﺑﻊ اﻟﻌﺎدي ﺑﻌﺪ اﻟﺘﺼـ ـ ـ ـ ـﺮﻳﺢ ﻋﻦ ﺗﺮوﻳﺴ ـ ـ ـ ــﺘﻪ‬
‫ﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫‪Class_Name::Function_Name‬‬
‫ﺑﻴﺎ ت وﺗﻮاﺑﻊ ﺧﺎﺻﺔ وﻋﺎﻣﺔ‬ ‫‪-1‬‬

‫ﺗﺴـ ــﺘﺨﺪم اﻟﺒﻴﺎ ت واﻟﺘﻮاﺑﻊ اﳋﺎﺻـ ــﺔ ﻓﻘﻂ ﰲ اﻷﻏﺮاض اﻟﱵ ﺗﻌﺮف ﻣﻦ ﳕﻂ اﻟﻔﺌﺔ‪ ،‬وﻻ ﳝﻜﻦ اﺳـ ــﺘﺨﺪاﻣﻬﺎ ﰲ اﻟﻔﺌﺎت‬
‫واﳌﻮاﺿ ـ ــﻴﻊ اﻟﱵ ﺗﺘﻮارث ﺻـ ــﻔﺎت ﻫﺬﻩ اﻟﻔﺌﺔ أو ﰲ أي ﻣﻦ اﻟﻔﺌﺎت اﻟﱵ ﺗﺴـ ــﺘﺪﻋﻲ أﻏﺮاﺿ ـ ـﺎً ﻣﻦ ﻫﺬﻩ اﻟﻔﺌﺔ‪ ،‬وﻳﺘﻢ ﺗﻌﺮﻳﻔﻬﺎ ﲢﺖ‬
‫اﺳــﻢ ‪ private‬أﺛﻨﺎء اﻟﺘﺼ ـﺮﻳﺢ ﻋﻨﻬﺎ ﰲ اﻟﻔﺌﺔ‪ .‬أﻣﺎ اﻟﺒﻴﺎ ت واﻟﺘﻮاﺑﻊ اﻟﻌﺎﻣﺔ ﻓﻬﻲ ﻋﻠﻰ ﻋﻜﺲ اﳋﺎﺻــﺔ ﺎ ﻗﺎﺑﻠﺔ ﻷن ﺗ ﱠﻮرث إﱃ‬

‫‪١-٣‬‬
‫ﻓﺌﺎت أﺧﺮى وﳝﻜﻦ أن ﺗﺴــﺘﺨﺪم ﰲ اﻷﻏﺮاض اﻟﱵ ﺗﻌﺮف ﻣﻦ ﳕﻂ اﻟﻔﺌﺔ وﰲ ﻛﻞ اﳌﻮاﺿــﻴﻊ اﻟﱵ ﺗﺮث ﺻــﻔﺎت ﻫﺬﻩ اﻟﻔﺌﺔ‪ ،‬وﻳﺘﻢ‬
‫ﺗﻌﺮﻳﻔﻬﺎ ﲢﺖ اﺳﻢ ‪ public‬أﺛﻨﺎء اﻟﺘﺼﺮﻳﺢ ﻋﻨﻬﺎ ﰲ اﻟﻔﺌﺔ‪.‬‬
‫‪constructor & destructor‬‬ ‫ﱐ اﻟﻔﺌﺔ وﻣﻬﺪﻣﻬﺎ‬ ‫‪-2‬‬

‫ﻫﻲ ﺗﻮاﺑﻊ ﺗﺪرج ﲢﺖ ﻗﺎﺋﻤﺔ اﻟﺘﻮاﺑﻊ اﻟﻌﺎﻣﺔ‪ ،‬ﻳﺴ ـ ــﺘﺨﺪم ﱐ اﻟﻔﺌﺔ ﰲ ﻴﺌﺔ ﺑﻴﺎ ت اﻟﻔﺌﺔ ﻛﻤﺎ ﻳﺴ ـ ــﺘﺨﺪم اﳌﻬﺪم ﺑﺘﻬﺪﱘ‬
‫ﻫﺬﻩ اﻟﺒﻴﺎ ت‪ ،‬أي إﺧﻼء اﻟﺬاﻛﺮة اﻟﺪاﺧﻠﻴﺔ ﻣﻦ ﺑﻴﺎ ت اﻟﻔﺌﺔ‪ .‬ﻫﺬﻩ اﻟﺘﻮاﺑﻊ اﺧﺘﻴﺎرﻳﺔ ﰲ اﻟﻔﺌﺔ ﺑﻠﻐﺔ ‪ ،Visual C++‬وﻫﻲ ﻻ‬
‫ﺗﻌﻴﺪ أي ﻗﻴﻤﺔ ﺣﻴﺚ ﻳﻌﺘﱪ ﻣﻦ اﳋﻄﺄ ﺗﻌﺮﻳﻔﻬﺎ ﻋﻠﻰ أ ﺎ ﺗﻌﻴﺪ ﻗﻴﻤﺔ‪ .‬إذا ﱂ ﻳﺘﻢ ﺗﻌﺮﻳﻒ ﱐ اﻟﻔﺌﺔ ﻳﺘﻢ ﻴﺌﺔ ﺑﻴﺎ ت اﻟﻔﺌﺔ ﺗﻠﻘﺎﺋﻴﺎً‬
‫ﺳـ ــﻨﺎد ﻗﻴﻢ ﻏﲑ ﳏﺪدة ﳍﺎ ﻋﻨﺪ اﺳـ ــﺘﺪﻋﺎء أي ﻏﺮض ﻣﻦ ﳕﻂ ﻫﺬﻩ اﻟﻔﺌﺔ‪ ،‬ﻛﻤﺎ أن ﻋﺪم ﺗﻌﺮﻳﻒ اﳌﻬﺪم ﻳﺆدي إﱃ ﺑﻘﺎء ﺑﻴﺎ ت‬
‫اﻟﻔﺌﺔ ﳐﺰﻧﺔ ﰲ اﻟﺬاﻛﺮة اﻟﺪاﺧﻠﻴﺔ اﶈﺠﻮزة ﳍﺎ ﺣﱴ اﻧﺘﻬﺎء ﺗﻨﻔﻴﺬ اﻟﱪ ﻣﺞ‪ .‬ﺧﺬ ﻫﺬﻩ اﻟﺘﻮاﺑﻊ أﺳ ـ ـ ــﻢ اﻟﻔﺌﺔ ﻧﻔﺴ ـ ـ ــﻪ‪ ،‬أي أن اﻟﺒﺎﱐ‬
‫ﺧﺬ اﺳﻢ اﻟﻔﺌﺔ وﻣﻬﺪﻣﻬﺎ أﻳﻀﺎً‪ ،‬وﻧﺴﺘﺨﺪم اﻟﺮﻣﺰ "~ ‪ "Telda‬ﰲ ﺑﺪاﻳﺔ اﺳﻢ اﳌﻬﺪم ﻟﺘﻤﻴﻴﺰﻩ ﻋﻦ ﻧﻴﻪ‪.‬‬
‫ﻣﺜﺎل ‪١-٣‬‬
‫ﻋﺮف ﻓﺌﺔ ﺳـ ـ ـ ـ ــﻢ ‪ String‬ﻳﻘﻮم ﻧﻴﻬﺎ )اﻟﺬي ﺧﺬ اﺳـ ـ ـ ـﻢ اﻟﻔﺌﺔ ﻧﻔﺴ ـ ـ ــﻪ ‪ (String‬ﺑﺘﻌﺮﻳﻒ ﻣﻮﻗﻊ ﰲ اﻟﺬاﻛﺮة ﻟﺘﺨﺰﻳﻦ‬
‫ﺣﺮف ﻋﻠﻰ ﺷﻜﻞ ﻣﺆﺷﺮ وﻳﻘﻮم ﻣﻬﺪﻣﻪ ‪ ~String‬ﲝﺬف ﻫﺬا اﳌﺆﺷﺮ ﻣﻦ اﻟﺬاﻛﺮة اﻟﺪاﺧﻠﻴﺔ‪.‬‬
‫اﳊﻞ‪:‬‬
‫>‪#include <string.h‬‬
‫‪class String‬‬
‫{‬
‫‪public:‬‬
‫;)‪String(char *ch‬‬
‫;)(‪~String‬‬
‫;‪char *_text‬‬
‫;}‬

‫) ‪String::String( char *ch‬‬


‫{‬
‫;]‪_text = new char[strlen( ch ) + 1‬‬
‫;) ‪if( _text ) strcpy( _text, ch‬‬
‫}‬

‫)(‪String::~String‬‬
‫{‬
‫;‪Delete _text‬‬
‫}‬
‫ﺗﻌﺮﻳﻒ ﻏﺮض ﻣﻦ ﳕﻂ اﻟﻔﺌﺔ واﺳﺘﺪﻋﺎء ﺗﻮاﺑﻌﻪ‬ ‫‪-3‬‬

‫ﳝﻜﻦ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻏﺮض ﻣﻦ ﳕﻂ اﻟﻔﺌﺔ اﳌﻌﺮﻓﺔ وﻳﺘﻢ اﺳﺘﺪﻋﺎء ﺗﻮاﺑﻊ ﻫﺬا اﻟﻐﺮض ﺳﺘﺨﺪام اﻟﻨﻘﻄﺔ "‪ ".‬ﻟﺸﻜﻞ‪:‬‬
‫‪Object_Name.Function_Name‬‬
‫‪٢-٣‬‬
‫ﻋﻨﺪ اﺳــﺘﺪﻋﺎء اﻟﻐﺮض ﺳــﻴﺘﻢ اﺳــﺘﺪﻋﺎء ﱐ اﻟﻐﺮض ﺗﻠﻘﺎﺋﻴﺎً‪ ،‬أي ﺳــﻴﻘﻮم اﳌﱰﺟﻢ ﺑﺘﻨﻔﻴﺬ أواﻣﺮ اﻟﺘﺎﺑﻊ اﻟﺬي ﺧﺬ ﻧﻔﺲ‬
‫اﺳ ـ ـ ـ ـ ــﻢ اﻟﻐﺮض وﻳﻘﻮم ﺑﺘﻨﻔﻴﺬ أواﻣﺮﻩ ﰲ ﺣﺎل وﺟﻮدﻩ‪ .‬وﳍﺬا ﺗُـ ﱠﻌﺮف ﻫﺬﻩ اﻟﺘﻮاﺑﻊ ﻋﻨﺪﻣﺎ ﻧﺮﻳﺪ إﻋﻄﺎء ﻗﻴﻢ اﺑﺘﺪاﺋﻴﺔ ﳏﺪدة ﻟﺒﻴﺎ ت‬
‫اﻟﻐﺮض ﻋﻨﺪ ﺗﻜﻮﻳﻨﻪ‪ ،‬ﻋﻠﻤﺎً ن أي ﺑﻊ ﻣﻦ اﻟﺘﻮاﺑﻊ اﻷﻋﻀﺎء ﳝﻜﻨﻪ أن ﻳﻐﲑ ﻗﻴﻢ اﻟﺒﻴﺎ ت ﰲ اﻟﻐﺮض‪.‬‬
‫ﻣﺜﺎل ‪٢-٣‬‬
‫‪minute‬‬ ‫َﻛﻮن ﻓﺌﺔ ﻟﻄﺒﺎﻋﺔ اﻟﻮﻗﺖ وﻓﻖ ﺷــﻜﻞ ‪ 24‬ﺳــﺎﻋﺔ و ‪ 12‬ﺳــﺎﻋﺔ‪ ،‬ﲝﻴﺚ ﺗﻌﺘﱪ ﺑﻴﺎ ت ﻫﺬﻩ اﻟﻔﺌﺔ ﻫﻲ ‪ hour‬و‬
‫و ‪ ،second‬ﺧﺎﺻﺔ ﻟﻔﺌﺔ‪ ،‬وﺗﻮاﺑﻌﻬﺎ ﻫﻲ‪ Time :‬و ‪ SetTime‬و ‪ PrintTime‬و ‪ PrintStandard‬ﻋﺎﻣﺔ‪.‬‬
‫اﳊﻞ‪:‬‬
‫>‪#include <iostream.h‬‬
‫‪class Time‬‬
‫{‬
‫‪private:‬‬
‫;‪int hour‬‬
‫;‪int minute‬‬
‫;‪int second‬‬
‫‪public:‬‬
‫;)(‪Time‬‬
‫;)(‪void SetTime‬‬
‫;)(‪void PrintTime‬‬
‫;)(‪void PrintStandard‬‬
‫;}‬

‫اﻟﺘﺎﺑﻊ ‪ Time‬ﻫﻮ ﲟﺜﺎﺑﺔ ﱐ ﻟﻠﻐﺮض ﺣﻴﺚ ﻳﺴ ـ ـ ـ ـ ــﺘﺨﺪم ﻟﺘﻬﻴﺌﺔ ﺑﻴﺎ ت اﻟﻐﺮض‪ ،‬أﻣﺎ اﻟﺘﺎﺑﻊ ‪ SetTime‬ﻓﻴﺴ ـ ـ ـ ـ ــﺘﺨﺪم‬
‫ﻹدﺧــﺎل اﻟﻮﻗــﺖ‪ .‬اﻟﺒﻴــﺎ ت ‪ hour‬و ‪ minute‬و ‪ second‬ﻫﻲ ﺑﻴــﺎ ت ﺧــﺎﺻـ ـ ـ ـ ـ ــﺔ ﻟﻐﺮض‪ ،‬أي أﻧــﻪ ﻻ ﳝﻜﻦ ﺗﻐﻴﲑ ﻗﻴﻤﻬــﺎ أو‬
‫ﻃﺒﺎﻋﺘﻬﺎ إﻻ ﺳ ـ ـ ــﺘﺨﺪام ﺗﻮاﺑﻊ اﻟﻐﺮض وﻣﻦ داﺧﻞ اﻟﻐﺮض ﻓﻘﻂ‪ .‬أﻣﺎ ﺗﻮاﺑﻊ اﻟﻐﺮض ﻓﻬﻲ ﻋﺎﻣﺔ و ﻟﺘﺎﱄ ﳝﻜﻦ اﺳ ـ ـ ــﺘﺪﻋﺎؤﻫﺎ ﻣﻦ‬
‫ﺧﺎرج اﻟﻐﺮض‪.‬‬
‫ﺗُﻌﱠﺮف ﺗﻮاﺑﻊ اﻟﻐﺮض ﲤﺎﻣﺎً ﻛﺘﻌﺮﻳﻒ اﻟﺘﻮاﺑﻊ اﻟﻌﺎدﻳﺔ ﻣﻊ ﻓﺎرق ﺑﺴـ ــﻴﻂ ﺑﻮﺿـ ــﻊ ﳕﻂ اﻟﺘﺎﺑﻊ واﺳـ ــﻢ اﻟﻐﺮض اﻟﺬي ﻳﺘﻀـ ــﻤﻦ‬
‫اﻟﺘﺎﺑﻊ ﻣﺘﺒﻮﻋﺎً ﻟﺮﻣﻮز "‪ "::‬وﻣﻦ ﰒ اﺳﻢ اﻟﺘﺎﺑﻊ‪ .‬وﳝﻜﻦ ﺗﻌﺮﻳﻒ ﺗﻮاﺑﻊ اﻟﻐﺮض ‪ Time‬ﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫)(‪Time::Time‬‬
‫{‬
‫;‪hour = 0‬‬
‫;‪minute = 0‬‬
‫;‪second = 0‬‬
‫}‬

‫)(‪void Time::SetTime‬‬

‫‪٣-٣‬‬
{
int h,m,s;
cout<<endl;
cout<<"Hour:";cin>>h;
cout<<"Minute:";cin>>m;
cout<<"Second:";cin>>s;
if (h >= 0 && h < 24) hour = h;
else hour= 0;
if (m >= 0 && m < 60) minute = m;
else minute= 0;
if (s >= 0 && s < 60) second = s;
else second = 0;
}

void Time::PrintTime()
{
if (hour < 10) cout<<"0"<<hour<<":"; else cout<<hour<<":";
if (minute < 10) cout<<"0"<<minute<<":";
else cout<<minute<<":";
if (second < 10) cout<<"0"<<second; else cout<<second;
}

void Time::PrintStandard()
{
if (hour == 0 || hour==12) cout<<"12:";
else cout<<hour%12<<":";
if (minute < 10) cout<<"0"<<minute<<":";
else cout<<minute<<":";
if (second < 10) cout<<"0"<<second; else cout<<second;
if (hour<12) cout<<"AM"; else cout<<"PM";
}

:‫ وﻣﻦ ﰒ ﻳﺘﻢ اﺳﺘﺪﻋﺎء ﺗﻮاﺑﻊ ﻫﺬا اﻟﻐﺮض ﻟﺸﻜﻞ اﻟﺘﺎﱄ‬،‫أﻣﺎ اﺳﺘﺨﺪام ﻫﺬا اﻟﻐﺮض ﻓﻴﺘﻢ ﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺘﻐﲑ ﻣﻦ ﳕﻄﻪ‬
void main()
{
Time T;
cout << "The initial time is ";
T.PrintTime();
cout << endl << "The initial standard time is ";
T.PrintStandard();
T.SetTime();

٤-٣
‫;" ‪cout << endl << endl << "Time after SetTime is‬‬
‫;)(‪T.PrintTime‬‬
‫;" ‪cout << endl << "Standard time after setTime is‬‬
‫;)(‪T.PrintStandard‬‬
‫;‪cout << endl‬‬
‫}‬
‫ﻋﻨﺪ اﻟﺘﺼـﺮﻳﺢ ﻋﻦ اﳌﺘﻐﲑ ‪ T‬ﻣﻦ اﻟﻨﻤﻂ ‪ Time‬ﻳﺘﻢ اﺳــﺘﺪﻋﺎء ﱐ اﻟﻐﺮض )(‪ Time‬ﺗﻠﻘﺎﺋﻴﺎً‪ ،‬وﻳﻘﻮم ﻫﺬا اﻟﺘﺎﺑﻊ ﺳــﻨﺎد‬
‫اﻟﻘﻴﻢ ‪ 0‬إﱃ ﻛﻞ ﻣﻦ اﳌﺘﻐﲑات اﳌﻤﺜﻠﺔ ﻟﻠﺒﻴﺎ ت اﳋﺎﺻ ـ ـ ـ ـ ــﺔ ﻟﻐﺮض ‪ hours‬و ‪ minute‬و ‪ .second‬وﻋﻨﺪ اﺳ ـ ـ ـ ـ ــﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ‬
‫)(‪ PrintTime‬ﻷﻣﺮ )(‪ T.PrintTime‬ﺗﺘﻢ ﻃﺒـ ــﺎﻋـ ــﺔ اﻟﻮﻗـ ــﺖ اﻻﺑﺘـ ــﺪاﺋﻲ ﻣﻦ أﺟـ ــﻞ اﻟﻘﻴﻢ ‪ ،0‬أﻣـ ــﺎ اﺳ ـ ـ ـ ـ ـﺘـ ــﺪﻋـ ــﺎء اﻟﺘ ـ ــﺎﺑﻊ‬
‫)‪ SetTime(15,43,16‬ﻓﺴـ ـ ــﻴﺘﻢ ﺗﻐﻴﲑ ﻗﻴﻢ اﳌﺘﻐﲑات ‪ hour‬و ‪ minute‬و ‪ second‬وﺑﻄﺒﺎﻋﺔ اﻟﻮﻗﺖ ﻣﻦ ﺟﺪﻳﺪ ﺳ ـ ـ ــﺘﻄﺒﻊ ﻗﻴﻤﺔ‬
‫اﻟﺘﻮﻗﻴــﺖ اﳉــﺪﻳــﺪ ﻷﻣﺮ )(‪ T.PrintTime‬ﺳ ـ ـ ـ ـ ــﺘﺘﻢ ﻃﺒــﺎﻋــﺔ اﻟﻮﻗــﺖ اﳉــﺪﻳــﺪ وﻓﻖ اﻟﺘﻮﻗﻴــﺖ ﻋﻠﻰ ‪ 24‬ﺳـ ـ ـ ـ ـ ــﺎﻋــﺔ‪ ،‬أﻣــﺎ اﻟﺘــﺎﺑﻊ‬
‫)(‪ T.PrintStandard‬ﻓﻴﻄﺒﻊ اﻟﻮﻗﺖ اﻟﻘﻴﺎﺳﻲ ﻋﻠﻰ ‪ 12‬ﺳﺎﻋﺔ‪.‬‬
‫‪ -3-1-1‬اﺳﺘﺨﺪام اﻷﻏﺮاض ﻛﻌﻨﺎﺻﺮ ﰲ ﻓﺌﺎت أﺧﺮى‬
‫ﻟﻘﺪ ذﻛﺮ ﺳــﺎﺑﻘﺎً أن اﺳــﺘﺨﺪام اﻷﻏﺮاض ﻳﺘﻢ ﲤﺎﻣﺎً ﻛﺎﺳــﺘﺨﺪام اﻷﳕﺎط اﻟﻘﻴﺎﺳــﻴﺔ واﻷﳕﺎط اﳉﺪﻳﺪة اﻟﱵ ﻧﻌﺮﻓﻬﺎ داﺧﻞ‬
‫اﻟﱪ ﻣﺞ‪ ،‬وﺑﺬﻟﻚ ﳝﻜﻨﻨﺎ اﻟﺘﺼ ـ ـ ـ ـ ـﺮﻳﺢ ﻋﻦ أﻏﺮاض ﺳ ـ ـ ـ ـ ــﺎﻛﻨﺔ ﻛﺎﻟﺜﻮاﺑﺖ وأﻏﺮاض ﻣﺘﻐﲑة ﻛﺘﻌﺮﻳﻒ اﳌﺘﻐﲑات وأﻏﺮاض دﻳﻨﺎﻣﻴﻜﻴﺔ‬
‫ﺳــﺘﺨﺪام اﳌﺆﺷـﺮات‪ .‬وﳝﻜﻦ ﻟﻜﻞ ﻣﻨﻬﺎ أن ﺗُـ ﱠﻌﺮف أﻳﻀـﺎً ﻛﻌﻨﺎﺻــﺮ ﺧﺎﺻــﺔ ﻟﻔﺌﺔ ﺳــﺘﺨﺪام اﻟﺘﻌﺮﻳﻒ ‪ private‬وﻋﻨﺎﺻــﺮ ﻋﺎﻣﺔ‬
‫ﺳــﺘﺨﺪام ‪ .public‬وﻋﻨﺪ اﺳــﺘﺨﺪام اﻟﻔﺌﺎت اﳌﻌﺮﻓﺔ ﻣﺴــﺒﻘﺎً ﻛﺄﻋﻀــﺎء ﰲ ﻓﺌﺔ ﺟﺪﻳﺪة ﳚﺐ اﻻﻧﺘﺒﺎﻩ إﱃ ﺑﻨﺎة ﻫﺬﻩ اﻟﻔﺌﺎت‪ ،‬ﻓﺈذا‬
‫ﻛﺎﻧﺖ ﻣﻌﺮﻓﺔ ﺑﻮﺳ ــﻄﺎء ﻓﻴﺠﺐ اﺳ ــﺘﺪﻋﺎؤﻫﺎ ﺑﻘﻴﻢ اﺑﺘﺪاﺋﻴﺔ ﺑﻘﻮاﻋﺪ ﳏﺪدة‪ ،‬أﻣﺎ إذا ﱂ ﺗﻜﻦ ﻣﻌﺮﻓﺔ أو ﻛﺎﻧﺖ ﻣﻌﺮﻓﺔ ﺑﺪون وﺳ ــﻄﺎء‬
‫ﻓﺘﺘﻢ ﻴﺌﺔ ﺑﻴﺎ ﺎ ﺗﻠﻘﺎﺋﻴﺎً ﺑﺪون اﺳﺘﺪﻋﺎء ﻫﺬﻩ اﻟﺘﻮاﺑﻊ‪ ،‬اﳌﺜﺎل اﻟﺘﺎﱄ ﻳﺒﲔ ﻃﺮق اﺳﺘﺪﻋﺎء ﻫﺬﻩ اﻟﻔﺌﺎت‪.‬‬
‫ﻣﺜﺎل ‪٣-٣‬‬
‫ﻋﺮف ﻓﺌﺔ ﺟﺪﻳﺪة ﳊﺴ ــﺎب ﻣﺪة ﳏﺎﺿ ــﺮة ﺑﻄﺮح ﺗﻮﻗﻴﺖ ﺑﺪء اﶈﺎﺿ ــﺮة ﻣﻦ ﺗﻮﻗﻴﺖ ﺎﻳﺘﻬﺎ‪ .‬اﺳ ــﺘﺨﺪم ﰲ ﲢﺪﻳﺪ ﻫﺬﻳﻦ‬
‫اﻟﺘﻮﻗﻴﺘﲔ اﻟﻔﺌﺔ ‪ Time‬اﻟﱵ ﺳﺒﻖ ﺗﻌﺮﻳﻔﻬﺎ‪.‬‬
‫اﳊﻞ‪:‬‬
‫ﻟﻠﺘﻤﻜﻦ ﻣﻦ اﺳـ ـ ـ ـ ــﺘﺨﺪام اﳌﺘﻐﲑات اﻟﱵ ﲤﺜﻞ ﺑﻴﺎ ت اﻟﻔﺌﺔ ‪ Time‬ﰲ اﻟﻔﺌﺔ اﳉﺪﻳﺪة ﻻ ﺑﺪ ﻣﻦ ﺗﻌﺮﻳﻔﻬﺎ ﻋﻠﻰ ﺷـ ـ ـ ـ ــﻜﻞ‬
‫‪ public‬ﺑﺪﻻً ﻣﻦ ﺗﻌﺮﻳﻔﻬﺎ ﻋﻠﻰ ﺷﻜﻞ ‪ private‬وﺗﺼﺒﺢ ﺗﻌﺮﻳﻔﺎت اﻟﻔﺌﺎت ﻋﻠﻰ اﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫‪class Time‬‬
‫{‬
‫‪public:‬‬
‫;‪int hour‬‬
‫;‪int minute‬‬
‫;‪int second‬‬
‫‪public:‬‬
‫;)(‪Time‬‬

‫‪٥-٣‬‬
void SetTime(int, int, int);
void PrintTime();
void PrintStandard();
};

class Course
{
private:
int hour;
int minute;
public:
Time Start, End;
Course();
void TimeCourse();
void PrintCourse();
};
:‫ ﻓﺴﻨﻌﺮﻓﻬﺎ ﻛﻤﺎ ﻳﻠﻲ‬Course ‫أﻣﺎ ﺗﻮاﺑﻊ اﻟﻔﺌﺔ‬
Course::Course()
{
Start.SetTime();
End.SetTime();
}

void Course::TimeCourse()
{
hour=End.hour-Start.hour;
minute=End.minute-Start.minute;
if (minute<0)
{
minute+=60;
hour-=1;
}
}

void Course::PrintCourse()
{
TimeCourse();
cout<<"The Time of the course is" <<hour<<"H:"
<<minute<<endl;
}
:‫ ﺑﻮﺳﻄﺎء ﻟﺘﺤﺪﻳﺪ ﻗﻴﻢ اﺑﺘﺪاﺋﻴﺔ ﻟﻠﻐﺮض ﻓﻴﺘﻢ ﻟﺸﻜﻞ اﻟﺘﺎﱄ‬Time ‫أﻣﺎ ﰲ ﺣﺎﻟﺔ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﱐ اﻟﻔﺌﺔ‬
٦-٣
‫‪class Time‬‬
‫{‬
‫‪public:‬‬
‫;‪int hour‬‬
‫;‪int minute‬‬
‫;‪int second‬‬
‫‪public:‬‬
‫;)‪Time(int, int, int‬‬
‫;)(‪void SetTime‬‬
‫;)(‪void PrintTime‬‬
‫;)(‪void PrintStandard‬‬
‫;}‬

‫ﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬ ‫‪Course‬‬ ‫إن ﺗﻌﺮﻳﻒ أﻏﺮاض ﻣﻦ ﻫﺬﻩ اﻟﻔﺌﺔ ﰲ اﻟﻔﺌﺔ اﳉﺪﻳﺪة ﻳﺘﻄﻠﺐ اﻟﺘﺼﺮﻳﺢ ﻋﻨﻬﺎ ﰲ ﱐ اﻟﻔﺌﺔ‬
‫)‪Course::Course():Start(0,0,0),End(0,0,0‬‬
‫{‬
‫;)(‪Start.SetTime‬‬
‫;)(‪End.SetTime‬‬
‫}‬
‫‪ -3-1-2‬اﻷﻏﺮاض اﻟﺪﻳﻨﺎﻣﻴﻜﻴﺔ‬
‫ﻳﻄﻠﻖ ﻋﻠﻰ اﻟﻔﺌﺎت اﳌﺸــﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺎت ﻟﻄﺮﻳﻘﺔ اﻟﱵ رأﻳﻨﺎﻫﺎ ﺣﱴ اﻵن ﻟﻔﺌﺎت اﻟﺴــﺎﻛﻨﺔ‪ .‬وﺑﻄﺮﻳﻘﺔ ﻣﺸــﺎ ﺔ ﻟﺘﻌﺮﻳﻒ‬
‫اﳌﺆﺷـ ـ ـ ـ ـﺮات ﻟﻠﺒﻴﺎ ت ﻣﻦ اﻷﳕﺎط اﻟﻘﻴﺎﺳ ـ ـ ـ ــﻴﺔ واﳌﻌﺮﻓﺔ ﺳـ ـ ـ ـ ـ ــﺎﺑﻘﺎً ﳝﻜﻨﻨﺎ ﺗﻌﺮﻳﻒ أﻏﺮاض دﻳﻨﺎﻣﻴﻜﻴﺔ ﻣﺸ ـ ـ ـ ــﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺎت اﳌﻌﺮﻓﺔ‪،‬‬
‫وﺗﺴـ ــﺘﺨﺪم أﻳﻀـ ـﺎً اﻟﻌﻤﻠﻴﺎت ‪ new‬ﻹﻧﺸـ ــﺎء ﻏﺮض ﺟﺪﻳﺪ و ‪ delete‬ﻹﻟﻐﺎﺋﻪ ﺑﻠﻐﺔ ‪ .Visual C++‬وﻟﻠﻮﺻـ ــﻮل إﱃ أﻋﻀـ ــﺎء أي‬
‫ﻏﺮض دﻳﻨﺎﻣﻴﻜﻲ ﻧﺴﺘﺨﺪم رﻣﺰ اﳌﺆﺷﺮ ">‪ "-‬ﺑﺪﻻً ﻣﻦ اﺳﺘﺨﺪام رﻣﺰ اﻟﻨﻘﻄﺔ ﰲ ﺣﺎﻟﺔ اﻷﻏﺮاض اﻟﺴﺎﻛﻨﺔ‪ .‬ﻧﺒﲔ ﰲ اﳌﺜﺎل ‪٤-٣‬‬
‫ﻧﺴ ـ ـ ــﺨﺔ أﺧﺮى ﻣﻦ ﺑﺮ ﻣﺞ ﺣﺴ ـ ـ ــﺎب ﻣﺪة ﳏﺎﺿ ـ ـ ــﺮة ﺳ ـ ـ ـ ــﺘﺨﺪام اﻷﻏﺮاض اﻟﺪﻳﻨﺎﻣﻴﻜﻴﺔ ﺑﺪﻻً ﻣﻦ اﻷﻏﺮاض اﻟﺴ ـ ـ ــﺎﻛﻨﺔ‪ ،‬ﺣﻴﺚ‬
‫ﺳﻨﻼﺣﻆ أﻳﻀﺎً أﻧﻪ ﻟﻴﺲ ﻣﻦ اﻟﻀﺮوري اﻟﺘﻘﻴﺪ ﺑﻄﺮﻳﻘﺔ اﻟﺘﺼﺮﻳﺢ ﻋﻦ اﻟﻔﺌﺎت ﺑﺘﻮاﺑﻊ ﻧﻴﺔ ذوات وﺳﻄﺎء‪.‬‬
‫ﻣﺜﺎل ‪٤-٣‬‬
‫أﻋﺪ ﻛﺘﺎﺑﺔ اﻟﱪ ﻣﺞ ﰲ اﳌﺜﺎل ‪ ٣-٣‬ﻣﺴﺘﺨﺪﻣﺎً ﺗﻌﺮﻳﻒ اﻷﻏﺮاض اﻟﺪﻳﻨﺎﻣﻴﻜﻴﺔ ﺑﺪﻻً ﻣﻦ اﻷﻏﺮاض اﻟﺴﺎﻛﻨﺔ‪.‬‬
‫اﳊﻞ‪:‬‬
‫>‪#include <iostream.h‬‬
‫‪class Time‬‬
‫{‬
‫‪public:‬‬
‫;‪int hour‬‬
‫;‪int minute‬‬
‫;‪int second‬‬
‫‪public:‬‬
‫‪٧-٣‬‬
Time(int, int, int);
void SetTime();
void PrintTime();
void PrintStandard();
};

class Course
{
private:
int hour;
int minute;
public:
Time *Start, *End;
Course();
~Course();
void TimeCourse();
void PrintCourse();
};

Time::Time(int h, int m, int s)


{
hour = h;
minute =m;
second = s;
}

void Time::SetTime()
{
int h,m,s;
cout<<endl;
cout<<"Hour:";cin>>h;
cout<<"Minute:";cin>>m;
cout<<"Second:";cin>>s;
if (h >= 0 && h < 24) hour = h;
else hour= 0;
if (m >= 0 && m < 60) minute = m;
else minute= 0;
if (s >= 0 && s < 60) second = s;
else second = 0;
}

٨-٣
void Time::PrintTime()
{
if (hour < 10) cout<<"0"<<hour<<":";
else cout<<hour<<":";
if (minute < 10) cout<<"0"<<minute<<":";
else cout<<minute<<":";
if (second < 10) cout<<"0"<<second;
else cout<<second;
}

void Time::PrintStandard()
{
if (hour == 0 || hour==12) cout<<"12:";
else cout<<hour%12<<":";
if (minute < 10) cout<<"0"<<minute<<":";
else cout<<minute<<":";
if (second < 10) cout<<"0"<<second;
else cout<<second;
if (hour<12) cout<<"AM"; else cout<<"PM";
}

Course::Course()
{
Start=new Time(0,0,0);
End=new Time(0,0,0);
Start->SetTime();
End->SetTime();
}

Course::~Course()
{
delete Start;
delete End;
}

void Course::TimeCourse()
{
hour=End->hour-Start->hour;
minute=End->minute-Start->minute;
if (minute<0)
{

٩-٣
minute+=60;
hour-=1;
}
}

void Course::PrintCourse()
{
TimeCourse();
cout<<"The Time of the course is" <<hour<<"H:"
<<minute<<endl;
}

void main()
{
Course *C;
C=new Course();
C->TimeCourse();
C->PrintCourse();
delete C;
}

٥-٣ ‫ﻣﺜﺎل‬
،CBox ‫ ﻋﻠﻰ ﺷ ـ ــﻜﻞ ﺻ ـ ــﻨﻒ ﺳ ـ ــﻢ‬،‫ اﻟﻄﻮل واﻟﻌﺮض واﻻرﺗﻔﺎع‬،‫اﻟﺘﻌﻠﻴﻤﺎت اﻟﺘﺎﻟﻴﺔ ﺗﻌﺮف ﻛﺘﻠﺔ ﺑﻴﺎ ت ﲤﺜﻞ أﺑﻌﺎد ﺻ ـ ــﻨﺪوق‬
:‫ ﻳﻌﻤﻞ ﻋﻠﻰ ﻴﺌﺔ اﻟﺼﻨﻒ‬CBox ‫وﻳﺘﻀﻤﻦ ﻫﺬا اﻟﺼﻨﻒ ﱐ اﻟﺼﻨﻒ‬
#include <iostream>
using namespace std;
class CBox
{
public:
double m_Length;
double m_Width;
double m_Height;
// ‫ﺗﻌﺮﻳﻒ ﱐ اﻟﺼﻨﻒ‬
CBox(double lv, double bv, double hv)
{
m_Length = lv; // m_Length ‫ إﱃ‬lv ‫ﲤﺮﻳﺮ ﻗﻴﻤﺔ اﻟﻮﺳﻴﻂ‬
m_Width = bv; // m_Width ‫ إﱃ‬bv ‫ﲤﺮﻳﺮ ﻗﻴﻤﺔ اﻟﻮﺳﻴﻂ‬
m_Height = hv; // m_Height ‫ إﱃ‬hv ‫ﲤﺮﻳﺮ ﻗﻴﻤﺔ اﻟﻮﺳﻴﻂ‬
}

١٠-٣
‫ﺑﻊ ﺣﺴﺎب ﺣﺠﻢ اﻟﺼﻨﺪوق ‪//‬‬
‫)‪double Volume(void‬‬
‫{‬
‫;‪return m_Length* m_Width* m_Height‬‬
‫}‬
‫;}‬
‫)‪int main(void‬‬
‫{‬
‫ﺗﻌﺮﻳﻒ ﻏﺮض ﻣﻦ ﺻﻨﻒ ‪CBox box1(78.0,24.0,18.0); // box1‬‬
‫ﺗﻌﺮﻳﻒ ﻏﺮض ﻣﻦ ﺻﻨﻒ ‪CBox cigarBox(8.0,5.0,1.0); // cigarBox‬‬
‫ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑ ﻳﺸﲑ إﱃ ﺟﻢ اﻟﺼﻨﺪوق ﺑﻘﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ ‪double boxVolume = 0.0; //0‬‬
‫ﺣﺴﺎب ﺣﺠﻢ اﻟﺼﻨﺪوق اﻷول واﺳﻨﺎد اﻟﻨﺎﺗﺞ إﱃ ‪ boxVolume‬وﻃﺒﺎﻋﺘﻪ‪//‬‬
‫;)(‪boxVolume = box1Volume‬‬
‫;‪cout << "Volume of box1 = " << boxVolume<< endl‬‬
‫ﺣﺴﺎب ﺣﺠﻢ اﻟﺼﻨﺪوق اﻟﺜﺎﱐ واﺳﻨﺎد اﻟﻨﺎﺗﺞ إﱃ ‪ boxVolume‬وﻃﺒﺎﻋﺘﻪ‪//‬‬
‫;)(‪boxVolume = cigarBoxVolume‬‬
‫;‪cout << "Volume of cigarBox = " << boxVolume<< endl‬‬
‫;‪return 0‬‬
‫}‬
‫ﺗﺞ ﺗﻨﻔﻴﺬ ﻫﺬا اﻟﱪ ﻣﺞ ﻫﻮ‪:‬‬
‫‪Volume of Box1 = 33696‬‬
‫‪Volume of cigarBox = 40‬‬
‫ﲟﺎ أن اﻟﺘﺎﺑﻊ اﻟﺒﻨﺎء ﻟﻪ وﺳ ــﻄﺎء ﻓﻌﻨﺪ اﻟﺘﺼـ ـﺮﻳﺢ ﻋﻦ ﻏﺮض ﻣﻦ اﻟﺼ ــﻨﻒ ‪ CBox‬ﺑﺪون ﲢﺪﻳﺪ وﺳ ــﻄﺎء ﺑﻊ اﻟﺒﻨﺎء‪ ،‬أي‬
‫ﻟﺸﻜﻞ‪:‬‬
‫;‪CBox Box2‬‬
‫ﻓﺈن ذﻟﻚ ﺳﻴﺆدي إﱃ إﺻﺪار رﺳﺎﻟﺔ ﺧﻄﺄ‪ .‬إﻻ أن ﺗﻌﺮﻳﻒ ﱐ أﺧﺮ ﻟﻠﺼﻨﻒ ﺧﺬ ﻧﻔﺲ اﻻﺳﻢ ﻟﻜﻦ ﺑﺪون وﺳﻄﺎء ﺳﻴﺠﻌﻞ‬
‫اﳌﻨﻀﺪ ﻳﺴﺘﺪﻋﻲ ﺑﻊ اﻟﺒﻨﺎء ﺑﺪون وﺳﻄﺎء ﻛﻤﺎ ﰲ اﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫>‪#include <iostream‬‬
‫;‪using namespace std‬‬
‫‪class CBox‬‬
‫{‬
‫‪public:‬‬
‫;‪double m_Length‬‬
‫;‪double m_Width‬‬
‫;‪double m_Height‬‬
‫ﺗﻌﺮﻳﻒ ﱐ اﻟﺼﻨﻒ ‪//‬‬
‫)‪CBox(double lv, double bv, double hv‬‬

‫‪١١-٣‬‬
{
m_Length = lv;
m_Width = bv;
m_Height = hv;
}
// ‫ﺗﻌﺮﻳﻒ ﱐ آﺧﺮ ﻟﻠﺼﻨﻒ‬
CBox(void)
{
m_Length =20.0;
m_Width = 10.0;
m_Height = 5.0;
}
// ‫ﺑﻊ ﺣﺴﺎب ﺣﺠﻢ اﻟﺼﻨﺪوق‬
double Volume(void)
{
return m_Length* m_Width* m_Height;
}
};
void main(void)
{
CBox box1(78.0,24.0,18.0); // box1 ‫ﺗﻌﺮﻳﻒ ﻏﺮض ﻣﻦ ﺻﻨﻒ‬
CBox cigarBox(8.0,5.0,1.0); // cigarBox ‫ﺗﻌﺮﻳﻒ ﻏﺮض ﻣﻦ ﺻﻨﻒ‬
CBox box2; // box2 ‫ﺗﻌﺮﻳﻒ ﻏﺮض ﻣﻦ ﺻﻨﻒ‬
double boxVolume = 0.0; //0 ‫ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑ ﻳﺸﲑ إﱃ ﺟﻢ اﻟﺼﻨﺪوق ﺑﻘﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ‬
boxVolume = box1Volume();
cout << "Volume of box1 = " << boxVolume<< endl;
boxVolume = cigarBoxVolume();
cout << "Volume of cigarBox = " << boxVolume<< endl;
boxVolume = box2Volume();
cout << "Volume of box2 = " << boxVolume<< endl;
}
:‫و ﺗﺞ ﺗﻨﻔﻴﺬ ﻫﺬا اﻟﱪ ﻣﺞ ﻫﻮ‬
Volume of Box1 = 33696
Volume of cigarBox = 40
Volume of box2 = 1000
‫ ﺗﻮارث اﻷﻏﺮاض‬-3-1-3
‫ﻋﻨﺪ إﻧﺸ ـ ــﺎء ﻓﺌﺔ ﺟﺪﻳﺪة ﳝﻜﻦ ﻟﻠﻤﱪﻣﺞ أن ﻳﻘﻮم ﺑﺘﺼ ـ ـ ــﻤﻴﻤﻬﺎ ﻟﱰث ﺑﻴﺎ ت وﺗﻮاﺑﻊ ﻓﺌﺔ ﻣﻌﺮﻓﺔ ﻣﺴ ـ ــﺒﻘﺎً ﺗﺴ ـ ــﻤﻰ ﻟﻔﺌﺔ‬
‫ وﺗﺼــﺒﺢ ﻛﻞ ﻓﺌﺔ ﻣﺸــﺘﻘﺔ ﺑﺪورﻫﺎ‬Derived Class ‫ ﺗﺴــﻤﻰ اﻟﻔﺌﺔ اﳉﺪﻳﺪة ﻟﻔﺌﺔ اﳌﺸــﺘﻘﺔ‬،‫اﻷﺳــﺎس ﺑﺪﻻً ﻣﻦ ﻛﺘﺎﺑﺘﻬﺎ ﻣﻦ ﺟﺪﻳﺪ‬

١٢-٣
‫ﻓﺌﺔ أﺳ ــﺎس ﻻﺷ ــﺘﻘﺎق ﻓﺌﺎت أﺧﺮى‪ ،‬وﻫﻜﺬا‪ ...‬ﺗﺴ ــﻤﻰ ﻋﻨﺪﺋﺬ اﻟﻮاراﺛﺔ ﻟﻮراﺛﺔ اﻟﺒﺴـ ــﻴﻄﺔ ‪ .Single Inheritance‬وﳝﻜﻦ ﻟﻔﺌﺔ‬
‫واﺣﺪة أن ﺗﺸﺘﻖ ﻣﺒﺎﺷﺮة ﻣﻦ أﻛﺜﺮ ﻣﻦ ﻓﺌﺔ و ﻟﺘﺎﱄ ﺗﺮث أﻋﻀﺎء )ﺑﻴﺎ ت وﺗﻮاﺑﻊ( أﻛﺜﺮ ﻣﻦ ﻓﺌﺔ أﺳﺎس‪ ،‬ﺗﺴﻤﻰ ﻋﻨﺪﺋﺬ اﻟﻮراﺛﺔ‬
‫ﻟﻮراﺛﺔ اﳌﺘﻌﺪدة ‪.Multiple Inheritance‬‬
‫ﻋﻨﺪ ﺗﻌﺮﻳﻒ ﻓﺌﺔ ﺟﺪﻳﺪة ﻣﺸ ـ ــﺘﻘﺔ ﳝﻜﻨﻨﺎ ﺗﻌﺮﻳﻒ ﺑﻴﺎ ت وﺗﻮاﺑﻊ ﻛﺄﻋﻀ ـ ــﺎء ﺟﺪد ﻟﻠﻔﺌﺔ اﳉﺪﻳﺪة‪ ،‬و ﻟﺘﺎﱄ ﺗﺼ ـ ــﺒﺢ ﳍﺬﻩ‬
‫اﻟﻔﺌﺔ إﻣﻜﺎﻧﻴﺔ اﻟﻮﺻــﻮل إﱃ ﺑﻴﺎ ت وﺗﻮاﺑﻊ أﻛﺜﺮ ﳑﺎ ﳝﻜﻦ أن ﺗﺼــﻞ إﻟﻴﻪ اﻟﻔﺌﺎت ﻣﻦ اﳌﺴــﺘﻮى اﻷﻋﻠﻰ‪ ،‬أي أﻧﻪ ﳝﻜﻦ أن ﺗﻜﻮن‬
‫ﻫﺬﻩ اﻟﻔﺌﺔ أوﺳﻊ ﻣﻦ اﻟﻔﺌﺔ اﻷﺳﺎﺳﻴﺔ‪.‬‬
‫ﻳﻌﺘﱪ ﻛﻞ ﻏﺮض ﻣﻦ أﻏﺮاض اﻟﻔﺌﺔ اﳌﺸﺘﻘﺔ ﻏﺮﺿﺎً ﻣﻦ أﻏﺮاض اﻟﻔﺌﺔ اﻷﺳﺎس أﻳﻀﺎً‪ ،‬وﻟﻜﻦ اﻟﻌﻜﺲ ﻏﲑ ﺻﺤﻴﺢ‪ ،‬أي‬
‫أن اﻟﻐﺮض اﳌﻌﺮف ﻛﺤﺎﻟﺔ ﻟﻠﻐﺮض اﻷﺳـ ــﺎس ﻻ ﳝﻜﻨﻪ اﻟﻮﺻـ ــﻮل إﱃ ﺧﺼـ ــﺎﺋﺺ اﻟﻔﺌﺔ اﳌﺸـ ــﺘﻘﺔ‪ .‬واﻟﻘﺎﻋﺪة اﻷﺳـ ــﺎﺳـ ــﻴﺔ اﳌﺘﺒﻌﺔ ﰲ‬
‫ﺗﻜﻮﻳﻦ اﻟﻔﺌﺎت ﻫﻲ ﻗﺎﻋﺪة اﻟﺘﻀ ــﻤﲔ اﻷﺳ ــﺎﺳ ــﻲ ﻣﻦ اﻷﻋﻠﻰ إﱃ اﻷﺳ ــﻔﻞ‪ ،‬وﲟﻮﺟﺐ ﻫﺬﻩ اﻟﻘﺎﻋﺪة ﺗﺴ ــﺘﻄﻴﻊ اﻟﻔﺌﺔ اﳌﺸ ــﺘﻘﺔ أن‬
‫ﺗﺼﻞ إﱃ ﺑﻴﺎ ت وﺗﻮاﺑﻊ اﻟﻐﺮض اﻷﺳﺎس اﻟﻌﺎﻣﺔ واﶈﻤﻴﺔ دون اﻟﺒﻴﺎ ت واﻟﺘﻮاﺑﻊ اﳋﺎﺻﺔ‪.‬‬
‫ﺗﺸ ــﻜﻞ اﻟﻮراﺛﺔ ‪ Inheritance‬ﺑﻨﻴﺔ ﻫﺮﻣﻴﺔ ﳍﺎ ﺷ ــﻜﻞ اﻟﺸ ــﺠﺮة‪ .‬وﺗﻀ ــﻢ ﻫﺬﻩ اﻟﺸ ــﺠﺮة اﻟﻔﺌﺔ اﻷﺳ ــﺎﺳ ــﻴﺔ اﻟﱵ ﺗﺘﺼ ــﻞ ﻣﻊ‬
‫اﻟﻔﺌﺎت اﳌﺸﺘﻘﺔ ﻣﻨﻬﺎ‪ .‬ﳝﻜﻦ أن ﺗﻜﻮن اﻟﻔﺌﺔ وﺣﻴﺪة ﻟﻜﻦ ﻋﻨﺪ اﺳﺘﺨﺪاﻣﻬﺎ ﻣﻊ أﺳﺎﻟﻴﺐ اﻟﻮراﺛﺔ ﺗﺼﺒﺢ إﻣﺎ ﻓﺌﺔ أﺳﺎﺳﻴﺔ ﻹﻋﻄﺎء‬
‫اﻟﻔﺌﺎت اﳌﺸ ــﺘﻘﺔ ﻋﻨﻬﺎ ﺑﻌﻀـ ـﺎً ﻣﻦ ﺻ ــﻔﺎ ﺎ وﺗﺼ ــﺮﻓﺎ ﺎ أو ﻓﺌﺔ ﻣﺸ ــﺘﻘﺔ وارﺛﺔ ﻟﺼ ــﻔﺎت وﺗﺼ ــﺮﻓﺎت ﻓﺌﺔ أﺧﺮى ﻣﻦ ﻣﺴ ــﺘﻮى أﻋﻠﻰ‪،‬‬
‫وﻳﺒﲔ اﻟﺸﻜﻞ ‪ ١-٣‬ﻃﺮﻳﻘﺔ اﻟﻮراﺛﺔ اﻟﺒﺴﻴﻄﺔ ﺑﲔ اﻟﻔﺌﺎت‪.‬‬

‫‪ClassName1‬‬

‫‪ClassName2‬‬

‫‪ClassName3‬‬ ‫‪ClassName4‬‬

‫اﻟﺸﻜﻞ ‪ ١-٣‬ﳐﻄﻂ ﻳﺒﲔ ﻋﻤﻠﻴﺔ اﻟﺘﻮارث ﺑﲔ اﻟﺼﻔﻮف‬


‫ﻳﺘﻢ اﻟﺘﺼـ ـﺮﻳﺢ ﻋﻦ ﻓﺌﺔ ﻛﻔﺌﺔ ﻣﺸ ــﺘﻘﺔ ﻣﻦ ﻓﺌﺔ أﺧﺮى ﺑﻠﻐﺔ ‪ Visual C++‬ﺑﻜﺘﺎﺑﺔ اﺳ ــﻢ اﻟﻔﺌﺔ اﻷﺳ ــﺎﺳ ــﻴﺔ ﺑﻌﺪ اﺳ ــﻢ اﻟﻔﺌﺔ‬
‫اﳌﺸﺘﻘﺔ ﻣﻔﺼﻮﻟﲔ ﻟﻨﻘﻄﺘﲔ ﻛﻤﺎ ﻳﻠﻲ‪:‬‬
‫‪class ClassName1‬‬
‫{‬
‫‪.‬ﻗﺎﺋﻤﺔ اﻷﻋﻀﺎء‪//‬‬
‫;}‬

‫‪ ClassName2‬ﻣﺸﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺔ ‪// ClassName1‬‬


‫‪class ClassName2: public ClassName1‬‬

‫‪١٣-٣‬‬
‫{‬
‫‪.‬ﻗﺎﺋﻤﺔ اﻷﻋﻀﺎء‪//‬‬
‫;}‬
‫‪ ClassName3‬ﻣﺸﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺔ ‪// ClassName2‬‬
‫‪class ClassName3: public ClassName2‬‬
‫{‬
‫‪.‬ﻗﺎﺋﻤﺔ اﻷﻋﻀﺎء‪//‬‬
‫;}‬
‫‪ ClassName2‬ﻣﺸﺘﻘﺔ ﻣﻦ اﻟﺼﻒ ‪// ClassName4‬‬
‫‪class ClassName4: public ClassName2‬‬
‫{‬
‫‪.‬ﻗﺎﺋﻤﺔ اﻷﻋﻀﺎء‪//‬‬
‫;}‬
‫اﻟﻔﺌﺔ ‪ ClassName1‬ﻫﻲ ﻓﺌﺔ أﺳـ ـ ـ ــﺎﺳـ ـ ـ ــﻴﺔ‪ ،‬واﻟﻔﺌﺔ ‪ ClassName2‬ﻫﻲ ﻓﺌﺔ ﻣﺸـ ـ ـ ــﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺔ ‪ ،ClassName1‬أﻣﺎ‬
‫اﻟﻔﺌﺎت ‪ ClassName3‬و ‪ ClassName4‬ﻓﻬﻲ ﻓﺌﺎت ﻣﺸــﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺔ ‪ ClassName2‬وﻫﻲ ﺗﺮث ﺻــﻔﺎت اﻟﻔﺌﺔ اﻷﺳــﺎﺳــﻴﺔ‬
‫‪ ClassName1‬واﻟﻔﺌﺔ ‪.ClassName2‬‬
‫ﻋﻨﺪ ﺗﻌﺮﻳﻒ ﻏﺮض ﻣﻦ ﳕﻂ ‪ ClassName4‬ﳝﻜﻦ ﳍﺬا اﻟﻐﺮض اﺳـ ـ ــﺘﺪﻋﺎء ﻛﺎﻓﺔ اﻟﺘﻮاﺑﻊ اﻷﻋﻀـ ـ ــﺎء اﳌﻌﺮﻓﺔ ﰲ اﻟﻔﺌﺎت‬
‫ﻣﻦ اﳌﺴﺘﻮى اﻷﻋﻠﻰ ‪ ClassName1‬و ‪ ClassName2‬إﺿﺎﻓﺔ إﱃ ﺗﻠﻚ اﳌﻌﺮﻓﺔ ﰲ اﻟﻔﺌﺔ ‪.ClassName4‬‬
‫اﺳﺘﺨﺪام اﻟﺘﻮاﺑﻊ اﻟﺒﻨﺎءة ﺿﻤﻦ اﻟﻔﺌﺎت اﳌﺸﺘﻘﺔ‬
‫ﲟﺎ أن اﻟﻔﺌﺔ اﳌﺸﺘﻘﺔ ﺗﺮث أﻋﻀﺎء اﻟﻔﺌﺔ اﻷﺳﺎس ﻟﺬﻟﻚ ﳚﺐ اﺳﺘﺪﻋﺎء ﺑﻊ اﻟﺒﻨﺎء اﳌﺮﺗﺒﻂ ﻟﻔﺌﺔ اﻷﺳﺎﺳﻴﺔ ﻋﻨﺪ إﻧﺸﺎء‬
‫ﻏﺮض ﻣﺘﻌﻠﻖ ﻟﻔﺌﺔ اﳌﺸ ـ ـ ــﺘﻘﺔ‪ ،‬وذﻟﻚ ﻟﻜﻲ ﻳﺘﻢ إﻋﻄﺎء ﻗﻴﻢ اﺑﺘﺪاﺋﻴﺔ ﻷﻋﻀـ ـ ــﺎء اﻟﻔﺌﺔ اﻷﺳـ ـ ــﺎﺳـ ـ ــﻴﺔ اﳌﻮﺟﻮدة ﺿـ ـ ــﻤﻦ ﻏﺮض اﻟﻔﺌﺔ‬
‫اﳌﺸـ ــﺘﻘﺔ‪ .‬ﳝﻜﻦ اﺳـ ــﺘﺪﻋﺎء ﺑﻊ اﻟﺒﻨﺎء اﳌﺮﺗﺒﻂ ﻟﻔﺌﺔ اﻷﺳـ ــﺎس ﻇﺎﻫﺮ ً ﺿـ ــﻤﻦ ﺑﻊ اﻟﺒﻨﺎء اﳌﺮﺗﺒﻂ ﻟﻔﺌﺔ اﳌﺸـ ــﺘﻘﺔ وﰲ ﺣﺎل ﻋﺪم‬
‫اﻟﻘﻴﺎم ﺑﺬﻟﻚ ﻓﺈن اﻟﺘﺎﺑﻊ اﻷﺧﲑ ﻳﻘﻮم ﺳﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ اﻷول ﺑﺸﻜﻞ ﺿﻤﲏ‪.‬‬
‫ﻋﻨﺪ ﺗﻌﺮﻳﻒ ﺑﻊ ﺑﻨﺎء ﰲ اﻟﻔﺌﺔ اﻷﺳـ ــﺎﺳـ ــﻴﺔ ﳚﺐ اﺳـ ــﺘﺪﻋﺎء ﻫﺬا اﻟﺘﺎﺑﻊ ﺿـ ــﻤﻦ ﺗﻌﻠﻴﻤﺎت ﺑﻊ ﺑﻨﺎء اﻟﻔﺌﺔ اﳌﺸ ـ ــﺘﻘﺔ ﻣﻦ‬
‫أﺟﻞ ﻗﻴﻢ اﺑﺘﺪاﺋﻴﺔ‪ .‬أي أﻧﻪ ﻋﻨﺪ اﻟﺘﺼ ـ ـﺮﻳﺢ ﻋﻦ ﻓﺌﺔ ‪ ClassName2‬ﻛﻔﺌﺔ ﻣﺸـ ــﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺔ ‪ ClassName1‬ﻋﻠﻰ ﺳـ ــﺒﻴﻞ اﳌﺜﺎل‬
‫ﳚﺐ اﺳ ـ ــﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ )(‪ ClassName1‬ﺿ ـ ــﻤﻦ ﺗﻌﻠﻴﻤﺎت ﺑﻊ اﻟﺒﻨﺎء )(‪ ClassName2‬أو أن ﻳﺘﻢ اﺳ ـ ــﺘﺪﻋﺎؤﻩ ﻣﺒﺎﺷ ـ ــﺮة أﺛﻨﺎء‬
‫اﻟﺘﻌﺮﻳﻒ ﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫)(‪class ClassName2: public ClassName1:ClassName1‬‬
‫{‬
‫‪.‬ﻗﺎﺋﻤﺔ اﻷﻋﻀﺎء‪//‬‬
‫;}‬

‫‪١٤-٣‬‬
‫إذ ﱂ ﻳﺘﻢ ﺗﻌﺮﻳﻒ ﺑﻊ اﻟﺒﻨﺎء ﻟﻠﻔﺌﺔ اﳌﺸﺘﻘﺔ ﻓﺈﻧﻪ ﻳﺘﻢ اﺳﺘﺪﻋﺎء ﺑﻊ اﻟﺒﻨﺎء ﻟﻠﻔﺌﺔ اﻷﺳﺎس ﺑﺸﻜﻞ اﻓﱰاﺿﻲ‪ .‬ﻓﻌﻨﺪ إﻧﺸﺎء‬
‫ﻏﺮض ﻣﻦ ﳕﻂ ﻓﺌﺔ ﻣﺸ ــﺘﻘﺔ ‪ ClassName2‬ﻣﻦ ﻓﺌﺔ ‪ ClassName1‬ﻳﺘﻢ اﺳ ــﺘﺪﻋﺎء ﺑﻊ اﻟﺒﻨﺎء ﻟﻠﻔﺌﺔ اﻷﺳ ــﺎس ‪ClassName1‬‬
‫أوﻻً ﰒ ﻳﺘﻢ اﺳــﺘﺪﻋﺎء ﺑﻊ اﻟﺒﻨﺎء ﻟﻠﻔﺌﺔ اﳌﺸــﺘﻘﺔ ‪ .ClassName2‬وﺑﺸــﻜﻞ ﻋﺎم ﺗﺴــﺘﺪﻋﻰ ﺗﻮاﺑﻊ اﻟﺒﻨﺎء ﻟﻠﻔﺌﺎت اﻟﻌﻠﻴﺎ ﻟﻔﺌﺔ ﻳﺸــﺘﻖ‬
‫ﻣﻨﻬﺎ اﻟﻐﺮض ﻣﻦ اﻷﻋﻠﻰ إﱃ اﻷﺳ ـ ـ ــﻔﻞ‪ ،‬وﻻ ﻳﺘﻢ ﺗﻮرﻳﺚ ﺗﻮاﺑﻊ اﻟﺒﻨﺎء ﻟﻠﻔﺌﺎت اﻷﺳ ـ ـ ــﺎﺳ ـ ـ ــﻴﺔ وﻋﻤﻠﻴﺎت اﻹﺳ ـ ـ ــﻨﺎد اﳌﺘﻌﻠﻘﺔ ﺎ إﱃ‬
‫اﻟﻔﺌﺎت اﳌﺸـ ــﺘﻘﺔ ﻋﻨﻬﺎ‪ .‬ﻟﻜﻦ ﳝﻜﻦ ﻟﺘﻮاﺑﻊ اﻟﺒﻨﺎء اﳌﺮﺗﺒﻄﺔ ﻟﻔﺌﺎت اﳌﺸـ ــﺘﻘﺔ وﻋﻤﻠﻴﺎت اﻹﺳـ ــﻨﺎد اﳌﻠﺤﻘﺔ ﺎ أن ﺗﺴـ ــﺘﺪﻋﻲ ﺗﻮاﺑﻊ‬
‫اﻟﺒﻨﺎء وﻋﻤﻠﻴﺎت اﻹﺳــﻨﺎد اﳌﺮﺗﺒﻄﺔ ﻟﻔﺌﺎت اﻷﺳــﺎس‪ .‬أﻣﺎ ﻟﻨﺴــﺒﺔ ﻟﻠﺘﻮاﺑﻊ اﳌﺪﻣﺮة ﻓﻴﺘﻢ اﺳــﺘﺪﻋﺎؤﻫﺎ ﺑﱰﺗﻴﺐ ﻋﻜﺴــﻲ ﻻﺳــﺘﺪﻋﺎء‬
‫اﻟﺘﻮاﺑﻊ اﻟﺒﻨﺎءة‪ ،‬أي ﻳﺘﻢ اﺳﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ اﳌﺪﻣﺮ ﻟﻔﺌﺔ ﻣﺸﺘﻘﺔ ﻗﺒﻞ اﺳﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ اﳌﺪﻣﺮ ﻟﻔﺌﺔ أﺳﺎﺳﻴﺔ‪.‬‬
‫ﻣﺜﺎل ‪٦-٣‬‬
‫أﻋﺪ ﺻﻴﺎﻏﺔ اﻟﱪ ﻣﺞ ﰲ اﳌﺜﺎل اﻟﺴﺎﺑﻖ ﺳﺘﺨﺪام ﻗﺎﻋﺪة اﻟﺘﻮارث‪.‬‬
‫اﳊﻞ‪:‬‬
‫>‪#include <iostream.h‬‬
‫‪class Time‬‬
‫{‬
‫‪public:‬‬
‫;‪int hour‬‬
‫;‪int minute‬‬
‫;‪int second‬‬
‫‪public:‬‬
‫;)‪Time(int, int, int‬‬
‫;)(‪void SetTime‬‬
‫;)(‪void PrintTime‬‬
‫;)(‪void PrintStandard‬‬
‫;}‬

‫‪class Course : public Time‬‬


‫{‬
‫‪public:‬‬
‫;)(‪Course‬‬
‫;)(‪void TimeCourse‬‬
‫;)(‪void PrintCourse‬‬
‫;}‬

‫)‪Time::Time(int h, int m, int s‬‬


‫{‬
‫;‪hour = h‬‬
‫;‪minute =m‬‬
‫;‪second = s‬‬
‫‪١٥-٣‬‬
}

void Time::SetTime()
{
int h,m,s;
cout<<endl;
cout<<"Hour:";cin>>h;
cout<<"Minute:";cin>>m;
cout<<"Second:";cin>>s;
if (h >= 0 && h < 24) hour = h;
else hour= 0;
if (m >= 0 && m < 60) minute = m;
else minute= 0;
if (s >= 0 && s < 60) second = s;
else second = 0;
}

void Time::PrintTime()
{
if (hour < 10) cout<<"0"<<hour<<":";
else cout<<hour<<":";
if (minute < 10) cout<<"0"<<minute<<":";
else cout<<minute<<":";
if (second < 10) cout<<"0"<<second;
else cout<<second;
}

void Time::PrintStandard()
{
if (hour == 0 || hour==12) cout<<"12:";
else cout<<hour%12<<":";
if (minute < 10) cout<<"0"<<minute<<":";
else cout<<minute<<":";
if (second < 10) cout<<"0"<<second;
else cout<<second;
if (hour<12) cout<<"AM"; else cout<<"PM";
}

Course::Course():Time(0,0,0)
{
}

١٦-٣
void Course::TimeCourse()
{
int hour1,hour2;
int minute1,minute2;

SetTime();
hour1=hour;
minute1=minute;

SetTime();
hour2=hour;
minute2=minute;

hour=hour2-hour1;
minute=minute2-minute1;

if (minute<0)
{
minute+=60;
hour-=1;
}
}

void Course::PrintCourse()
{
TimeCourse();
cout<<"The Time of the course is" <<hour<<"H:"
<<minute<<endl;
}

void main()
{

Course *C;
C=new Course();
C->PrintCourse();
delete C;
}

١٧-٣
‫ﺗﺆدي ﻫﺬﻩ اﻟﻨﺴ ـ ــﺨﺔ ﻣﻦ اﻟﱪ ﻣﺞ اﻟﻮﻇﻴﻔﺔ ذا ﺎ اﻟﱵ ﺗﺆدﻳﻬﺎ اﻟﻨﺴ ـ ــﺨﺔ اﻟﺴ ـ ــﺎﺑﻘﺔ ﻟﻜﻦ ﺳ ـ ــﺘﺨﺪام أﺳ ـ ــﻠﻮب اﻟﺘﻮارث‪.‬‬
‫ﻧﻼﺣﻆ ﻣﻦ ﺧﻼل ﻫﺬا اﳌﺜﺎل اﺳﺘﺨﺪام اﻟﺘﻮاﺑﻊ اﻷﻋﻀﺎء واﳌﺘﻐﲑات اﳌﻌﺮﻓﺔ ﰲ اﻟﻔﺌﺔ اﻷﺳﺎﺳﻴﺔ ‪ Time‬ﲤﺎﻣﺎً ﻛﺎﺳﺘﺨﺪام اﻟﺘﻮاﺑﻊ‬
‫اﻷﻋﻀ ـ ــﺎء واﳌﺘﻐﲑات اﳌﻌﺮﻓﺔ ﰲ اﻟﻔﺌﺔ ‪ .Course‬ﻟﻘﺪ ﰎ اﺳ ـ ــﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ )(‪ SetTime‬اﻟﻌﻀ ـ ــﻮ ﰲ اﻟﻔﺌﺔ ‪ Time‬ﻋﺪة ﻣﺮات ﰲ‬
‫اﻟﺘﺎﺑﻊ )(‪ TimeCourse‬اﻟﻌﻀﻮ ﰲ اﻟﻔﺌﺔ ‪ ،Course‬وﻗﺪ اﺳﺘﺨﺪﻣﺖ ﻫﺬﻩ اﻻﺳﺘﺪﻋﺎءات اﳌﺘﻜﺮرة ﻟﻘﺮاءة اﻟﻘﻴﻢ اﳌﺨﺘﻠﻔﺔ‪.‬‬
‫إﻋﺎدة ﺗﻌﺮﻳﻒ ﺑﻊ ﰲ ﻓﺌﺔ ﻣﺸﺘﻘﺔ‬
‫ﳝﻜﻨﻨﺎ ﰲ أي ﻓﺌﺔ ﻣﺸﺘﻘﺔ إﻋﺎدة ﺗﻌﺮﻳﻒ ﺑﻊ ﻋﻀﻮ ﰲ ﻓﺌﺔ أﺳﺎس‪ .‬واﻟﻘﺎﻋﺪة اﻷﺳﺎﺳﻴﺔ ﰲ اﺳﺘﺪﻋﺎء اﻟﺘﻮاﺑﻊ اﻷﻋﻀﺎء‬
‫ﻋﻨﺪ ﺗﻌﺮﻳﻒ ﻏﺮض ﻣﻦ ﳕﻂ ﻓﺌﺔ ﻣﺸـ ــﺘﻘﺔ ﻫﻲ اﺳـ ــﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ ﰲ اﻟﻔﺌﺔ اﳌﻌﺮف ﻋﻠﻴﻬﺎ اﻟﻐﺮض إذا ﻛﺎن ﻣﻮﺟﻮداً أو اﻟﺼـ ــﻌﻮد إﱃ‬
‫اﻟﻔﺌﺎت ﻣﻦ اﳌﺴ ــﺘﻮى اﻷﻋﻠﻰ ﻟﻠﺒﺤﺚ ﻋﻦ اﻟﺘﺎﺑﻊ وﺗﻨﻔﻴﺬ أول ﺑﻊ ﺗﺘﻢ ﻣﺼ ــﺎدﻓﺘﻪ‪ .‬وﳝﻜﻨﻨﺎ أﺛﻨﺎء إﻋﺎدة ﺗﻌﺮﻳﻒ ﺑﻊ ﰲ ﻣﺴ ــﺘﻮى‬
‫ﻻﺣﻖ اﺳـ ـ ـ ـ ــﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ اﳌﻌﺮف ﳌﺴـ ـ ـ ـ ــﺘﻮى اﻷﻋﻠﻰ إذا ﺗﻄﻠﺐ اﻷﻣﺮ‪ .‬واﻟﺴ ـ ـ ـ ـ ـﺆال اﻟﺬي ﻳﻄﺮح ﻫﻨﺎ ﻫﻮ ﻣﻦ أﺟﻞ أي ﻣﻦ‬
‫اﻟﺒﻴﺎ ت ﺳـ ـ ــﻴﺘﻢ ﺗﻨﻔﻴﺬ ﻫﺬا اﻟﺘﺎﺑﻊ إذا ﻣﺎ ﻛﺎﻧﺖ ﻫﻨﺎك ﺑﻴﺎ ت ﺳـ ـ ــﺘﺘﻢ ﻣﻌﺎﳉﺘﻬﺎ ﻣﻦ ﻗﺒﻞ اﻟﺘﺎﺑﻊ؟ اﻟﻮاﻗﻊ ﺳـ ـ ــﻴﺘﻢ ﺗﻨﻔﻴﺬ ﻫﺬا اﻟﺘﺎﺑﻊ‬
‫ﻋﻠﻰ ﺑﻴﺎ ت اﻟﻔﺌﺔ اﻟﱵ ﰎ اﺳﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ ﻣﻨﻬﺎ‪ .‬ﺑﻔﺮض ﻟﺪﻳﻨﺎ ﺗﻌﺮﻳﻒ اﻟﻔﺌﺎت اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫‪class ClassName1‬‬
‫{‬
‫;)(‪Function1‬‬
‫;)(‪Function2‬‬
‫;}‬

‫‪ ClassName2‬ﻣﺸﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺔ ‪// ClassName1‬‬


‫‪class ClassName2: public ClassName1‬‬
‫{‬
‫;)(‪Function1‬‬
‫;)(‪Function3‬‬
‫;}‬
‫‪ ClassName3‬ﻣﺸﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺔ ‪// ClassName2‬‬
‫‪class ClassName3: public ClassName2‬‬
‫{‬
‫;)(‪Function1‬‬
‫;)(‪Function4‬‬
‫;}‬
‫وﺑﻔﺮض أن ﻟﺪﻳﻨﺎ اﻟﺘﺼﺮﻳﺢ اﻟﺘﺎﱄ‪:‬‬
‫;‪ClassName3 *Objet1‬‬
‫ﻓﻌﻨﺪ اﺳ ـ ـ ـ ـ ــﺘﺪﻋﺎﺋﻨﺎ ﻟﻠﺘﺎﺑﻊ )(‪ Function1‬ﻷﻣﺮ )(‪ Objet1->Function1‬ﻓﺴ ـ ـ ـ ـ ــﻴﺘﻢ ﺗﻨﻔﻴﺬ اﻷواﻣﺮ اﳌﻌﺮﻓﺔ ﰲ اﻟﺘﺎﺑﻊ‬
‫)(‪ Function1‬ﰲ اﻟﻐﺮض ‪ ،ClassName3‬وﻟﺘﻨﻔﻴــﺬ أواﻣﺮ اﻟﺘــﺎﺑﻊ )(‪ Function1‬ﰲ اﻟﻔﺌــﺔ ‪ ClassName2‬ﳚــﺐ أن ﻧﻜﺘــﺐ‬
‫)(‪ .ClassName2:: Function1‬واﳌﺜﺎل ‪ ٦-٣‬ﻳﺒﲔ ﻃﺮﻳﻘﺔ اﻻﺳــﺘﺪﻋﺎء ﺣﻴﺚ ﲤﺖ ﻃﺒﺎﻋﺔ ﻗﻴﻢ ‪ hour‬و ‪ minute‬ﳍﺬﻩ اﻟﻔﺌﺔ‪.‬‬

‫‪١٨-٣‬‬
‫إذا أرد اﺳ ـ ــﺘﺪﻋﺎء ﺑﻊ ﻋﻀ ـ ــﻮ ﻳﻨﺘﻤﻲ إﱃ ﻓﺌﺔ ﻣﻦ ﻣﺴ ـ ــﺘﻮى أﻋﻠﻰ ﻣﻦ أي ﺑﻊ ﻣﻦ أي ﻋﻀ ـ ــﻮ ﳚﺐ ﲢﺪﻳﺪ اﻟﻔﺌﺔ اﻟﱵ ﻳﻨﺘﻤﻲ‬
‫إﻟﻴﻬﺎ ﻫﺬا اﻟﻌﻀﻮ وﻓﻖ ﻗﺎﻋﺪة اﺳﺘﺪﻋﺎء ﺧﺎﺻﺔ‪ ،‬وﺗﺘﻢ وﻓﻖ اﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫;)(‪ClassName::FunctionName‬‬
‫ﻓﺈذا أرد اﺳﺘﺪﻋﺎء ﺑﻊ ﻃﺒﺎﻋﺔ اﻟﺘﻮﻗﻴﺖ )(‪ Print‬اﳌﻌﺮف ﰲ اﻟﻔﺌﺔ ‪ Time‬ﰲ اﳌﺜﺎل ‪ ٦-٣‬ﻣﻦ اﻟﺘﺎﺑﻊ )(‪ Print‬اﳌﻌﺮف‬
‫ﰲ اﻟﻔﺌﺔ ‪ Course‬ﻧﻜﺘﺐ اﻟﺼﻴﻐﺔ اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫;)(‪Time::Print‬‬

‫‪Virtual Functions‬‬ ‫اﻟﺘﻮاﺑﻊ اﻟﻈﺎﻫﺮﻳﺔ‬


‫ﻟﻘﺪ ذﻛﺮ ﺳــﺎﺑﻘﺎً أﻧﻪ ﻹﻣﻜﺎن اﻟﺘﺼ ـﺮﻳﺢ ﻋﻦ ﺗﻮاﺑﻊ أﻋﻀــﺎء ﰲ ﻓﺌﺎت ﻣﺘﻮارﺛﺔ ﺧﺬ ﻧﻔﺲ اﻻﺳــﻢ‪ ،‬وﻳﺘﻢ اﺳــﺘﺪﻋﺎء أي‬
‫ﻣﻦ ﻫﺬﻩ اﻟﺘﻮاﺑﻊ ﺑﺘﺤﺪﻳﺪ اﻟﻐﺮض اﻟﺬي ﻳﻨﺘﻤﻲ إﻟﻴﻪ اﻟﺘﺎﺑﻊ وﻓﻖ ﻗﻮاﻋﺪ ﳏﺪدة‪ .‬ﳝﻜﻨﻨﺎ اﺳ ـ ـ ــﺘﺪﻋﺎء ﻫﺬﻩ اﻟﺘﻮاﺑﻊ ﺑﻄﺮﻳﻘﺔ أﺧﺮى ﻛﻤﺎ‬
‫ﻳﻠﻲ‪:‬‬
‫ﻟﺘﺼ ـ ـﺮﻳﺢ ﻋﻦ ﻏﺮض ﻛﻤﺆﺷـ ــﺮ ﻟﻠﻔﺌﺔ اﻷﺳـ ــﺎس وﻣﻦ ﰒ ﺗﻌﺮﻳﻒ ﻏﺮض ﻛﻤﺆﺷـ ــﺮ ﻷي ﻓﺌﺔ ﻣﺸـ ــﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺔ اﻷﺳـ ــﺎس‪،‬‬
‫و ﺳــﻨﺎد ﻗﻴﻤﺔ ﻣﺆﺷــﺮ اﻟﻔﺌﺔ اﳌﺸــﺘﻘﺔ إﱃ ﻣﺆﺷــﺮ اﻟﻔﺌﺔ اﻷﺳــﺎﺳــﻴﺔ واﺳــﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ اﳌﻌﺮف ﺑﻨﻔﺲ اﻻﺳــﻢ ﺳــﻴﺘﻢ ﺗﻨﻔﻴﺬ أواﻣﺮ اﻟﺘﺎﺑﻊ‬
‫ﰲ اﻟﻔﺌﺔ اﳌﺸـﺘﻘﺔ اﳌﺆﺷـﺮ إﻟﻴﻬﺎ‪ .‬ﺗﺴـﻤﻰ ﻫﺬﻩ اﻟﻌﻤﻠﻴﺔ ﺑﺘﻌﺪدﻳﺔ اﻷﺷـﻜﺎل وﻻ ﳝﻜﻦ أن ﺗﺘﻢ إﻻ ﻟﺘﺼـﺮﻳﺢ ﻋﻦ ﻫﺬﻩ اﻟﺘﻮاﺑﻊ ﻛﺘﻮاﺑﻊ‬
‫ﻇﺎﻫﺮﻳﺔ ‪ Virtual‬ﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫;)(‪virtual FunctionName‬‬
‫ﻟﺘﻮﺿﻴﺢ ذﻟﻚ ﺑﻔﺮض أن ﻟﺪﻳﻨﺎ اﻟﻔﺌﺎت اﻟﺘﺎﻟﻴﺔ‪:‬‬
‫‪class ClassName1‬‬
‫{‬
‫;)(‪virtual Function1‬‬
‫;)(‪Function2‬‬
‫;}‬

‫‪ ClassName2‬ﻣﺸﺘﻖ ﻣﻦ اﻟﻔﺌﺔ ‪// ClassName1‬‬


‫‪class ClassName2: public ClassName1‬‬
‫{‬
‫;)(‪virtual Function1‬‬
‫;)(‪Function3‬‬
‫;}‬
‫اﻟﻔﺌﺔ ‪// ClassName2‬‬ ‫‪ ClassName3‬ﻣﺸﺘﻖ ﻣﻦ‬
‫‪class ClassName3: public ClassName2‬‬
‫{‬
‫;)(‪virtual Function1‬‬
‫;)(‪Function4‬‬
‫;}‬

‫‪١٩-٣‬‬
‫ﻟﻘﺪ ﰎ اﻟﺘﺼـ ـﺮﻳﺢ ﻋﻦ اﻟﺘﺎﺑﻊ )(‪ Function1‬ﻛﺘﺎﺑﻊ ﻇﺎﻫﺮي )ﻳﻜﻔﻲ اﻟﺘﺼـ ـﺮﻳﺢ ﻋﻨﻪ ﻛﺘﺎﺑﻊ ﻇﺎﻫﺮي ﰲ اﻟﻔﺌﺔ اﻷﺳ ــﺎﺳ ــﻴﺔ(‬
‫وﺑﺬﻟﻚ ﳝﻜﻨﻨﺎ اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻏﺮض ﻣﻦ اﻟﻨﻤﻂ ‪ ClassName1‬ﻣﺮ ﻣﻦ اﻟﺸﻜﻞ‪:‬‬
‫;‪ClassName1*Object‬‬
‫ﻷﻣﺮ‪:‬‬ ‫‪ClassName3‬‬ ‫وﺑﺘﻌﺮﻳﻒ ﻏﺮض آﺧﺮ ‪ Object2‬ﻣﻦ اﻟﻨﻤﻂ‬
‫;‪ClassName3*Object2‬‬
‫ﻷﻣﺮ‪:‬‬ ‫‪Object‬‬ ‫و ﺳﻨﺎد ﻗﻴﻤﺔ ‪ Object2‬إﱃ‬
‫;‪Object= Object2‬‬
‫ﻷﻣﺮ‪:‬‬ ‫)(‪Function1‬‬ ‫و ﺳﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ‬
‫)(‪Object.Function1‬‬
‫ﺳﻴﺘﻢ ﺗﻨﻔﻴﺬ أواﻣﺮ اﻟﺘﺎﺑﻊ )(‪ Function1‬اﳌﻌﺮف ﰲ اﻟﻐﺮض ‪.Object2‬‬
‫وإذا أﺧﺬ ﺑﻌﲔ اﻻﻋﺘﺒﺎر أﻧﻪ ﳝﻜﻦ ﲤﺮﻳﺮ ﻣﺘﻐﲑات ﻟﻌﻨﻮان ﺑﲔ ﺗﻮاﺑﻊ ﻟﻐﺔ ‪ Visual C++‬ﻓﻴﻤﻜﻨﻨﺎ ﺗﺼﻮر ﺗﻌﺮﻳﻒ ﻣﺜﻞ‬
‫ﻫﺬﻩ اﻷواﻣﺮ ﰲ ﺗﻮاﺑﻊ ﻣﻌﺮﻓﺔ ﻣﺴــﺒﻘﺎً ﺧﺬ وﺳــﻄﺎءﻫﺎ ﻣﺜﻞ ﻫﺬﻩ اﳌﺆﺷ ـﺮات ﰲ وﺣﺪات ﺑﺮﳎﻴﺔ ﻣﻐﻠﻘﺔ‪ ،‬وﺑﺬﻟﻚ ﺗﻨﻔﺬ أﻓﻌﺎل ﻫﺬﻩ‬
‫اﻟﺘﻮاﺑﻊ ﻻﺣﻘﺎً ﻋﻨﺪ ﺗﻌﺮﻳﻒ اﻟﻔﺌﺎت اﳌﺸ ـ ـ ـ ــﺘﻘﺔ‪ ،‬وﺗﺼ ـ ـ ـ ــﺒﺢ ﻫﺬﻩ اﻷﻓﻌﺎل ﻛﺄﻓﻌﺎل ﻣﺆﺟﻠﺔ‪ .‬وﳍﺬﻩ اﳋﺎﺻ ـ ـ ـ ــﻴﺔ أﳘﻴﺔ ﻛﺒﲑة ﲡﻌﻞ ﻣﻦ‬
‫اﻟﻮﺣﺪات اﻟﱪﳎﻴﺔ ﻛﻮﺣﺪات ﻣﻔﺘﻮﺣﺔ ﻟﻴﺴﺖ ﻣﻐﻠﻘﺔ ﻛﻤﺎ ﰲ ﺣﺎﻟﺔ اﻟﻮﺣﺪات اﳌﺼﺎﻏﺔ ﻋﻠﻰ ﺷﻜﻞ ﺗﻮاﺑﻊ‪.‬‬
‫‪Polymorphism‬‬ ‫ﺗﻌﺪدﻳﺔ اﻷﺷﻜﺎل‬
‫ﻟﺘﻜﻦ ﻟ ــﺪﻳﻨ ــﺎ ﻓﺌ ــﺔ أﻏﺮاض ‪ ClassName1‬ﻣﺸ ـ ـ ـ ـ ــﺘﻘـ ـﺔ ﻣﻦ اﻟﻔﺌ ــﺔ ‪ ClassName‬ﻓ ــﺈن أي ﻏﺮض ﻣﻦ أﻏﺮاض اﻟﻔﺌ ــﺔ‬
‫‪ ClassName1‬ﻫﻮ ﻋﺒﺎرة ﻋﻦ ﻧﺴــﺨﺔ أﻛﺜﺮ ﲢﺪﻳﺪاً ﻣﻦ أي ﻧﺴــﺨﺔ ﻟﻐﺮض ﻣﻦ أﻏﺮاض اﻟﻔﺌﺔ ‪ ،ClassName‬و ﻟﺘﺎﱄ ﻓﺈن أي‬
‫ﻋﻤﻠﻴﺔ ﻗﺎﺑﻠﺔ ﻟﻠﺘﻨﻔﻴﺬ ﻋﻠﻰ أﻏﺮاض اﻟﻔﺌﺔ ‪ ClassName‬ﻫﻲ ﻗﺎﺑﻠﺔ ﻟﻠﺘﻨﻔﻴﺬ ﻋﻠﻰ أﻏﺮاض اﻟﻔﺌﺔ ‪ .ClassName1‬وﻫﺬا ﻣﺎ ﻳﺴـ ــﻤﻰ‬
‫أﻳﻀـ ـ ـﺎً ﻟﻔﻌﻞ اﳌﺆﺟﻞ ﲤﺎﻣﺎً ﻛﺤﺎﻟﺔ إﺳـ ـ ــﻨﺎد وﻇﻴﻔﺔ إﻏﻼق ﻣﻜﺘﺐ اﳌﺪﻳﺮ إﱃ أﺣﺪ اﳌﻮﻇﻔﲔ ﻣﻊ ﺎﻳﺔ اﻟﺪوام ﻓﺴـ ـ ــﻴﺘﻢ ﺗﻨﻔﻴﺬ ﻫﺬا‬
‫اﻟﻌﻤﻞ ﺑﺸﻜﻞ داﺋﻢ ﺣﱴ وﻟﻮ ﺗﻐﲑ اﳌﺪﻳﺮ‪ .‬ﺗﺴﻤﻰ ﻫﺬﻩ اﻟﻮﻇﻴﻔﺔ ﺑﺘﻌﺪدﻳﺔ اﻷﺷﻜﺎل ‪ ،Polymorphism‬وﻫﻲ ﺗﺴﺘﺨﺪم ﺑﺸﻜﻞ‬
‫ﻛﺒﲑ ﰲ ﺗﺴــﻮﻳﻖ ﺑﺮﳎﻴﺎت ﻋﻠﻰ ﺷــﻜﻞ وﺣﺪات ﺑﺮﳎﻴﺔ ‪ Units‬ﻣﻌﺮوﻓﺔ اﶈﺘﻮى ﺑﺸــﻜﻞ دﻗﻴﻖ وﻗﺎﺑﻠﺔ ﻷن ﻳﺸــﺘﻖ ﻣﻨﻬﺎ أﻏﺮاض ﻗﺪ‬
‫ﺗﺴﺘﺪﻋﻰ أﻏﺮاض ﻣﻨﻪ‪ ،‬أو ﺑﺸﻜﻞ آﺧﺮ وﺣﺪات ﺑﺮﳎﻴﺔ ﻗﺎﺑﻠﺔ ﻟﻠﺘﻌﺪﻳﻞ ﰲ ﺗﻮاﺑﻊ ﻻﺣﻘﺔ ﻣﻦ اﳌﱪﻣﺞ‪ ،‬وﻫﻲ ﺑﺬﻟﻚ ﲡﻌﻞ ﻣﻦ ﻫﺬﻩ‬
‫اﻟﻮﺣﺪات وﺣﺪات ﻣﻔﺘﻮﺣﺔ ﻏﲑ ﻣﻐﻠﻘﺔ ﻛﻤﺎ ﰲ ﺣﺎﻟﺔ اﻟﻮﺣﺪات اﳌﺒﻨﻴﺔ ﻋﻠﻰ أﺳـ ـ ـ ــﺎس اﻟﱪﳎﺔ اﳋﻮارزﻣﻴﺔ اﻟﺘﻘﻠﻴﺪﻳﺔ‪ .‬ﺳـ ـ ـ ــﻨﻮﺿـ ـ ـ ــﺢ‬
‫ﻣﻔﻬﻮﻣﻲ اﻟﺘﻮاﺑﻊ اﻟﻈﺎﻫﺮﻳﺔ وﻣﺘﻌﺪدات اﻷﺷﻜﺎل ﻣﻦ ﺧﻼل اﻟﺘﻄﺒﻴﻖ اﻟﺜﺎﱐ ﰲ ﻫﺬا اﻟﻔﺼﻞ‪.‬‬

‫‪this‬‬ ‫‪ -3-2‬اﳌﺆﺷﺮ‬
‫ﻗﺪ ﳓﺘﺎج ﰲ ﺑﻌﺾ اﻷﺣﻴﺎن ﻋﻨﺪ اﺳ ــﺘﺪﻋﺎء أﺣﺪ اﻟﺘﻮاﺑﻊ اﻷﻋﻀ ــﺎء ﰲ ﻏﺮض ﻟﺘﺎﺑﻊ أﺧﺮ أن ﳓﺪد ﻟﻠﻤﻨﻀ ــﺪ اﺳ ــﺘﺪﻋﺎء‬
‫اﻟﺘﺎﺑﻊ اﻟﻌﻀ ــﻮ ﰲ ﻫﺬا اﻟﻐﺮض دون ﻏﲑﻩ‪ ،‬ﳍﺬا ﻧﺴ ــﺘﺨﺪم اﳌﺆﺷ ــﺮ "‪ "this‬ﻟﻺﺷ ــﺎرة إﱃ اﻟﻐﺮض اﳊﺎﱄ‪ .‬ﻋﻨﺪ ﺗﻨﻔﻴﺬ أي ﺑﻊ ﻣﻦ‬
‫أﻋﻀــﺎء اﻟﺼــﻨﻒ‪ ،‬ﻳﺘﻀــﻤﻦ ﻫﺬا اﻟﺘﺎﺑﻊ ﻣﺆﺷــﺮاً ﳐﻔﻴﺎً ﻳﺪل ﻋﻠﻰ اﻟﻐﺮض اﻟﺬي ﻳُﺴــﺘَﺨﺪم ﻣﻌﻪ ﻫﺬا اﻟﺘﺎﺑﻊ‪ .‬ﻛﻤﺎ أﻧﻪ ﻋﻨﺪ اﺳــﺘﺨﺪام‬
‫أي ﺑﻊ ﻋﻀ ــﻮ ﻷي ﺑﻴﺎن ﻣﻦ ﺑﻴﺎ ت ﺻ ــﻨﻒ ﻓﺈن ﺗﻌﺮﻳﻒ اﻟﺒﻴﺎن ﻳﺘﻀ ــﻤﻦ ﻣﺎ ﻳﺸ ــﲑ إﱃ اﻟﻐﺮض اﻟﺬي ﳛﺘﻮي ﻫﺬا اﻟﺒﻴﺎن‪ ،‬أي‬

‫‪٢٠-٣‬‬
‫إن ﻣﻨﻀ ــﺪ اﻟﻠﻐﺔ ﳛﺘﻔﻆ ﻣﻊ ﻛﻞ ﻋﻀ ــﻮ ﻣﻦ أﻋﻀ ــﺎء اي ﻏﺮض ﻣﺎ ﻳﺸ ــﲑ إﱃ اﻟﻐﺮض ذاﺗﻪ ﳌﺆﺷ ــﺮ >‪ .this-‬وﻫﻮ ﻣﺆﺷ ــﺮ ﳝﻜﻦ‬
‫اﺳﺘﺨﺪاﻣﻪ ﻟﻔﺮض اﺳﺘﺨﺪام ﺑﻴﺎن أو إﺟﺮاء ﳏﺪدﻳﻦ‪.‬‬
‫ﻣﺜﺎل ‪٧-٣‬‬
‫ﻹﺟﺮاء ﻋﻤﻠﻴﺔ ﻣﻘﺎرﻧﺔ ﺑﲔ ﺣﺠﻤﻲ ﺻﻨﺪوﻗﲔ ﺳﻨﻘﻮم ﺑﺘﻌﺮﻳﻒ ﺑﻊ اﳌﻘﺎرﻧﺔ اﻟﺘﺎﱄ‪:‬‬
‫)‪int Compare(CBox B1, CBox B2‬‬
‫{‬
‫;)(‪return B1.Volume() > B2.Volume‬‬
‫}‬
‫وﻫﻮ ﺑﻊ ﳛﺴ ــﺐ ﺣﺠﻢ اﻟﺼ ــﻨﺪوق اﻷول وﺣﺠﻢ اﻟﺼ ــﻨﺪوق اﻟﺜﺎﱐ ﻟﺪﺧﻮل إﱃ ﺑﻴﺎ ت ﺧﺎﺻ ــﺔ ‪ private‬ﻟﻠﺼ ــﻨﻒ‬
‫ﻣﻦ أﺟﻞ ‪ B1‬و ‪ .B2‬وﻟﻄﺒﺎﻋﺔ ﺗﺞ ﻋﻤﻠﻴﺔ اﳌﻘﺎرﻧﺔ ﳝﻜﻨﻨﺎ ﻛﺘﺎﺑﺔ اﻟﺘﻌﻠﻴﻤﺎت اﻵﺗﻴﺔ ﺿﻤﻦ اﻹﺟﺮاء ‪:main‬‬
‫))‪if(Compare(cigar, match‬‬
‫;"‪cout << "match is smaller than cigar‬‬
‫‪else‬‬
‫;"‪cout << "match is equal to or larger than cigar‬‬
‫ﻋﺎدة ﺻ ـ ـ ــﻴﺎﻏﺔ اﻟﺘﺎﺑﻊ ‪ Compare‬ﻛﻤﺎ‬ ‫‪xBox‬‬ ‫ﳝﻜﻨﻨﺎ ﺑﻄﺮﻳﻘﺔ أﺧﺮى ﻣﻘﺎرﻧﺔ ﺣﺠﻢ اﻟﺼ ـ ـ ــﻨﺪوق ﲝﺠﻢ أي ﺻ ـ ـ ــﻨﺪوق‬
‫ﻳﻠﻲ‪:‬‬
‫)‪int Compare(CBox xBox‬‬
‫{‬
‫;)(‪return Volume() > xBox.Volume‬‬
‫}‬
‫وﺑﻜﺘﺎﺑﺔ اﻟﺘﻌﻠﻴﻤﺎت ﰲ اﻹﺟﺮاء ‪ main‬ﻋﻠﻰ اﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫)(‪void main‬‬
‫{‬
‫;)‪CBox match(2.2, 1.1, 0.5‬‬
‫;)‪CBox cigar(8.0, 5.0,1.0‬‬
‫))‪if(cigar.Compare(match‬‬
‫;"‪cout << endl<< "match is smaller than cigar‬‬
‫‪else‬‬
‫;"‪cout << endl<< "match is equal to or larger than cigar‬‬
‫}‬
‫أي إن ﻋﻤﻠﻴﺔ اﳌﻘﺎرﻧﺔ ﲡﺮي ﺑﲔ ﺑﻴﺎ ت اﻟﻐﺮض ‪ cigar‬ذا ﺎ وﺑﻴﺎ ت اﻟﻐﺮض اﳌﻘﺎرن‪ .‬وﺗﺘﻢ ﻫﺬﻩ اﻟﻌﻤﻠﻴﺔ ﲤﺎﻣﺎً ﻛﻤﺎ‬
‫ﻟﻮ ﺣﺪد ﻫﺬﻩ اﻟﺒﻴﺎ ت ﻣﻦ أﺟﺮ اﻟﻐﺮض ‪ cigar‬ﰲ ﺑﺮ ﻣﺞ ﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫>‪#include <iostream‬‬
‫;‪using namespace std‬‬
‫‪class CBox‬‬
‫{‬
‫‪public:‬‬
‫‪٢١-٣‬‬
‫)‪CBox(double lv, double bv, double hv‬‬
‫{‬
‫;‪m_Length = lv‬‬
‫;‪m_Width = bv‬‬
‫;‪m_Height = hv‬‬
‫}‬
‫)(‪double Volume‬‬
‫{‬
‫;‪return m_Length*m_Width*m_Height‬‬
‫}‬
‫)‪int Compare(CBox xBox‬‬
‫{‬
‫;)(‪return this->Volume() > xBox.Volume‬‬
‫}‬
‫‪private:‬‬
‫;‪double m_Length‬‬
‫;‪double m_Width‬‬
‫;‪double m_Height‬‬
‫;}‬

‫)(‪void main‬‬
‫{‬
‫;)‪CBox match(2.2, 1.1, 0.5‬‬
‫;)‪CBox cigar(8.0, 5.0,1.0‬‬
‫))‪if(cigar.Compare(match‬‬
‫;"‪cout << endl<< "match is smaller than cigar‬‬
‫‪else‬‬
‫;"‪cout << endl<< "match is equal to or larger than cigar‬‬
‫}‬

‫‪ -3-3‬اﻟﺒﻴﺎ ت واﻟﺘﻮاﺑﻊ اﻟﺴﺎﻛﻨﺔ‬


‫اﻟﺒﻴﺎن اﻟﺴـ ــﺎﻛﻦ ﰲ ﺻـ ــﻨﻒ ﻫﻮ ﺑﻴﺎن ﻗﺎﺑﻞ ﻟﻠﺘﻐﻴﲑ إﻻ أن ﻧﺴـ ــﺨﺔ واﺣﺪة ﻣﻦ ﻫﺬا اﻟﺒﻴﺎن ﺗﻈﻬﺮ ﰲ ﻛﻞ ﻏﺮض ﻣﻦ ﳕﻂ‬
‫اﻟﺼـ ــﻨﻒ‪ .‬وﻳﺘﻢ اﻟﺘﺼ ـ ـﺮﻳﺢ ﻋﻨﻪ ﻣﺴـ ــﺒﻮﻗﺎً ﻟﻜﻠﻤﺔ اﶈﺠﻮزة "‪ ."static‬أي إن اﻟﺒﻴﺎن اﻟﺴـ ــﺎﻛﻦ ﻣﺮﺗﺒﻂ ﻟﺼـ ــﻨﻒ وﻟﻴﺲ ﻟﻐﺮض‪،‬‬
‫وﻫﻮ ﻻ ﻳﺘﻀــﻤﻦ ﻣﺆﺷــﺮ ‪ .this‬اﻟﺘﺎﺑﻊ اﻟﺴــﺎﻛﻦ أﻳﻀـﺎً ﻏﲑ ﻣﺮﺗﺒﻂ ﻟﻐﺮض‪ ،‬و ﻟﺘﺎﱄ ﻓﻬﻮ ﻻ ﳝﺘﻠﻚ ﻣﺆﺷــﺮ ‪ this‬وﻻ ﻳﺴــﺘﺨﺪم إﻻ‬
‫ﺑﻴﺎ ت ﺳ ــﺎﻛﻨﺔ وﻻ ﻳﺴ ــﺘﺪﻋﻲ إﻻ ﺗﻮاﺑﻊ ﺳ ــﺎﻛﻨﺔ‪ .‬ﲟﺎ أن ﻧﺴ ــﺨﺔ وﺣﻴﺪة ﻣﻦ اﻟﺒﻴﺎن اﻟﺴ ــﺎﻛﻦ ﺗﻈﻬﺮ ﰲ ﻛﻞ اﻷﻏﺮاض ﻟﺬا ﳝﻜﻨﻨﺎ‬
‫ﲢﺪﻳﺪ ﻗﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ ﻟﻪ ﺑﻨﻔﺲ اﻟﻄﺮﻳﻘﺔ اﻟﱵ ﻳﺘﻢ ﻓﻴﻬﺎ اﻟﺘﻌﺮﻳﻒ ﻋﻦ ﺑﻊ ﻣﻦ ﺗﻮاﺑﻊ اﻟﻐﺮض‪ .‬ﺗﺴ ــﺘﺨﺪم اﻟﺒﻴﺎ ت واﻟﺘﻮاﺑﻊ اﻟﺴ ــﺎﻛﻨﺔ‬
‫ﳌﺮاﻗﺒﺔ اﻟﺼﻨﻮف ذا ﺎ واﻟﺘﺤﻜﻢ ﺎ‪.‬‬

‫‪٢٢-٣‬‬
#include <iostream>
using namespace std;
class CBox
{
public:
static int objectCount;
CBox(double lv, double bv, double hv)
{
m_Length = lv;
m_Width = bv;
m_Height = hv;
objectCount++;
}
CBox()
{
cout<< “Default constructor called.”;
m_Length = m_Width = m_Height = 1.0;
objectCount++;
}
double Volume() const
{
return m_Length*m_Width*m_Height;
}
private:
double m_Length;
double m_Width;
double m_Height;
};
int CBox::objectCount = 0;
void main()
{
CBox boxes[5];
CBox cigar(8.0, 5.0, 1.0);
cout <<"Number of objects (through class) = "
<< CBox::objectCount<<endl;
cout << "Number of objects (through object) = "
<< boxes[2].objectCount;<< endl;
}

٢٣-٣
‫‪ -3-4‬اﻟﺘﻮاﺑﻊ اﻟﺼﺪﻳﻘﺔ‬
‫ﻗﺪ ﻳﻜﻮن ﻣﻦ اﻟﻀ ـ ـ ـ ـ ــﺮوري ﺗﻌﺮﻳﻒ ﺗﻮاﺑﻊ ﳍﺎ ﺣﻖ اﻟﺪﺧﻮل ﻏﲑ اﶈﺪود إﱃ ﺣﻘﻮل ﺻ ـ ـ ـ ـ ــﻨﻒ‪ .‬وﳓﺘﺎج ﳌﺜﻞ ﻫﺬﻩ اﳊﺎﻟﺔ‬
‫ﺧﺼﻮﺻﺎً ﻋﻨﺪ ﻋﺪم ﻛﻔﺎﻳﺔ ﲢﻠﻴﻞ ﻫﺮﻣﻴﺔ اﻟﺼﻨﻮف‪ .‬ﺗﺴﻤﻰ ﻫﺬﻩ اﻟﺘﻮاﺑﻊ ﻟﺼﺪﻳﻘﺔ وﻳﺘﻢ اﻟﺘﺼﺮﻳﺢ ﻋﻨﻬﺎ داﺧﻞ اﻟﺼﻨﻒ ﻟﻜﻠﻤﺔ‬
‫اﶈﺠﻮزة ‪ .friend‬اﻟﺘﻮاﺑﻊ اﻟﺼﺪﻳﻘﺔ ﻫﻲ إذاً ﺗﻮاﺑﻊ ﺧﺎرﺟﻴﺔ ﻟﻨﺴﺒﺔ ﻟﻠﺼﻨﻒ‪ ،‬وﻫﻲ ﺗﻮاﺑﻊ ﻣﺴﺘﻘﻠﺔ أو أﻋﻀﺎء ﰲ ﺻﻨﻮف أﺧﺮى‬
‫ﻳﺴﻤﺢ ﳍﺎ ﻟﻮﺻﻮل إﱃ أﻋﻀﺎء اﻟﺼﻨﻒ‪ ،‬ﻛﺎﻟﺒﻴﺎ ت واﻟﺘﻮاﺑﻊ‪.‬‬
‫‪class A‬‬
‫{‬
‫;‪int a‬‬
‫;)‪friend void Write_a(int i‬‬
‫;}‬

‫;‪A Test‬‬

‫)‪void Write_a(int i‬‬


‫{‬
‫;‪Test.a=i‬‬
‫;‪return‬‬
‫}‬

‫‪٢٤-٣‬‬
‫ﺗﻄﺒﻴﻘﺎﺕ ﻋﻤﻠﻴﺔ‬

‫اﻟﺘﻄﺒﻴﻖ اﻷول‪:‬‬
‫ﻟﻌﻮدة إﱃ ﺗﻄﺒﻴﻖ ﺗﻜﻮﻳﻦ ﻻﺋﺤﺔ ﺧﻄﻴﺔ ﲰﺎء ﻃﻼب ﳝﻜﻨﻨﺎ ﲡﻤﻴﻊ اﻟﺘﻮاﺑﻊ اﳌﺴ ـ ـ ـ ـ ــﺘﺨﺪﻣﺔ ﳌﻌﺎﳉﺔ ﻻﺋﺤﺔ ﰲ ﻏﺮض‬
‫وﺣﻴﺪ‪ ،‬أو ﲡﻤﻴﻌﻬﺎ ﲝﺴــﺐ اﻟﻮﻇﺎﺋﻒ ﰲ أﻏﺮاض ﻣﺘﻌﺪدة ﺗﺘﻮارث اﻟﺼــﻔﺎت واﻟﺘﻮاﺑﻊ ﻓﻴﻤﺎ ﺑﻴﻨﻬﺎ‪ .‬ﺳــﻨﺒﲔ ﰲ ﻫﺬا اﻟﺘﻄﺒﻴﻖ ﲡﻤﻴﻊ‬
‫ﻫﺬﻩ اﻟﺘﻮاﺑﻊ ﰲ ﻓﺌﺔ واﺣﺪة‪:‬‬
‫>‪#include <iostream.h‬‬
‫>‪#include <stdlib.h‬‬
‫>‪#include <string.h‬‬

‫‪struct String‬‬
‫{‬
‫;]‪char Name[20‬‬
‫;]‪char Id_Number[6‬‬
‫;}‬

‫‪String Data[30]={ {{'A'},{'1'}},‬‬


‫‪{{'B'},{'2'}},‬‬
‫‪{{'C'},{'3'}},‬‬
‫‪{{'D'},{'4'}},‬‬
‫‪{{'E'},{'5'}},‬‬
‫‪{{'F'},{'6'}},‬‬
‫‪{{'G'},{'7'}},‬‬
‫‪{{'H'},{'8'}},‬‬
‫‪{{'I'},{'9'}},‬‬
‫‪{{'J'},{'1','0'}},‬‬
‫;}‬

‫‪struct Student‬‬
‫{‬
‫;]‪char Name[20‬‬
‫;]‪char Id_Number[6‬‬
‫;‪Student *Successor‬‬
‫;}‬
‫‪class Students‬‬
‫{‬
‫‪public:‬‬
‫;‪Student *List_Student‬‬
‫‪public:‬‬
‫;)(‪Students‬‬

‫‪٢٥-٣‬‬
Student *New_Node();
Student *Last_Node(Student *L);
Student *Search_Node(Student *List, char name[]);
Student *Successor();
Student *Predecessor(Student *List, Student *P);
Student *Swap( Student *P, Student *L);
Student *Sort(Student *List);
void Add_Node();
void Add_NodeP(Student *S);
void Delet_NodeP(Student *P);
void View_Node(Student *List);
void View_List();
};

Students::Students()
{
int i;
Student *s, *p;
List_Student=new Student;
strcpy(List_Student->Name,Data[0].Name);
strcpy(List_Student->Id_Number,Data[0].Id_Number);
List_Student->Successor=NULL;
s=List_Student;
for (i=1; i<=9;i++)
{
p=new Student;
strcpy(p->Name,Data[i].Name);
strcpy(p->Id_Number,Data[i].Id_Number);
p->Successor=NULL;
s->Successor=p;
s=p;
}
}

Student *Students::New_Node()
{
Student *s;
s=new Student;
cout<<"Name:";cin>>s->Name;
cout<<"Id_Number:";cin>>s->Id_Number;
s->Successor=NULL;
return s;
}

٢٦-٣
Student *Students::Last_Node(Student *L)
{
if (L->Successor==NULL) return L;
else Last_Node(L->Successor);
}

Student *Students::Search_Node(Student *List, char name[])


{

if (strcmp( List->Name, name)==0) return List;


if (List->Successor!=NULL)
Search_Node(List->Successor,name);
else return NULL;
}
Student *Students::Successor()
{
Student *List;
List=List_Student;
if (List->Successor==NULL) return NULL;
else return List->Successor;
}

Student *Students::Predecessor(Student *List, Student *P)


{
if (List->Successor==P) return List;
if (List->Successor!=NULL) Predecessor(List->Successor, P);
else return NULL;
}
Student *Students::Swap( Student *P, Student *L)
{
Student *S, *PP, *PL, *List;

List=List_Student;
PP=Predecessor(List, P);
PL=Predecessor(List, L);
if (PP==L)
{
L->Successor=P->Successor;
P->Successor=L;
if (PL!=NULL) PL->Successor=P; else List= P;
return List;
}

٢٧-٣
if (PL==P)
{
P->Successor=L->Successor;
L->Successor=P;
if (PP!=NULL) PP->Successor=L; else List =L;
return List;
}
S=P->Successor;
P->Successor=L->Successor;
L->Successor=S;
if (PP!=NULL) PP->Successor=L; else List =L;
if (PL!=NULL) PL->Successor=P; else List= P;
return List;
}

Student *Students::Sort(Student *List)


{
Student *L1, *L2, *S;
L1=List;
while (L1!=NULL)
{
L2=L1->Successor;
while (L2!=NULL)
{
if (L1->Id_Number>L2->Id_Number)
{
List=Swap(L1,L2);
S=L1;
L1=L2;
L2=S;
}
L2=L2->Successor;
}
L1=L1->Successor;
}
return List;
}

void Students::Add_Node()
{
Student *L,*List;

List=List_Student;

٢٨-٣
L=Last_Node(List);
L->Successor=New_Node();
}

void Students::Add_NodeP( Student *S)


{
int i;
Student *L, *List;
List=List_Student;
L=New_Node();
if (S->Successor!=NULL) L->Successor=S->Successor;
S->Successor=L;
}
void Students::Delet_NodeP( Student *P)
{
Student *L, *List;
List=List_Student;
L=Predecessor(List, P);
if (L==NULL) L=List;
L->Successor=P->Successor;
}

void Students::View_List()
{
Student *S;
S=List_Student;
while (S!=NULL)
{
View_Node(S);
S=S->Successor;
}
}

void Students::View_Node(Student *List)


{
cout<<"Name:"<<List->Name<<endl;
cout<<"Id_Number:"<<List->Id_Number<<endl;
}

void main()
{
int i;
Students st;

٢٩-٣
st.View_List();
}

‫اﻟﺘﻄﺒﻴﻖ اﻟﺜﺎﱐ‬
:‫ﳝﻜﻦ إﻋﺎدة ﻛﺘﺎﺑﺔ ﺑﺮ ﻣﺞ ﺣﺴﺎب ﺣﺠﻢ ﺻﻨﺪوق ﺳﺘﺨﺪام ﺑﻴﺎ ت ﺧﺎﺻﺔ ﻛﻤﺎ ﻳﻠﻲ‬
#include <iostream>
using namespace std;
class CBox
{
private:
double m_Length;
double m_Width;
double m_Height;
public:
CBox(double lv, double bv, double hv)
{
m_Length = lv;
m_Width = bv;
m_Height = hv;
}
double Volume(void)
{
return m_Length* m_Width* m_Height;
}
};

int main(void)
{
CBox box1(78.0,24.0,18.0); // box1 ‫ﺗﻌﺮﻳﻒ ﻏﺮض ﻣﻦ ﺻﻨﻒ‬
CBox cigarBox(8.0,5.0,1.0); // cigarBox ‫ﺗﻌﺮﻳﻒ ﻏﺮض ﻣﻦ ﺻﻨﻒ‬
double boxVolume = 0.0; //0 ‫ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑ ﻳﺸﲑ إﱃ ﺟﻢ اﻟﺼﻨﺪوق ﺑﻘﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ‬
boxVolume = box1.Volume();
cout << "Volume of box1 = " << boxVolume<< endl;
boxVolume = cigarBox.Volume();
cout << "Volume of cigarBox = " << boxVolume<< endl;
return 0;
}
:‫ﺗﺞ ﺗﻨﻔﻴﺬ ﻫﺬا اﻟﱪ ﻣﺞ ﻫﻮ‬
Volume of Box1 = 33696
Volume of cigarBox = 40
٣٠-٣
‫وﻫﻲ ﻧﺘﻴﺠﺔ ﳓﺼ ــﻞ ﻋﻠﻴﻬﺎ ﻓﻴﻤﺎ ﻟﻮ ﰎ اﻟﺘﻌﺮﻳﻒ ﻋﻦ ﺑﻴﺎ ت اﻟﺼ ــﻨﻒ ‪ CBox‬ﻋﻠﻰ ﺷ ــﻜﻞ ﺑﻴﺎ ت ﻋﺎﻣﺔ ‪ ،public‬إﻻ‬
‫أن ﻛﺘﺎﺑﺔ ﺗﻌﻠﻴﻤﺔ إدﺧﺎل ﺑﻴﺎ ت اﻟﻐﺮض ‪ box1‬ﰲ اﻹﺟﺮاء ‪ main‬ﻟﺸﻜﻞ‪:‬‬
‫;‪cin>>box1.m_Length‬‬
‫;‪cin>>box1.m_Width‬‬
‫;‪cin>>box1.m_Height‬‬
‫ﻋﻠﻰ ﺳـ ـ ــﺒﻴﻞ اﳌﺜﺎل‪ ،‬ﺳ ـ ــﻴﺆدي إﱃ إﺻ ـ ــﺪار رﺳ ـ ــﺎﻟﺔ ﺧﻄﺄ ﰲ ﻫﺬﻩ اﻟﻨﺴ ـ ــﺨﺔ ﻣﻦ اﻟﱪ ﻣﺞ ﻷن ﻫﺬﻩ اﳌﺘﻐﲑات ﻏﲑ ﻣﻌﺮوﻓﺔ ﺧﺎرج‬
‫اﻟﺼﻨﻒ ‪.CBox‬‬
‫اﻟﺘﻄﺒﻴﻖ اﻟﺜﺎﻟﺚ‪:‬‬
‫ﺳـ ـ ــﻨﺒﲔ ﰲ ﻫﺬا اﻟﺘﻄﺒﻴﻖ اﺳ ـ ـ ــﺘﺨﺪام اﻟﺘﻮاﺑﻊ اﻟﻈﺎﻫﺮﻳﺔ وﻣﺘﻌﺪدة اﻷﺷـ ـ ــﻜﺎل ﻟﺘﻨﻔﻴﺬ ﻋﻤﻠﻴﺔ ﺣﺴـ ـ ــﺎب اﻟﺮواﺗﺐ ﺗﺒﻌﺎً ﻟﻨﻮع‬
‫اﳌﻮﻇﻒ‪ .‬ﳍﺬا ﺳﻨﻌﺮف اﻟﻔﺌﺔ اﻷﺳﺎﺳﻴﺔ ‪ Employee‬ﻛﻤﺎ ﻳﻠﻲ‪:‬‬
‫‪class Employee‬‬
‫{‬
‫‪public:‬‬
‫;)‪Employee(char *first, char *last‬‬
‫;)(‪~Employee‬‬
‫;)(‪char *getFirstName‬‬
‫;)(‪char *getLastName‬‬
‫;};‪float earnings() {return 0‬‬
‫;}{)(‪void print‬‬
‫‪private:‬‬
‫;‪char *firstName‬‬
‫;‪char *lastName‬‬
‫;}‬
‫أﻣﺎ ﺗﻌﺮﻳﻒ ﻫﺬﻩ اﻟﺘﻮاﺑﻊ ﻓﻴﻤﻜﻦ أن ﻳﻜﻮن ﻋﻠﻰ اﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫)‪Employee::Employee(char *first, char *last‬‬
‫{‬
‫;] ‪firstName = new char[ strlen(first) + 1‬‬
‫اﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎن ﻋﺎﻣﻼً ﺟﺪﻳﺪاً ‪assert(firstName != 0); //‬‬
‫;)‪strcpy(firstName, first‬‬
‫;] ‪lastName = new char[ strlen(last) + 1‬‬
‫اﺧﺘﺒﺎر ﻓﻴﻤﺎ إذا ﻛﺎن ﻋﺎﻣﻼً ﺟﺪﻳﺪاً ‪assert(lastName != 0); //‬‬
‫;)‪strcpy(lastName, last‬‬
‫}‬

‫إﻟﻐﺎء ﺣﺠﻮزات اﻟﺬاﻛﺮة ‪Employee::~Employee() //‬‬


‫{‬
‫;‪delete [] firstName‬‬

‫‪٣١-٣‬‬
‫;‪delete [] lastName‬‬
‫}‬

‫)(‪char *Employee::getFirstName‬‬
‫ﻳﻌﻴﺪ ﻫﺬا اﻟﺘﺎﺑﻊ ﻣﺆﺷﺮاً ﻟﻼﺳﻢ اﻷول‪{ //‬‬
‫‪ .‬ﻳﺴﺘﺨﺪم اﻟﺜﺎﺑﺖ ﻟﻸﺧﺬ ﳊﺴﺒﺎن أﺛﻨﺎء ﺗﻐﻴﲑ اﻟﺒﻴﺎ ت ﻛﻤﺎ ﳚﺐ أن ﻳﻌﻴﺪ ‪//‬‬
‫اﻟﺘﺎﺑﻊ ﺑﻌﺪ ﺳﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ ﻗﺒﻞ ﺪﱘ اﻟﻐﺮض وﳜﺰن دﻳﻨﺎﻣﻴﻜﻴﺎً ﻟﻸﺧﺬ ﺑﻌﲔ اﻻﻋﺘﺒﺎر ‪//‬‬
‫اﳌﺆﺷﺮات ﻏﲑ اﳌﻌﺮف ‪//‬‬
‫;‪return firstName‬‬
‫}‬

‫)(‪char *Employee::getLastName‬‬
‫{‬
‫وﻇﻴﻔﺔ اﻟﺘﺎﺑﻊ اﻟﺴﺎﺑﻖ ‪//‬‬
‫;‪return lastName‬‬
‫}‬

‫اﻟﻔﺌﺎت اﳌﺸﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺔ ‪ Employee‬ﻫﻲ اﻟﻔﺌﺎت اﻟﺘﺎﻟﻴﺔ‪:‬‬


‫‪ ‬اﻟﻔﺌﺔ ‪ Boss‬اﳌﺘﻌﻠﻘﺔ ﲟﻮﻇﻔﲔ ﻳﺘﻘﺎﺿﻮن راﺗﺒﺎً ﺷﻬﺮ ً ﺑﺘﺎً ﺑﻐﺾ اﻟﻨﻈﺮ ﻋﻦ ﻋﺪد ﺳﺎﻋﺎت ﻋﻤﻠﻬﻢ‪.‬‬
‫‪ ‬اﻟﻔﺌﺔ ‪ CommissionWorker‬وﲣﺺ ﻣﻮﻇﻔﲔ ﳛﺼﻠﻮن ﻋﻠﻰ راﺗﺐ أﺳﺎﺳﻲ ﻣﻀﺎﻓﺎً إﻟﻴﻪ ﻧﺴﺒﺔ ﳏﺪدة ﺗﺘﺒﻊ ﻋﺪد‬
‫اﻟﻘﻄﻊ اﳌﺒﺎﻋﺔ‪.‬‬
‫‪ ‬اﻟﻔﺌﺔ ‪ PieceWorker‬وﺗﺘﻌﻠﻖ ﲝﺴﺎب رواﺗﺐ اﳌﻮﻇﻔﲔ اﻟﺬﻳﻦ ﻻ ﻳﺘﻘﺎﺿﻮن إﻻ ﻧﺴﺒﺔ ﳏﺪدة ﺑﻌﺪد اﻟﻘﻄﻊ اﳌﺒﺎﻋﺔ‪.‬‬
‫‪ ‬اﻟﻔﺌﺔ ‪ HourlyWorker‬ﻟﻠﻌﻤﺎل اﻟﺬي ﻳﻌﻤﻠﻮن ﺑﺸﻜﻞ ﺳﺎﻋﻲ‪ ،‬أي أ ﻢ ﻳﺘﻘﺎﺿﻮن أﺟﺮاً ﲝﺴﺐ ﻋﺪد اﻟﺴﺎﻋﺎت‬
‫ﻣﻀﺎﻓﺎً إﻟﻴﻪ ز دة ﳏﺪدة ﻋﻨﺪ ﲡﺎوز ﻋﺪد ﺳﺎﻋﺎت اﻟﻌﻤﻞ ﺣﺪاً ﻣﻌﻴﻨﺎً‪.‬‬
‫أﻣﺎ أواﻣﺮ ﻫﺬﻩ اﻟﺘﻮاﺑﻊ ﻓﻬﻲ ﻋﻠﻰ اﻟﺸﻜﻞ اﻟﺘﺎﱄ‪:‬‬
‫ﻳﺘﻢ اﺳ ـ ـ ــﺘﺪﻋﺎء اﻟﺘﺎﺑﻊ ‪ Earnings‬ﳊﺴـ ـ ــﺎب أﺟﻮر اﳌﻮﻇﻔﲔ ﻣﻬﻤﺎ ﻛﺎن اﳌﺮﺗﺐ‪ .‬إﻻ أن ﻃﺮﻳﻘﺔ اﳊﺴـ ـ ــﺎب ﺗﺘﻌﻠﻖ ﲟﺮﺗﺐ‬
‫اﳌﻮﻇﻒ وﻫﻲ ﻓﺌﺎت ﻣﺸ ـ ــﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺔ اﻷﺳ ـ ــﺎﺳ ـ ــﻴﺔ ‪ .Employee‬وﳍﺬا ﳚﺐ اﻟﺘﺼـ ـ ـﺮﻳﺢ ﻋﻦ ‪ Earning‬ﻋﻠﻰ أﻧﻪ ﺑﻊ ﻇﺎﻫﺮي‬
‫ﺿﻤﻦ اﻟﻔﺌﺔ اﻷﺳﺎﺳﻴﺔ ‪ Employee‬وﳚﺐ ﺗﻌﺪﻳﻠﻪ ﺿﻤﻦ اﻟﻔﺌﺎت اﳌﺸﺘﻘﺔ ﺑﺸﻜﻞ ﻳﻨﺎﺳﺐ ﻛﻞ ﻓﺌﺔ‪ .‬و ﻟﺘﺎﱄ ﻣﻦ أﺟﻞ ﺣﺴﺎب‬
‫أﺟﺮ أي ﻣﻮﻇﻒ ﻳﻘﻮم اﻟﱪ ﻣﺞ ﺳـ ـ ـ ـ ــﺘﺨﺪام ﻣﺆﺷـ ـ ـ ـ ــﺮ ﻓﺌﺔ أﺳـ ـ ـ ـ ــﺎس ﻳﺪل ﻋﻠﻰ اﻟﻐﺮض اﳌﺮﺗﺒﻂ ﳌﻮﻇﻒ ﰒ ﻳﺴـ ـ ـ ـ ــﺘﺪﻋﻲ اﻟﺘﺎﺑﻊ‬
‫‪.Earning‬‬
‫ﻓﻴﻤﺎ ﻳﻠﻲ ﺗﻌﺮﻳﻒ اﻟﻔﺌﺎت اﳌﺸﺘﻘﺔ ﻣﻦ اﻟﻔﺌﺔ اﻷﺳﺎس ‪:Employee‬‬
‫‪class Boss : public Employee‬‬
‫{‬
‫‪public:‬‬

‫‪٣٢-٣‬‬
Boss(char *first, char *last, float s= 0.0);
void setWeeklySalary(float);
virtual float earnings();
virtual void print();
private:
float weeklySalary;
};

class CommissionWorker : public Employee


{
public:
CommissionWorker(char * first, char * last,
float s= 0.0, float c= 0.0, unsigned q= 0);
void setSalary(float);
void setCommission(float);
void setQuantity(unsigned);
virtual float earnings() ;
virtual void print();
private:
float salary; // ‫أﺳﺎس اﻟﺮاﺗﺐ اﻷﺳﺒﻮﻋﻲ‬
float commission; // ‫رﺻﻴﺪ اﻟﺰ دة ﻣﻦ أﺟﻞ ﻛﻞ ﻗﻄﻌﺔ‬
unsigned quantity; // ‫ﻋﺪد اﻟﻘﻄﻊ ﻷﺳﺒﻮع‬
};

class PieceWorker : public Employee


{
public:
PieceWorker(char *first, char *last, float w= 0.0, unsigned q= 0);
void setWage(float);
void setQuantity(unsigned);
virtual float earnings();
virtual void print();
private:
float wagePerPiece; // ‫أﺟﺮ اﻟﻘﻄﻌﺔ‬
unsigned quantity; // ‫اﻟﻜﻤﻴﺔ اﻷﺳﺒﻮﻋﻴﺔ‬
};

class HourlyWorker : public Employee


{
public:
HourlyWorker(char *first, char *last,
٣٣-٣
float w= 0.0, float h= 0.0);
void setWage(float);
void setHours(float);
virtual float earnings();
virtual void print();
private:
float wage; // ‫أﺟﺮ اﻟﺴﺎﻋﺔ‬
float hours; // ‫ﻋﺪد اﻟﺴﺎﻋﺎت اﻷﺳﺒﻮﻋﻴﺔ‬
};
:‫أﻣﺎ أواﻣﺮ ﻫﺬﻩ اﻟﺘﻮاﺑﻊ ﻓﻬﻲ ﻛﻤﺎ ﻳﻠﻲ‬
Boss::Boss(char *first, char *last, float s)
{
Employee(first, last) // ‫اﺳﺘﺪﻋﺎء ﱐ اﻟﻐﺮض اﻟﺮﺋﻴﺴﻲ‬
weeklySalary = s > 0 ? s : 0; 1
}

void Boss::setWeeklySalary(float s)
{
weeklySalary = s > 0 ? s : 0;
}

float Boss::earnings()
{
return weeklySalary;
}

void Boss::print()
{
cout << endl << " Boss: " << getFirstName()
<< ' ' << getLastName();
}

CommissionWorker::CommissionWorker(char *first,
char *last, float s, float c, unsigned q)
: Employee(first, last) // ‫اﺳﺘﺪﻋﺎء ﱐ اﻟﻐﺮض اﻟﺮﺋﻴﺴﻲ‬
{
salary = s > 0 ? s : 0;

weeklySalary ‫ ﺧﺬ اﳌﺘﻐﲑ‬s>0 ‫ أﻧﻪ إذا ﻛﺎﻧﺖ‬weeklySalary = s > 0 ? s : 0; ‫اﻟﻌﻤﻠﻴﺔ "?" ﻫﻲ ﻋﻤﻠﻴﺔ اﺧﺘﺒﺎر ﻣﻨﻄﻘﻲ ﻣﺮﻛﺒﺔ وﺗﻌﲏ اﻟﻌﺒﺎرة‬ ١

.0 ‫ وإﻻ ﺧﺬ ﻫﺬا اﳌﺘﻐﲑ اﻟﻘﻴﻤﺔ‬s ‫اﻟﻘﻴﻤﺔ‬

٣٤-٣
commission = c > 0 ? c : 0;
quantity = q > 0 ? q : 0;
}

void CommissionWorker::setSalary(float s)
{ salary = s > 0 ? s : 0; }

void CommissionWorker::setCommission(float c)
{ commission = c > 0 ? c : 0; }

void CommissionWorker::setQuantity(unsigned q)
{ quantity = q > 0 ? q : 0; }

float CommissionWorker::earnings() const


{ return salary + commission * quantity; }

void CommissionWorker::print() const


{
cout << endl << "Commission worker: " << getFirstName()
<< ' ' << getLastName();
}

PieceWorker::PieceWorker(char *first, char *last,


float w, unsigned q): Employee(first, last) // ‫اﺳﺘﺪﻋﺎء ﱐ اﻟﻐﺮض اﻟﺮﺋﻴﺴﻲ‬
{
wagePerPiece = w > 0 ? w : 0;
quantity = q > 0 ? q : 0;
}

void PieceWorker::setWage(float w) { wagePerPiece = w > 0 ? w : 0; }

void PieceWorker::setQuantity(unsigned q)
{ quantity = q > 0 ? q : 0; }

float PieceWorker::earnings()
{ return quantity * wagePerPiece; }

void PieceWorker::print()
{
cout << endl << " Piece worker: " << getFirstName()
<< ' ' << getLastName();

٣٥-٣
}
HourlyWorker::HourlyWorker(char *first, char *last,
float w, float h) : Employee(first, last)
{
wage = w > 0 ? w : 0;
hours = h >= 0 && h < 168 ? h : 0;
}

void HourlyWorker::setWage(float w) { wage = w > 0 ? w : 0; }

void HourlyWorker::setHours(float h)
{ hours = h >= 0 && h < 168 ? h : 0; }

float HourlyWorker::earnings() { return wage * hours; }

void HourlyWorker::print()
{
cout << endl << " Hourly worker: " << getFirstName()
<< ' ' << getLastName();
}
:‫ﻻﺧﺘﺒﺎر اﻟﱪ ﻣﺞ اﻟﻨﻬﺎﺋﻲ ﳝﻜﻦ أن ﻧُ ﱠﻜﻮن اﻟﱪ ﻣﺞ اﻟﺘﺎﱄ‬
#include <iostream.h>
#include <iomanip.h>
main()
{
cout << setiosflags(ios::showpoint) << setprecision(2);

Employee *ptr;
Boss b("John", "Smith", 800.00);
ptr = &b;
ptr->print();
cout << " earned $" << ptr->earnings();
b.print();
cout << " earned $" << b.earnings();

CommissionWorker c("Sue", "Jones", 200.0, 3.0, 150);


ptr = &c;
ptr->print();
cout << " earned $" << ptr->earnings();
c.print();
cout << " earned $" << c.earnings();

٣٦-٣
PieceWorker p("Bob", "Lewis", 2.5, 200);
ptr = &p;
ptr->print();
cout << " earned $" << ptr->earnings();
p.print();
cout << " earned $" << p.earnings();

HourlyWorker h("Karen", "Price", 13.75, 40);


ptr = &h;
ptr->print();
cout << " earned $" << ptr->earnings();
h.print();
cout << " earned $" << h.earnings();
cout << endl;
return 0;
}

٣٧-٣

You might also like