Professional Documents
Culture Documents
ﳝﻜــﻦ ﲤﺜﻴــﻞ ﻛــﻞ اﻷﺷــﻴﺎء اﻟــﱵ ﻧﺘﻌﺎﻣــﻞ ﻣﻌﻬــﺎ ﲜﻤﻠــﺔ ﻣــﻦ اﻟﺒﻴﺎﻧــﺎت ،اﻟﻄﺎﻟــﺐ ﻣــﺜﻼً ﺑﺎﻟﻨﺴــﺒﺔ ﻟﺸــﺆون
اﻟﻄﻼب ﻫـﻮ ﻣﻌﻠﻮﻣـﺎت ﺗﺸـﻤﻞ اﺳـﻢ اﻟﻄﺎﻟـﺐ وﺗﻮﻟـﺪﻩ وﻋﻨﻮاﻧـﻪ وﺗـﺎرﻳﺦ اﻟﺘﺴـﺠﻴﻞ واﻟﺴـﻨﺔ اﻟـﱵ ﻳـﺪرس ـﺎ ،وﰲ
ﺷ ــﻌﺒﺔ اﻻﻣﺘﺤﺎﻧــﺎت ﻫ ــﻮ ﻋﺒ ــﺎرة ﻋ ــﻦ ﲨﻠ ــﺔ ﺑﻴﺎﻧ ــﺎت ﻗ ــﺪ ﺗﺘﻀــﻤﻦ ﺟــﺰءاً ﻣ ــﻦ اﻟﺒﻴﺎﻧ ــﺎت اﻟ ــﱵ ــﻢ ﺷــﻌﺒﺔ ﺷ ــﺆون
اﻟﻄﻼب إﺿﺎﻓﺔ إﱃ ﻣﻌﻠﻮﻣﺎت ﺗﺘﻌﻠﻖ ﺑﺪرﺟﺎﺗﻪ ﰲ اﻣﺘﺤﺎﻧﺎت اﳌﻘﺮرات.
اﳌﺆﺷﺮ ﻫﻮ ﻋﻨﻮان ﰲ اﻟﺬاﻛﺮة اﻟﺪاﺧﻠﻴﺔ ﳉﻬﺎز اﳊﺎﺳﻮب ﻳـﺪل ﻋﻠـﻰ ﻣﻮﻗـﻊ ﲣـﺰﻳﻦ ﻛﺘﻠـﺔ ﻣـﻦ اﻟﺒﻴﺎﻧـﺎت.
وﻫــﻮ ﻣﺘﻐــﲑ ﳛــﺪد ﻗﻴﻤﺘــﻪ ﻣــﱰﺟﻢ اﻟﻠﻐــﺔ ﰲ أﺛﻨــﺎء اﻟﺘﺼ ـﺮﻳﺢ ﻋﻨــﻪ ﰲ اﻟﱪﻧــﺎﻣﺞ أو ﳝﻜــﻦ ﲢﺪﻳــﺪ ﻗﻴﻤﺘــﻪ ﻣــﻦ ﻗﺒــﻞ
اﳌﱪﻣﺞ ﻛﺒﺎﻗﻲ اﳌﺘﻐﲑات ﻟﻘﺮاءة ﻣﻮاﻗﻊ ﰲ اﻟﺬاﻛﺮة ،وﻫﺬا ﻣﺎ ﻻ ﻳﺴﺘﺨﺪﻣﻪ اﳌﱪﳎﻮن إﻻ ﻧﺎدراً ﻟﻌﺪم اﳊﺎﺟﺔ ﻟﻪ.
ﺳــﻨﺒﲔ ﰲ ﻫــﺬﻩ اﻟﻮﺣــﺪة ﻛﻴﻔﻴــﺔ اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ اﳌﺆﺷـﺮات ﻛﻤﺘﻐـﲑات دﻳﻨﺎﻣﻴﻜﻴــﺔ ،وﺳــﻨﺒﲔ أﻳﻀـﺎً ﻛﻴﻔﻴــﺔ
ﲣـ ـﺰﻳﻦ اﻟﺒﻴﺎﻧ ــﺎت ﰲ اﳌﻮاﻗ ــﻊ اﻟ ــﱵ ﺗ ــﺪل ﻋﻠﻴﻬ ــﺎ ﻫ ــﺬﻩ اﳌﺆﺷـ ـﺮات واﺳ ــﺘﺨﺮاﺟﻬﺎ .ﻛﻤ ــﺎ ﺳ ــﻨﺒﲔ ﻛﻴﻔﻴ ــﺔ اﺳ ــﺘﺨﺪام
اﳌﺆﺷﺮات ﰲ ﺑﻨﺎء اﻟﻠﻮاﺋﺢ اﳋﻄﻴﺔ.
١-١
ﻳﺄﺧــﺬ ﻗﻴﻤــﺔ ﲤﺜــﻞ أﺣــﺪ أﻳــﺎم اﻷﺳــﺒﻮع )اﻟﺴــﺒﺖ اﻷﺣــﺪ .(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
٣-١
ﺣﻴــﺚ Typeﳕــﻂ ﻣــﻦ أﳕــﺎط اﻟﺒﻴﺎﻧــﺎت اﳌﻌﺮﻓــﺔ ﺑﻠﻐــﺔ C++ﺑﺸــﻜﻞ ﻣﺴــﺒﻖ أو اﳌﻌــﺮف ﻣــﻦ ﻗﺒــﻞ اﳌﺴــﺘﺨﺪم و
Variable_Nameاﺳﻢ اﳌﺘﻐﲑ.
new -١-٣-١اﻷﻣﺮ
ﻋﻨــﺪ اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ ﻣﺘﻐــﲑ ﻣﺆﺷــﺮ ﺑﻠﻐــﺔ Visual C++ﻳﺄﺧــﺬ ﻫــﺬا اﳌﺘﻐــﲑ اﻟﻘﻴﻤــﺔ NULLاﻟــﱵ ﺗــﺪل
ﻋﻠـﻰ ﻻ ﺷـﻲء ،وﻫـﻲ ﻗﻴﻤــﺔ ﻣﻌﺮﻓـﺔ ﺑﻠﻐـﺔ Visual C++وﺗـﺪل ﻋﻠـﻰ اﻟﻌﻨـﻮان .0x000000وﻫـﺬا اﻟﻌﻨـﻮان ﻣــﻦ
اﻟﺬاﻛﺮة ﻻ ﳝﻜﻦ ﲣﺰﻳﻦ ﻓﻴﻪ ﺷﻲء .ﻟﺬا ﻓﻌﻨﺪ اﺳﺘﺨﺪاﻣﻨﺎ ﳌﺘﻐﲑ ﻣﺆﺷﺮ ﻻ ﺑﺪ ﻣﻦ إﻋﻄﺎﺋﻪ ﻗﻴﻤـﺔ ،وﳝﻜﻨﻨـﺎ ﲢﺪﻳـﺪ
ﻋﻨ ـﻮان اﻟ ــﺬاﻛﺮة اﳌ ـﺮاد ﲣ ـﺰﻳﻦ ﻗﻴﻤ ــﺔ اﳌﺘﻐ ــﲑ ﻓﻴﻬ ــﺎ أو ﳝﻜﻨﻨ ــﺎ ﺗ ــﺮك اﻟﻠﻐ ــﺔ إﻋﻄ ــﺎء ﻗﻴﻤ ــﺔ ﲝﺴ ــﺐ اﻟ ــﺬاﻛﺮة اﳌﺘﺎﺣ ــﺔ
ﺑﺎﺳﺘﺨﺪام اﻷﻣﺮ newاﻟﺬي ﳛﺪد أﻳﻀﺎً ﺣﺠﻢ اﻟﺬاﻛﺮة اﳌﺨﺼﺼﺔ ﻟﺘﺨﺰﻳﻦ ﻗﻴﻤﺔ اﳌﺘﻐﲑ.
ﻳﺴﺘﺨﺪم اﻷﻣﺮ newﻋﻠﻰ اﻟﺸﻜﻞ اﻵﰐ:
Variable_Name =new type
ﺣﻴ ــﺚ typeﻫ ــﻮ ﳕ ــﻂ ﺑﻴﺎﻧ ــﺎت اﳌﺘﻐ ــﲑ اﳌﺆﺷ ــﺮ و Variable_Nameﻫ ــﻮ اﺳ ــﻢ اﳌﺘﻐ ــﲑ اﳌﺼ ــﺮح ﻋﻨ ــﻪ ﻣﺴ ــﺒﻘﺎً
ﺑﺎﻟﺸﻜﻞ:
type *Variable_Name;.
١ﳚﺐ إﻋﻄﺎء اﳌﺘﻐﲑ اﳌﺆﺷﺮ ﻗﻴﻤﺔ اﺑﺘﺪاﺋﻴﺔ ﻟﺘﻼﰲ ﺣﺼﻮل ﺧﻄﺄ ﰲ أﺛﻨﺎء ﺗﺮﲨﺔ اﻟﱪﻧﺎﻣﺞ .وﻳﺘﻢ ذﻟﻚ إﻣﺎ ﺑﺘﺤﺪﻳﺪ ﻫﺬا اﻟﻌﻨﻮان
ﻣﺒﺎﺷﺮة أو ﺑﺈﺳﻨﺎد ﻋﻨﻮان ﻣﺘﻐﲑ ﻣﻦ ﳕﻂ اﳌﺆﺷﺮ ﻧﻔﺴﻪ ﳕﻂ اﳌﺆﺷﺮ إﱃ اﳌﺘﻐﲑ اﳌﺆﺷﺮ.
٤-١
ﻓــﺈن xﻳﺸــﲑ إﱃ ﻋﻨ ـﻮان ﰲ اﻟــﺬاﻛﺮة اﻟﺪاﺧﻠﻴــﺔ ﻛﻤﻮﻗــﻊ ﻟﺘﺨ ـﺰﻳﻦ ﻫــﺬﻩ اﻟﻘﻴﻤــﺔ )ﻗﻴﻤــﺔ ،(xأي أن ﻗﻴﻤــﺔ xﻣــﻦ
اﻟﺸﻜﻞ ،x=0x3FBA000أﻣﺎ ﻗﻴﻤﺔ *xﻓﻬﻲ .10ﻳﻮﺿﺢ اﻟﺸﻜﻞ ١-١ﻋﻤﻠﻴﺔ ﲤﺜﻴﻞ اﻟﺒﻴﺎﻧﺎت ﺑﺎﺳﺘﺨﺪام
اﳌﺆﺷﺮات.
x ﻣﺆﺷﺮ اﳌﺘﻐﲑ x ﻣﻮﻗﻊ اﳌﺘﻐﲑ
0x3FBA000 10
0x3FBA000
٥-١
&y=0x0012FF7C
x=0x0012FF7C
z=0x0012FF7C
*x/2=5
٦-١
-٢-٤-١اﺳﺘﺨﺪام اﻟﺴﺠﻼت ﻛﺄﻧﻤﺎط ﻟﻠﺒﻴﺎﻧﺎت
ﺗﺴﺘﺨﺪم اﻟﺴﺠﻼت اﳌﻌﺮﻓﺔ ﺑﻠﻐﺔ 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
;}
٨-١
int second;
};
ﻣﺆﺷﺮات اﻟﺴﺠﻼت-٥-٤-١
ﻳــﺘﻢ اﻟﺘﺼ ـﺮﻳﺢ ﻋــﻦ ﻣﺆﺷ ـﺮات اﻟﺴــﺠﻼت ﺑﺎﻟﻄﺮﻳﻘــﺔ ﻧﻔﺴــﻬﺎ اﻟــﱵ ﻳــﺘﻢ اﻟﺘﺼ ـﺮﻳﺢ ﻓﻴﻬــﺎ ﻋــﻦ ﻣﺆﺷ ـﺮات
"->" arrow وﳝﻜﻦ اﻟﻮﺻـﻮل إﱃ ﺣﻘـﻮل اﻟﺴـﺠﻞ ﺑﺎﺳـﺘﺨﺪام اﳌﺆﺷـﺮ اﻟﺴـﻬﻢ.اﳌﺘﻐﲑات ﻣﻦ اﻟﻨﻤﻂ اﻟﻘﻴﺎﺳﻲ
ﻋﻨـﺪ اﻟﺘﺼـﺮﻳﺢ ﻋـﻦ ﺳـﺠﻞ اﻟﻮﻗـﺖ.ﺑﺪﻻً ﻣـﻦ اﻟﻨﻘﻄـﺔ اﻟـﱵ ﺗﺴـﺘﺨﺪم ﰲ أﺛﻨـﺎء اﻟﺘﺼـﺮﻳﺢ ﻋﻨﻬـﺎ ﺑﺎﻟﺸـﻜﻞ اﻟﻌـﺎدي
:ﺑﺎﻟﺸﻜﻞ
struct time
{
int hour;
int minute;
int second;
٩-١
;}
وﺑﻔﺮض ﺗﻌﺮﻳﻒ ﻣﺘﻐﲑ ﻣﺆﺷﺮ ﻣﻦ ﳕﻂ timeﺑﺎﻟﺸﻜﻞ اﻵﰐ:
;time *the_time
ﻓﺈﻧﻪ ﻳﺘﻢ اﻟﻮﺻﻮل إﱃ ﻛﻞ ﺣﻘﻞ ﻣﻦ اﳊﻘﻮل ﺑﺎﻟﺸﻜﻞ اﻵﰐ:
;the_time->hour
;the_time->minute
;the_time->second
)(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
}
١١-١
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,
……..
……..
١٢-١
Data ﺑﻴﺎﻧﺎت اﻟﻌﻘﺪة ﻣﺆﺷﺮ إﱃ اﻟﻌﻘﺪة اﻟﺘﺎﻟﻴﺔ
Node Pointer Node
١٣-١
;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
}
٥-٢
if (*y<min) min=*y;
if (*z<min) min=*z;
return min;
}
*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
٨-٢
;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
ﻣﺜﺎل ٥-٢
ﻟﻨﻌﺪ ﺻـ ــﻴﺎﻏﺔ اﻟﱪ ﻣﺞ ﰲ ﻣﺜﺎل ﺣﺴـ ــﺎب ﻋﺎﻣﻠﻲ ﻋﺪد ﲝﻴﺚ ﻧﻀـ ــﻊ ﺗﺮوﻳﺴـ ــﺔ اﻹﺟﺮاء " "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
}
١٣-٢
ﻟﻜﺘﻠﺔ اﻟﺪاﺧﻠﻴﺔ ﻓﺈ ﺎ ﺗﺮى ﻓﻘﻂ اﳌﺘﻐﲑات اﶈﻠﻴﺔ اﳋﺎﺻﺔ ﺎ وﻻ ﺗﺮى اﳌﺘﻐﲑات اﳌﻮﺟﻮدة ﰲ اﻟﻜﺘﻞ اﻟﱵ ﲢﺘﻮﻳﻬﺎ إن وﺟﺪت
ﻣﺘﻐﲑات ﳏﻠﻴﺔ ﻻﺳﻢ ﻧﻔﺴﻪ.
اﳌﺘﻐﲑات اﻟﻮﺣﻴﺪة اﻟﱵ ﻳﻄﺎل ﻣﺪاﻫﺎ ﻣﺴﺘﻮى ﳕﻮذج اﻹﺟﺮاء ﻫﻲ وﺳﻄﺎء اﻹﺟﺮاء .وﳕﺎذج اﻹﺟﺮاءات ﻻ ﲢﺘﺎج إﱃ ذﻛﺮ أﲰﺎء
اﻟﻮﺳﻄﺎء ﻋﻨﺪ اﺳﺘﺪﻋﺎﺋﻬﺎ ﺑﻞ ﳝﻜﻦ اﻻﻛﺘﻔﺎء ﺑﺬﻛﺮ أﳕﺎط ﻫﺬﻩ اﻟﻮﺳﻄﺎء ،وإذا ﻣﺎ ذﻛﺮت أﲰﺎء اﻟﻮﺳﻄﺎء ﻓﺴﻴﺘﻢ ﲡﺎﻫﻠﻬﺎ ﻣﻦ
ﻗﺒﻞ اﳌﱰﺟﻢ وﻣﻦ ﰒ ﳝﻜﻦ اﺳﺘﻌﻤﺎل ﻫﺬﻩ اﻷﲰﺎء ﰲ ﻣﻜﺎن آﺧﺮ ﰲ اﻟﱪ ﻣﺞ دون أي ﺛﲑ ﰲ ﺗﻨﻔﻴﺬ اﻹﺟﺮاء.
ﻣﺜﺎل ٦-٢
اﻟﱪ ﻣﺞ اﻵﰐ ﻳﺒﲔ ﻣﺪى اﳌﺘﻐﲑات ﰲ اﻟﱪ ﻣﺞ ﺑﻠﻐﺔ :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 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
}
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
)void f(void
{
;using namespace A
;i=1 ﺗﻌﻠﻴﻤﺔ // A::i=1 .ﺗﻜﺎﻓﺊ ﻫﺬﻩ اﻟﻌﻠﻴﻤﺔ
;j=1 ﺗﻌﻠﻴﻤﺔ // A::j=1 .ﺗﻜﺎﻓﺊ ﻫﺬﻩ اﻟﻌﻠﻴﻤﺔ
; return
}
ﻋﻨﺪ اﺳ ــﺘﺨﺪام ﻋﺒﺎرة اﻟﺘﻮﺟﻴﻪ usingﻳﺼ ــﺒﺢ ﻣﻦ اﳌﻤﻜﻦ اﺳ ــﺘﺨﺪام ﻛﻞ اﲰﺎء ﻣﻌﺮﻓﺎت ﻓﻀ ــﺎء اﻷﲰﺎء ،وﻫﻲ ﺻ ــﺎﳊﺔ
اﺑﺘﺪاءً ﻣﻦ ﻧﻘﻄﺔ وﺿ ـ ـ ــﻊ اﳌﻮﺟﻪ usingوﺣﱴ ﺎﻳﺔ ﳎﻤﻮﻋﺔ اﻟﺘﻌﻠﻴﻤﺎت اﻟﱵ ﺗﺘﻀ ـ ـ ــﻤﻦ ﻫﺬا اﻟﺘﻌﺮﻳﻒ .وإذا ﰎ إﺿ ـ ـ ــﺎﻓﺔ ﻣﻌﺮﻓﺎت
ﺟﺪﻳﺪة إﱃ ﻓﻀﺎء اﻷﲰﺎء ﺑﻌﺪ اﺳﺘﺨﺪام usingﺳﺘﺴﺘﺨﺪم أﻳﻀﺎً ﻛﻤﺎ ﻟﻮ أﻧﻪ ﻣﻌﺮﻓﺔ ﺳﺎﺑﻘﺎً ،واﳌﺜﺎل اﻟﺘﺎﱄ ﻳﻮﺿﺢ ذﻟﻚ:
namespace A
{
;int i
}
namespace A
{
;int j
}
)void f(void
{
;i=0
;j=0
; return
}
١٨-٢
-٣ﺍﻟﺴﻼﺳﻞ ﺍﳊﺮﻓﻴﺔ
ﺗﺸــﺒﻪ اﻟﺴﻼﺳــﻞ اﳊﺮﻓﻴــﺔ ﺑﻠﻐــﺔ C++اﳌﺼــﻔﻮﻓﺎت ،وﻫــﻲ ﻟﻮاﻗــﻊ ﺻــﻒ ﻣــﻦ اﳊــﺮوف ﻣــﻦ اﻟــﻨﻤﻂ charﻳﻨﺘﻬــﻲ ﻟﺮﻣــﺰ
اﳋﺎص " ."\0ﻳــﺘﻢ اﻟﻮﺻــﻮل إﱃ ﻛــﻞ ﺣــﺮف ﻣــﻦ ﺣــﺮوف اﻟﺴﻠﺴــﻠﺔ ﺑــﺮﻗﻢ ﻳﺸــﲑ إﱃ ﺗﺮﺗﻴــﺐ اﳊــﺮف ﰲ اﻟﺴﻠﺴــﻠﺔ .ﺧــﺬ اﻟﺘﺼـﺮﻳﺢ
ﻋﻦ ﺳﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ ﻣﺼﻔﻮﻓﺔ ﺣﺪ اﻷﺷﻜﺎل اﻵﺗﻴﺔ:
١-٣
ت -اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺆﺷﺮ إﱃ ﺳﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ
ﳝﻜــﻦ أﻳﻀـﺎً اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ ﻣﺘﻐــﲑ ﻳﺸــﲑ إﱃ ﺳﻠﺴــﻠﺔ ﺣﺮﻓﻴــﺔ ﺳــﺘﺨﺪام اﳌﺆﺷـﺮات ،وﻳــﺘﻢ اﻟﺘﻌﺎﻣــﻞ ﻣــﻊ اﻟﺴﻼﺳــﻞ اﳊﺮﻓﻴــﺔ
اﳌﺼﺮح ﻋﻨﻬﺎ ﺬﻩ اﻟﻄﺮﻳﻘﺔ ﲤﺎﻣﺎً ﻛﺎﻟﺘﻌﺎﻣﻞ ﻣﻊ ﻣﺼﻔﻮﻓﺔ اﳌﺆﺷﺮات .ﻳﺘﻢ اﻟﺘﺼـﺮﻳﺢ ﻋــﻦ ﻣﺼــﻔﻮﻓﺔ أﺣــﺮف ﻟﻄــﻮل اﶈــﺪد ﻟﻄﺮﻳﻘــﺔ
اﻵﺗﻴﺔ:
;]char *Name[n
وﺗﺴــﻨﺪ اﻟﻘــﻴﻢ إﱃ اﳌﺼــﻔﻮﻓﺎت اﳌﻌﺮﻓــﺔ ــﺬﻩ اﻟﻄﺮﻳﻘــﺔ ﺑــﻨﻔﺲ أﺳــﻠﻮب إﺳــﻨﺎد اﻟﻘــﻴﻢ إﱃ اﳌﺆﺷ ـﺮات ﻧﻔﺴــﻪ .ﻛﻤــﺎ ﳝﻜﻨﻨــﺎ
اﻟﺘﺼﺮﻳﺢ ﻋﻦ ﻣﺆﺷﺮ ﻟﺴﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ ﳛﺪد ﻃﻮﳍﺎ ﻣﻦ ﺧﻼل ﻋﻤﻠﻴﺔ اﻹﺳﻨﺎد ﻛﻤﺎ ﰐ:
;"char *color="blue
٢-٣
ﺗﺘﻀــﻤﻦ ﻣﻜﺘﺒــﺔ اﻹﺟـﺮاءات Stringﺑﻠﻐــﺔ C++اﻟﻌﺪﻳــﺪ ﻣــﻦ اﻹﺟـﺮاءات اﻟــﱵ ﺗﺴــﺘﺨﺪم ﰲ ﺗــﺪاول اﻟﺴﻼﺳــﻞ اﳊﺮﻓﻴــﺔ،
ﺳﻨﺒﲔ ﻓﻴﻤﺎ ﰐ ﺑﻌﺾ ﻫﺬﻩ اﻹﺟﺮاءات:
ﻣﺜﺎل ٢-٣
>#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
٣-٣
ﻳﻘ ــﻮم ﻫ ــﺬﻩ اﻹﺟـ ـﺮاء ﺿ ــﺎﻓﺔ اﻟﺴﻠﺴ ــﻠﺔ 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
٤-٣
ﻣﺜﺎل ٤-٣
>#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 اﻟﺼﻔﺔ-أ
. أي ﻋﺪد اﻟﺮﻣﻮز اﳌﻜﻮﻧﺔ ﻟﻠﺴﻠﺴﻠﺔ،ﺗﻌﻴﺪ ﻫﺬﻩ اﻟﺼﻔﺔ ﻃﻮل اﻟﺴﻠﺴﻠﺔ
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
٧-٣ ﻣﺜﺎل
وﻳــﺘﻢ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ﺍﻟﱪﳎﺔ ﻏﺮﺿﻴﺔ ﺍﻟﺘﻮﺟﻪ
ﺗﺴـ ــﺘﺨﺪم اﻟﺒﻴﺎ ت واﻟﺘﻮاﺑﻊ اﳋﺎﺻـ ــﺔ ﻓﻘﻂ ﰲ اﻷﻏﺮاض اﻟﱵ ﺗﻌﺮف ﻣﻦ ﳕﻂ اﻟﻔﺌﺔ ،وﻻ ﳝﻜﻦ اﺳـ ــﺘﺨﺪاﻣﻬﺎ ﰲ اﻟﻔﺌﺎت
واﳌﻮاﺿ ـ ــﻴﻊ اﻟﱵ ﺗﺘﻮارث ﺻـ ــﻔﺎت ﻫﺬﻩ اﻟﻔﺌﺔ أو ﰲ أي ﻣﻦ اﻟﻔﺌﺎت اﻟﱵ ﺗﺴـ ــﺘﺪﻋﻲ أﻏﺮاﺿ ـ ـﺎً ﻣﻦ ﻫﺬﻩ اﻟﻔﺌﺔ ،وﻳﺘﻢ ﺗﻌﺮﻳﻔﻬﺎ ﲢﺖ
اﺳــﻢ 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
{
;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();
};
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
١٣-٣
{
.ﻗﺎﺋﻤﺔ اﻷﻋﻀﺎء//
;}
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
;}
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
;}
١٨-٣
إذا أرد اﺳ ـ ــﺘﺪﻋﺎء ﺑﻊ ﻋﻀ ـ ــﻮ ﻳﻨﺘﻤﻲ إﱃ ﻓﺌﺔ ﻣﻦ ﻣﺴ ـ ــﺘﻮى أﻋﻠﻰ ﻣﻦ أي ﺑﻊ ﻣﻦ أي ﻋﻀ ـ ــﻮ ﳚﺐ ﲢﺪﻳﺪ اﻟﻔﺌﺔ اﻟﱵ ﻳﻨﺘﻤﻲ
إﻟﻴﻬﺎ ﻫﺬا اﻟﻌﻀﻮ وﻓﻖ ﻗﺎﻋﺪة اﺳﺘﺪﻋﺎء ﺧﺎﺻﺔ ،وﺗﺘﻢ وﻓﻖ اﻟﺸﻜﻞ اﻟﺘﺎﱄ:
;)(ClassName::FunctionName
ﻓﺈذا أرد اﺳﺘﺪﻋﺎء ﺑﻊ ﻃﺒﺎﻋﺔ اﻟﺘﻮﻗﻴﺖ )( Printاﳌﻌﺮف ﰲ اﻟﻔﺌﺔ Timeﰲ اﳌﺜﺎل ٦-٣ﻣﻦ اﻟﺘﺎﺑﻊ )( Printاﳌﻌﺮف
ﰲ اﻟﻔﺌﺔ Courseﻧﻜﺘﺐ اﻟﺼﻴﻐﺔ اﻟﺘﺎﻟﻴﺔ:
;)(Time::Print
١٩-٣
ﻟﻘﺪ ﰎ اﻟﺘﺼـ ـﺮﻳﺢ ﻋﻦ اﻟﺘﺎﺑﻊ )( 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
}
٢٢-٣
#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
٢٤-٣
ﺗﻄﺒﻴﻘﺎﺕ ﻋﻤﻠﻴﺔ
اﻟﺘﻄﺒﻴﻖ اﻷول:
ﻟﻌﻮدة إﱃ ﺗﻄﺒﻴﻖ ﺗﻜﻮﻳﻦ ﻻﺋﺤﺔ ﺧﻄﻴﺔ ﲰﺎء ﻃﻼب ﳝﻜﻨﻨﺎ ﲡﻤﻴﻊ اﻟﺘﻮاﺑﻊ اﳌﺴ ـ ـ ـ ـ ــﺘﺨﺪﻣﺔ ﳌﻌﺎﳉﺔ ﻻﺋﺤﺔ ﰲ ﻏﺮض
وﺣﻴﺪ ،أو ﲡﻤﻴﻌﻬﺎ ﲝﺴــﺐ اﻟﻮﻇﺎﺋﻒ ﰲ أﻏﺮاض ﻣﺘﻌﺪدة ﺗﺘﻮارث اﻟﺼــﻔﺎت واﻟﺘﻮاﺑﻊ ﻓﻴﻤﺎ ﺑﻴﻨﻬﺎ .ﺳــﻨﺒﲔ ﰲ ﻫﺬا اﻟﺘﻄﺒﻴﻖ ﲡﻤﻴﻊ
ﻫﺬﻩ اﻟﺘﻮاﺑﻊ ﰲ ﻓﺌﺔ واﺣﺪة:
>#include <iostream.h
>#include <stdlib.h
>#include <string.h
struct String
{
;]char Name[20
;]char Id_Number[6
;}
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);
}
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;
}
void Students::Add_Node()
{
Student *L,*List;
List=List_Student;
٢٨-٣
L=Last_Node(List);
L->Successor=New_Node();
}
void Students::View_List()
{
Student *S;
S=List_Student;
while (S!=NULL)
{
View_Node(S);
S=S->Successor;
}
}
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
}
٣١-٣
;delete [] lastName
}
)(char *Employee::getFirstName
ﻳﻌﻴﺪ ﻫﺬا اﻟﺘﺎﺑﻊ ﻣﺆﺷﺮاً ﻟﻼﺳﻢ اﻷول{ //
.ﻳﺴﺘﺨﺪم اﻟﺜﺎﺑﺖ ﻟﻸﺧﺬ ﳊﺴﺒﺎن أﺛﻨﺎء ﺗﻐﻴﲑ اﻟﺒﻴﺎ ت ﻛﻤﺎ ﳚﺐ أن ﻳﻌﻴﺪ //
اﻟﺘﺎﺑﻊ ﺑﻌﺪ ﺳﻠﺴﻠﺔ ﺣﺮﻓﻴﺔ ﻗﺒﻞ ﺪﱘ اﻟﻐﺮض وﳜﺰن دﻳﻨﺎﻣﻴﻜﻴﺎً ﻟﻸﺧﺬ ﺑﻌﲔ اﻻﻋﺘﺒﺎر //
اﳌﺆﺷﺮات ﻏﲑ اﳌﻌﺮف //
;return firstName
}
)(char *Employee::getLastName
{
وﻇﻴﻔﺔ اﻟﺘﺎﺑﻊ اﻟﺴﺎﺑﻖ //
;return lastName
}
٣٢-٣
Boss(char *first, char *last, float s= 0.0);
void setWeeklySalary(float);
virtual float earnings();
virtual void print();
private:
float weeklySalary;
};
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; اﻟﻌﻤﻠﻴﺔ "?" ﻫﻲ ﻋﻤﻠﻴﺔ اﺧﺘﺒﺎر ﻣﻨﻄﻘﻲ ﻣﺮﻛﺒﺔ وﺗﻌﲏ اﻟﻌﺒﺎرة ١
٣٤-٣
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; }
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::setHours(float h)
{ hours = h >= 0 && h < 168 ? h : 0; }
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();
٣٦-٣
PieceWorker p("Bob", "Lewis", 2.5, 200);
ptr = &p;
ptr->print();
cout << " earned $" << ptr->earnings();
p.print();
cout << " earned $" << p.earnings();
٣٧-٣