Պոլիմորֆիզմը Java-ում. Դինամիկ և ստատիկ կապում: Օբյեկտների սկզբնավորում. Պոլիմորֆ մեթոդների վարքագիծը, երբ կանչվում են կոնստրուկտորներից: Ներածություն օբյեկտների ծրագրավորման Constructors. Պահպանված բառեր սուպեր և սա։ Մեկնարկային բլոկներ

Ստատիկ կապը որպես օպտիմալացում

Որոշ դեպքերում արդյունավետությունը հիմնական պահանջն է, և նույնիսկ վերը նշված փոքր ծախսերն անցանկալի են: Այս դեպքում կարելի է նշել, որ դրանք միշտ չէ, որ արդարացված են։ Զանգահարեք x.f (a, b, c...)դինամիկ կապի կարիք չունի հետևյալ դեպքերում.

1 զհամակարգում որևէ տեղ չի գերագնահատվում (ունի միայն մեկ հայտարարագիր);

2 xբազմիմորֆ չէ, այսինքն՝ այն որևէ կցորդի թիրախ չէ, որի աղբյուրը տարբեր տեսակի է:

Այս դեպքերից որևէ մեկում, որը հայտնաբերված է լավ կոմպիլյատորի կողմից, ստեղծվել է համար x.f (a, b, c...)կոդը կարող է լինել նույնը, ինչ ստեղծվել է C, Pascal, Ada կամ Fortran կոմպիլյատորների կողմից՝ զանգահարելու համար f (x, a, b, c...). Ոչ մի վերադիր ծախս չի պահանջվի:

ISE կոմպիլյատորը, որը վերջին դասախոսության մեջ նկարագրված միջավայրի մի մասն է, ներկայումս իրականացնում է օպտիմալացում (1), և նախատեսվում է ավելացնել (2) ((2)-ի վերլուծությունը, ըստ էության, տիպի վերլուծության հետևանք է. մեխանիզմներ, որոնք նկարագրված են մուտքագրման մասին դասախոսության մեջ):

Թեև (1)-ն ինքնին հետաքրքիր է, դրա անմիջական օգտակարությունը սահմանափակվում է դինամիկ կապի համեմատաբար ցածր գնով (տե՛ս վերևում գտնվող վիճակագրությունը): Դրանից իրական շահույթը անուղղակի է, քանի որ (1) թույլ է տալիս երրորդ օպտիմալացում.

4. Օգտագործեք հնարավորության դեպքում ընթացակարգի կոդի ավտոմատ փոխարինում.

Նման փոխարինումը նշանակում է ծրագրի մարմնի ընդլայնում կոչվող ընթացակարգի տեքստով այն վայրում, որտեղ այն կոչվում է: Օրինակ, ընթացակարգի համար

set_a (x:SOME_TYPE) է

x դարձրե՛ք a հատկանիշի նոր արժեքը:

կոմպիլյատորը կարող է գեներացնել կանչելու համար s.set_a (որոշ_արժեք)նույն կոդը, որը Pascal կոմպիլյատորը կստեղծի հանձնարարության համար s.a: = որոշ_արժեք(մեզ համար ընդունելի չէ, քանի որ այն խախտում է տեղեկատվության թաքցումը): Այս դեպքում բացարձակ ծախս չկա, քանի որ գեներացված կոդը չի պարունակում ընթացակարգի զանգ։

Կոդի փոխարինումը ավանդաբար դիտվում է որպես օպտիմալացում, որը պետք է հստակեցվի ծրագրավորողներ. Ադան ներառում է պրագմա (հրահանգ թարգմանչին) ներդիր, C և C++-ն առաջարկում են նմանատիպ մեխանիզմներ։ Բայց այս մոտեցումը բնորոշ սահմանափակումներ ունի. Թեև փոքր, ստատիկ ծրագրի համար իրավասու ծրագրավորողը կարող է որոշել, թե որ ընթացակարգերը կարող են փոխարինվել, մեծ զարգացող նախագծերի համար դա անհնար է: Այս դեպքում, փոխարինողներ որոշելու պատշաճ ալգորիթմ ունեցող կոմպիլյատորը շատ կգերազանցի ծրագրավորողների ենթադրությունները:

Յուրաքանչյուր զանգի համար, որի վրա կիրառվում է ավտոմատ ստատիկ կապակցում (1), OO կոմպիլյատորը կարող է որոշել՝ հիմնվելով ժամանակի հիշողության փոխզիջման վերլուծության վրա, արժե արդյոք ընթացակարգի ավտոմատ փոխարինումը (3): Սա ամենազարմանալի օպտիմիզացումներից մեկն է. պատճառներից մեկը, թե ինչու կարելի է ձեռքով արտադրված C կամ Fortran կոդի արդյունավետությունը հասնել, իսկ երբեմն, մեծ համակարգերում, գերազանցել:

Արդյունավետության ձեռքբերումներին, որոնք մեծանում են ծրագրի չափի և բարդության հետ, կոդերի ավտոմատ փոխարինումը ավելացնում է ավելի մեծ հուսալիության և ճկունության առավելությունները: Ինչպես նշվեց, ծածկագրի փոխարինումը իմաստային առումով ճիշտ է միայն այն ընթացակարգի համար, որը կարող է ստատիկորեն սահմանափակվել, ինչպես օրինակ (1) և (2) դեպքերում: Սա ոչ միայն ընդունելի է, այլև միանգամայն համահունչ է OO մեթոդին, մասնավորապես բաց-փակ սկզբունքին, եթե ծրագրավորողը, մեծ համակարգի զարգացման ճանապարհի կեսին, ավելացնում է որոշ բաղադրիչի վերացում, որն այդ պահին ուներ միայն մեկը: իրականացումը։ Եթե ​​ընթացակարգի կոդը տեղադրվում է ձեռքով, արդյունքը կարող է լինել սխալ իմաստաբանությամբ ծրագիր (քանի որ այս դեպքում անհրաժեշտ է դինամիկ կապ, իսկ կոդի տեղադրումը, իհարկե, նշանակում է ստատիկ կապ): Մշակողները պետք է կենտրոնանան ճիշտ ծրագրերի ստեղծման վրա, այլ ոչ թե հոգնեցուցիչ օպտիմալացումների վրա, որոնք, երբ ձեռքով արվում են, հանգեցնում են սխալների, բայց իրականում կարող են ավտոմատացվել:

Մի վերջին նշում արդյունավետության մասին. Օբյեկտ-կողմնորոշված ​​լեզուների հրապարակված վիճակագրությունը ցույց է տալիս, որ զանգերի 30%-ից մինչև 60%-ը իրականում օգտագործում է դինամիկ կապ: Սա կախված է նրանից, թե մշակողները որքան ինտենսիվ են օգտագործում մեթոդների հատուկ հատկություններ: ISE համակարգում այս հարաբերակցությունը մոտ է 60%-ի: Նոր նկարագրված օպտիմալացումներով դուք վճարում եք միայն դինամիկ կերպով կապելու միայն այն զանգերը, որոնք իրականում դրա կարիքն ունեն: Մնացած դինամիկ զանգերի համար վերին ծախսը ոչ միայն փոքր է (սահմանափակվում է հաստատունով), այլև տրամաբանորեն անհրաժեշտ է. շատ դեպքերում դինամիկ կապին համարժեք արդյունքի հասնելու համար դուք պետք է օգտագործեք պայմանական հայտարարություններ ( Եթե, ապա...կամ դեպք...), որը կարող է ավելի թանկ լինել, քան վերը նշված պարզ զանգվածի վրա հիմնված մեխանիզմը: Այսպիսով, զարմանալի չէ, որ լավ կոմպիլյատորով կազմված OO ծրագրերը կարող են մրցակցել ձեռքով գրված C կոդի հետ:

Boost your website գրքից հեղինակ Մացիևսկի Նիկոլայ

Ստատիկ արխիվացումը գործողության մեջ Կա մի տարբերակ, որով կարող եք անցնել ընդամենը մի քանի տող կոնֆիգուրացիայի ֆայլում (httpd.conf կամ .htaccess, նախընտրելի է առաջինը), եթե դուք ծախսում եք մի քանի րոպե և արխիվացնում եք բոլոր անհրաժեշտ ֆայլերը ինքներդ: Ենթադրենք՝ ունենք

The C++ Reference Guide գրքից հեղինակ Stroustrap Bjarne

Հ.3.3 Ծրագիր և կապակցում Ծրագիրը բաղկացած է մեկ կամ մի քանի ֆայլերից՝ կապված միմյանց հետ (§R.2): Ֆայլը բաղկացած է նկարագրությունների հաջորդականությունից: Ֆայլի շրջանակով անունը, որը բացահայտորեն հայտարարված է ստատիկ, տեղական է իր թարգմանչական միավորի համար և կարող է

C# 2005 ծրագրավորման լեզու և .NET 2.0 հարթակ գրքից: Տրոելսեն Էնդրյուի կողմից

Dynamic Binding Պարզ ասած, դինամիկ կապը կամ դինամիկ կապը մոտեցում է, որով դուք կարող եք ստեղծել տվյալ տիպի օրինակներ և զանգահարել դրանց անդամներին գործարկման ժամանակ և այն պայմաններում, երբ կոմպիլյացիայի ժամանակ դեռևս ոչինչ հայտնի չէ տիպի մասին:

ArchiCAD 11 գրքից հեղինակ Դնեպրով Ալեքսանդր Գ

Դիտումների միացում ArchiCAD-ի վիզուալիզացիայի գործիքների շարքում կա մեխանիզմ, որի նպատակն է միաժամանակ ցուցադրել երկու տարբեր տեսակետներ միասին: Ի՞նչ է, սրա անհրաժեշտությունը բավականին հաճախ է առաջանում։ Օրինակ՝ օբյեկտները տեսողականորեն կապելու համար

Օբյեկտ-կողմնորոշված ​​ծրագրավորման հիմունքներ գրքից Մեյեր Բերտրանի կողմից

Դինամիկ կապում Վերջին երկու մեխանիզմների՝ գերակայության և պոլիմորֆիզմի համադրությունը ուղղակիորեն ենթադրում է հետևյալ մեխանիզմը. Ենթադրենք կա զանգ, որի թիրախը պոլիմորֆ էակ է, օրինակ BOAT տիպի էությունը կանչում է հերթի բաղադրիչը:

System Programming in Windows Environment գրքից Հարթ Ջոնսոն Մ

ADT A դասի հետ կապելը, ինչպես բազմիցս ասվել է, ADT-ի իրականացում է՝ կա՛մ ձևականորեն, կա՛մ անուղղակիորեն նշված: Դասախոսության սկզբում նշվեց, որ հայտարարությունները կարելի է դիտարկել որպես դասի մեջ ներառելու իմաստային հատկությունները, որոնք գտնվում են.

TCP/IP Architecture, Protocols, Implementation (ներառյալ IP տարբերակ 6 և IP Security) գրքից կողմից Ֆեյթ Սիդնեյ Մ

Դինամիկ կապակցում Դինամիկ կապը կլրացնի գերակայությունը, պոլիմորֆիզմը և ստատիկ մուտքագրումը, ստեղծելով հիմնական քառաբանություն

VBA Dummies-ի համար գրքից Սթիվ Քամինգսի կողմից

Տարբեր անունով կոճակ. Երբ ստատիկ կապակցումը սխալ է Մինչ այժմ, այս դասախոսության մեջ ուրվագծված ժառանգության սկզբունքներից հիմնականը պետք է հստակ լինի. Դինամիկ կապի սկզբունքը Երբ ստատիկ կապի արդյունքը չի համապատասխանում արդյունքին:

UNIX օպերացիոն համակարգ գրքից հեղինակ Ռոբաչևսկի Անդրեյ Մ.

Մուտքագրում և կապում Թեև, որպես այս գրքի ընթերցող, դուք հավանաբար կկարողանաք տարբերել ստատիկ մուտքագրման և ստատիկ կապման միջև, կան մարդիկ, ովքեր չեն կարող դա անել: Սա կարող է մասամբ պայմանավորված լինել Smalltalk-ի ազդեցությամբ, որը պաշտպանում է դինամիկ մոտեցում երկու խնդիրների նկատմամբ:

Սկսնակների համար նախատեսված C++ գրքից Լիպման Սթենլիի կողմից

Անուղղակի կապակցում Անուղղակի կապը կամ բեռնվածության ժամանակի կապը կապող երկու տեխնիկաներից ավելի պարզն է: Microsoft C++-ի օգտագործման կարգը հետևյալն է. Նոր DLL-ի համար անհրաժեշտ բոլոր գործառույթները հավաքելուց հետո,

Linux Kernel Development գրքից Love Robert-ի կողմից

Բացահայտ կապակցում Բացահայտ կապակցումը կամ գործարկման ժամանակի կապակցումը պահանջում է, որ ծրագիրը տրամադրի հատուկ ցուցումներ DLL-ը բեռնելու կամ ազատելու մասին: Այնուհետև ծրագիրը ստանում է պահանջվողի հասցեն

Հեղինակի գրքից

11.9.3 Կապում DHCP սերվերը պահպանում է հաճախորդների և դրանց կազմաձևման պարամետրերի միջև քարտեզագրման աղյուսակը: Binding-ը բաղկացած է յուրաքանչյուր հաճախորդին IP հասցե և մի շարք կոնֆիգուրացիաներ հատկացնելուց

Հեղինակի գրքից

Ստատիկ վիճակ Փոփոխական հայտարարագրում Static բանալի բառը պետք է օգտագործվի, երբ ցանկանում եք, որ փոփոխականը մնա հիշողության մեջ, որպեսզի դրա արժեքը օգտագործվի նույնիսկ այն բանից հետո, երբ ընթացակարգն ավարտի իր աշխատանքը: Հետևյալ օրինակում փոփոխականը

Հեղինակի գրքից

Պարտադիր Նախքան հաճախորդը կարող է զանգահարել հեռակա ընթացակարգ, այն պետք է կապված լինի հեռավոր համակարգին, որն ունի անհրաժեշտ սերվեր: Այսպիսով, պարտադիր առաջադրանքը բաժանվում է երկու մասի. Պահանջվող սերվերով հեռակա հոսթորդ գտնելու՞մ եք: Գտնելով

Հեղինակի գրքից

9.1.7. Անվտանգ կապ A Ծանրաբեռնվածություն օգտագործելիս թվում է, որ ծրագիրը կարող է ունենալ նույնանուն մի քանի գործառույթ՝ պարամետրերի տարբեր ցուցակներով: Այնուամենայնիվ, բառային այս հարմարությունը գոյություն ունի միայն սկզբնաղբյուր տեքստի մակարդակում: Մեծամասնության մեջ

Հեղինակի գրքից

Ստատիկ հիշողության տեղաբաշխում կույտի վրա Օգտվողի տարածության մեջ հիշողության բաշխման շատ գործողություններ, մասնավորապես նախկինում քննարկված օրինակներից մի քանիսը, կարող են իրականացվել փաթեթի միջոցով, քանի որ հատկացված հիշողության շրջանի չափը հայտնի է priori: IN

տվյալները . Պոլիմորֆիզմի նպատակը, որը կիրառվում է օբյեկտի վրա հիմնված ծրագրավորման համար, մեկ անուն օգտագործելն է՝ դասի համար ընդհանուր գործողություններ սահմանելու համար։

Java-ում օբյեկտի փոփոխականները պոլիմորֆ են: Օրինակ:
դաս King (public static void main (String args) ( King king = new King() ; king = new AerysTargaryen() ; king = new RobertBaratheon() ;) դասակարգ Robert Baratheon ընդլայնում King () դաս AerysTargaryen extensions King ( )
King տիպի փոփոխականը կարող է վերաբերել կա՛մ King տիպի օբյեկտին, կա՛մ King-ի ցանկացած ենթադասի օբյեկտին:
Վերցնենք հետևյալ օրինակը.

class King (public void speech() ( System .out .println («Ես եմ Անդալների թագավորը») ;) public void speech (String մեջբերում) ( System .out .println («Իմաստունն ասաց.» + մեջբերում); «ԵՍ» ԱՆԴԱԼՆԵՐԻ ԹԱԳԱՎՈՐՆ ԵՄ!!!11») ; else System .out .println ("i"m... the king...") ;) ) class AerysTargaryen extensions King ( @Override public void speech() ( System .out .println ("Burn them all... " ) ;) @Override public void speech(String quotation) ( System .out .println (մեջբերում+ "... And now burn them all!") ;) ) class Kingdom (public static void main(String args) (King king) = new AerysTargaryen() ; king.speech («Homo homini lupus est») ;))
Ինչ է տեղի ունենում, երբ կոչվում է օբյեկտին պատկանող մեթոդթագավոր?

1. Կազմողը ստուգում է հայտարարված օբյեկտի տեսակը և մեթոդի անվանումը, համարակալում է բոլոր մեթոդները անունովելույթ AerusTargarien դասում և բոլոր հանրային մեթոդներըելույթ գերդասարաններում
AerusTargarien. Կազմողն այժմ գիտի հնարավոր թեկնածուներին մեթոդ կանչելիս:
2. Կոմպիլյատորը որոշում է մեթոդին փոխանցվող արգումենտների տեսակները: Եթե ​​գտնվի մեկ մեթոդ, որի ստորագրությունը համընկնում է փաստարկների հետ, զանգը կատարվում է:Այս գործընթացըking.speech («Homo homini lupus est») կոմպիլյատորը կընտրի մեթոդըխոսք (լարային մեջբերում), բայց չէ ելույթ ().

Եթե ​​կոմպիլյատորը գտնում է մի քանի մեթոդներհամապատասխան պարամետրերով (կամ ոչ մեկը), ցուցադրվում է սխալի հաղորդագրություն:



Այժմ կոմպիլյատորը գիտի կոչվող մեթոդի պարամետրերի անվանումը և տեսակները:
3. Այն դեպքում, երբ կոչված մեթոդն էմասնավոր, ստատիկ, եզրափակիչկամ կոնստրուկտոր, օգտագործվում է ստատիկ կապում ( վաղ կապում) Այլ դեպքերում, կոչվող մեթոդը որոշվում է օբյեկտի իրական տեսակով, որի միջոցով տեղի է ունենում զանգը: Նրանք. օգտագործվում է ծրագրի կատարման ընթացքում դինամիկ կապում (ուշ կապում).

4. Վիրտուալ մեքենան յուրաքանչյուր դասի համար նախապես ստեղծում է մեթոդի աղյուսակ, որը թվարկում է բոլոր մեթոդների ստորագրությունները և կանչվող իրական մեթոդները:
Դասի մեթոդների աղյուսակԹագավորկարծես այսպես.
  • ելույթ () - Թագավոր.ելույթ ()
  • խոսք (լարային մեջբերում) -Թագավոր.խոսք (լարային մեջբերում)
  • Թագավոր.խոսք (բուլյան բարձրաձայն խոսել)
Եվ դասի համարAerysTargaryen - այսպես.
  • ելույթ () - AerysTargaryen . ելույթ ()
  • խոսք (լարային մեջբերում) - AerysTargaryen. խոսք (լարային մեջբերում)
  • ելույթ (Բուլյան բարձրաձայն խոսել) -Թագավոր. խոսք (բուլյան բարձրաձայն խոսել)
Այս օրինակում Object-ից ժառանգված մեթոդներն անտեսվում են:
Զանգահարելիսթագավոր.ելույթ ():
  1. Որոշվում է փոփոխականի իրական տեսակըթագավոր . Այս դեպքում դա էAerysTargaryen.
  2. Վիրտուալ մեքենան որոշում է այն դասը, որին պատկանում է մեթոդըելույթ ()
  3. Մեթոդը կոչվում է.
Կապելով բոլոր մեթոդներըJavaիրականացվում է պոլիմորֆ՝ ուշ կապելու միջոցով։Դինամիկ կապը ունի մեկ կարևոր հատկություն՝ թույլ է տալիսփոփոխել ծրագրերը՝ առանց դրանց կոդերը վերակոմպիլյացիայի։ Ահա թե ինչ են անում ծրագրերըդինամիկ ընդարձակվող ( ընդարձակելի).
Ի՞նչ կլինի, եթե կոնստրուկտորում կանչեք կառուցված օբյեկտի դինամիկորեն կապված մեթոդը: Օրինակ:
class King ( King () ( System . out . println ( «Call King constructor» ), ելույթ () ; // AerysTargaryen-ում վերացված պոլիմորֆ մեթոդ) public void speech() ( System .out .println («Ես եմ «Անդալների թագավորը») ;) ) դաս AerysTargaryen extensions King ( private String զոհի անունը; AerysTargaryen () ( System .out .println ( «Կանչեք Աերիս Թարգարիեն կոնստրուկտորին») ; qurbanName = «Լյաննա Սթարք» ; ելույթ (); ) @Override public void speech() ( System .out .println ("Burn" + viktimaName + "!") ;) ) class Kingdom (public static void main(String args) (King king = new AerysTargaryen() ;)) Արդյունք:

Զանգահարեք Քինգ կոնստրուկտորին Այրել զրոյական! Զանգահարեք Aerys Targaryen-ի կոնստրուկտոր Բերն Լյաննա Սթարքին!
Բազային դասի կոնստրուկտորը միշտ կանչվում է ածանցյալ դասի կառուցման ժամանակ։ Կանչն ավտոմատ կերպով շարժվում է ժառանգական շղթայով, այնպես որ ժառանգական շղթայի բոլոր հիմնական դասերի կառուցողները ի վերջո կանչվեն:
Սա նշանակում է, որ կոնստրուկտորին կանչելիսնոր AerysTargaryen() կկոչվի.
  1. նոր օբյեկտ ()
  2. նոր թագավոր ()
  3. նոր AerysTargaryen ()
Ըստ սահմանման, դիզայների գործը առարկայի կյանք տալն է: Ցանկացած կոնստրուկտորի ներսում օբյեկտը կարող է միայն մասամբ ձևավորվել. հայտնի է միայն, որ բազային դասի օբյեկտները սկզբնավորվել են: Եթե ​​կոնստրուկտորը ևս մեկ քայլ է այս կոնստրուկտորի դասից ստացված դասի օբյեկտ կառուցելու ուղղությամբ, ապա «ստացված» մասերը դեռ չեն սկզբնավորվել ընթացիկ կոնստրուկտորի կանչի պահին:

Այնուամենայնիվ, դինամիկորեն կապված զանգը կարող է գնալ հիերարխիայի «արտաքին» մաս, այսինքն, ածանցյալ դասեր: Եթե ​​կոնստրուկտորում կանչում է ածանցյալ դասի մեթոդ, դա կարող է հանգեցնել չնախապատրաստված տվյալների մանիպուլյացիայի, ինչը մենք տեսնում ենք այս օրինակի ելքում:

Ծրագրի արդյունքը որոշվում է օբյեկտի սկզբնավորման ալգորիթմի կատարմամբ.

  1. Նոր օբյեկտի համար հատկացված հիշողությունը լցված է երկուական զրոներով։
  2. Բազային դասի կոնստրուկտորները կանչվում են ավելի վաղ նկարագրված հերթականությամբ: Այս պահին կոչվում է գերագնահատված մեթոդելույթ () (այո, նախքան դասի կոնստրուկտորին կանչելըAerysTargaryen), որտեղ պարզվում է, որ փոփոխականըզոհի անունը զրոյական է առաջին փուլի պատճառով։
  3. Դասի անդամի սկզբնավորիչները կանչվում են այն հաջորդականությամբ, որով դրանք սահմանված են:
  4. Ստացված դասի կոնստրուկտորի մարմինը կատարվում է:
Մասնավորապես, նման վարքագծային խնդիրների պատճառով արժե պահպանել կոնստրուկտորներ գրելու հետևյալ կանոնը.
- կոնստրուկտորում կատարեք միայն ամենաանհրաժեշտ և պարզ գործողությունները օբյեկտի սկզբնավորման համար
- հնարավորության դեպքում խուսափեք այնպիսի մեթոդներ կանչելուց, որոնք սահմանված չենմասնավոր կամ վերջնական (ինչը այս համատեքստում նույնն է):
Օգտագործված նյութեր.
  1. Էկել Բ.Մտածում Java-ում , 4-րդ հրատարակություն - Գլուխ 8
  2. Քեյ Ս. Հորսթման, Գարի Քորնել - Core Java 1 - Գլուխ 5
  3. Վիքիպեդիա

Սկսած PHP 5.3.0-ից, կար մի հատկություն, որը կոչվում է ուշ ստատիկ կապ, որը կարող է օգտագործվել ստատիկ ժառանգության համատեքստում կանչվող դասի հղում ստանալու համար:

Ավելի ճիշտ, ուշ ստատիկ կապումը պահպանում է վերջին «չփոխանցված զանգի» մեջ նշված դասի անվանումը։ Ստատիկ զանգերի դեպքում սա բացահայտորեն նշված դաս է (սովորաբար օպերատորի ձախ կողմում :: ); ոչ ստատիկ զանգերի դեպքում սա օբյեկտի դասն է: «Վերահղված զանգը» ստատիկ զանգ է, որը սկսվում է ինքնուրույն ::, ծնող::, ստատիկ ::կամ, եթե մենք բարձրացնենք դասի հիերարխիան, forward_static_call(). Գործառույթ get_called_class ()կարող է օգտագործվել կանչված դասի անունով տող ստանալու համար, և ստատիկ ::ներկայացնում է դրա շրջանակը.

«Ուշ ստատիկ կապ» անվանումն ինքնին արտացոլում է այս հատկանիշի ներքին իրականացումը: «Ուշ կապում»-ն արտացոլում է այն փաստը, որ կոչ է անում ստատիկ ::չի հաշվարկվի այն դասի համեմատ, որում սահմանված է կանչված մեթոդը, այլ կհաշվարկվի գործարկման ժամանակի տեղեկատվության հիման վրա: Այս հատկությունը կոչվում էր նաև «ստատիկ կապ», քանի որ այն կարող է օգտագործվել (բայց պարտադիր չէ) ստատիկ մեթոդներում։

Սահմանափակումներ ինքնուրույն ::

Օրինակ #1 Օգտագործում ինքնուրույն ::

Ա դաս (
արձագանք __ԴԱՍ__ ;
}
հանրային ստատիկ գործառույթ
փորձարկում()(
ինքնուրույն::who();
}
}

B դասը տարածվում է A (
հանրային ստատիկ ֆունկցիա who() (
արձագանք __ԴԱՍ__;
}
}

B::test();
?>

Օգտագործելով ուշ ստատիկ կապ

Հետագայում ստատիկ պարտադիր կապը փորձում է հաղթահարել այս սահմանափակումը՝ տրամադրելով հիմնաբառ, որը հղում է անում անմիջապես գործարկման ժամանակ կոչվող դասին: Պարզ ասած, բանալի բառ, որը թույլ կտա ձեզ կապել Բ-ից փորձարկում()նախորդ օրինակում։ Որոշվել է ոչ թե նոր բանալի բառ ներմուծել, այլ օգտագործել ստատիկ, որն արդեն վերապահված է։

Օրինակ #2 Հեշտ օգտագործման համար ստատիկ ::

Ա դաս (
հանրային ստատիկ ֆունկցիա who() (
արձագանք __ԴԱՍ__ ;
}
հանրային ստատիկ գործառույթ
փորձարկում()(
ստատիկ ::who(); // Այստեղ կիրառվում է ուշ ստատիկ կապը
}
}

B դասը տարածվում է A (
հանրային ստատիկ ֆունկցիա who() (
արձագանք __ԴԱՍ__;
}
}

B::test();
?>

Այս օրինակի գործարկման արդյունքը.

Մեկնաբանություն:

Ոչ ստատիկ համատեքստում կանչված դասը կլինի այն դասը, որին պատկանում է օբյեկտի օրինակը: Քանի որ $this->կփորձի զանգահարել մասնավոր մեթոդներ նույն շրջանակից՝ օգտագործելով ստատիկ ::կարող է տարբեր արդյունքներ տալ: Մեկ այլ տարբերություն այն է, որ ստատիկ ::կարող է վերաբերել միայն դասի ստատիկ դաշտերին:

Օրինակ #3 Օգտագործում ստատիկ ::ոչ ստատիկ համատեքստում

Ա դաս (
մասնավոր ֆունկցիա foo() (
echo «հաջողություն!\n» ;
}
հանրային ֆունկցիայի թեստ() (
$this -> foo();
ստատիկ ::foo();
}
}

B դասը տարածվում է A (
/* foo()-ը կպատճենվի B-ում, հետևաբար դրա շրջանակը դեռ A է,
և զանգը հաջող կլինի*/
}

C դասը տարածվում է A (
մասնավոր ֆունկցիա foo() (
/* բնօրինակ մեթոդը փոխարինվել է; նոր C մեթոդի շրջանակը */
}
}

$b = նոր B();
$b -> test();
$c = նոր C();
$c -> test(); //ճիշտ չէ
?>

Այս օրինակի գործարկման արդյունքը.

հաջողություն! հաջողություն! հաջողություն! Ճակատագրական սխալ. Կանչ դեպի մասնավոր մեթոդ C::foo() «A» համատեքստից 9-րդ տողում /tmp/test.php-ում:

Մեկնաբանություն:

Ուշ ստատիկ կապի լուծվող շրջանը կֆիքսվի ստատիկ կանչով, որը հաշվարկում է այն: Մյուս կողմից, ստատիկ զանգեր՝ օգտագործելով հրահանգներ, ինչպիսիք են ծնող::կամ ինքնուրույն ::վերահղման զանգի տեղեկատվությունը:

Օրինակ #4 Վերահղված և չվերահղված զանգեր

Պարտադիր- հատուկ գործառույթի կանչերի փոխարինում ծրագրային կոդերով. դասի մեթոդներ. Իմաստ ունի միայն ածանցյալ դասերի համար:

Սովորաբար կոմպիլյատորն ունի անհրաժեշտ տեղեկատվություն՝ որոշելու համար, թե որ ֆունկցիան է նկատի ունենում։ Օրինակ, եթե ծրագիրը հանդիպում է obj.f(-ին) կանչի, ապա կոմպիլյատորը եզակի կերպով ընտրում է f() ֆունկցիան՝ կախված նպատակակետի obj-ի տեսակից: Եթե ​​ծրագիրը օգտագործում է ցուցիչներ դասի:ptr->f(-ի) օրինակների համար, ապա ֆունկցիա - դաս մեթոդի ընտրությունը որոշվում է ցուցիչի տեսակով:

Եթե ​​ֆունկցիայի ընտրությունը կատարվում է կոմպիլյացիայի ժամանակ, ապա գործ ունենք ստատիկ կապ.

Այս դեպքում բազային դասի ցուցիչի համար կկանչվի ֆունկցիա՝ բազային դասի մեթոդ, նույնիսկ եթե բազային դասի ցուցիչին վերագրվի ստացված դասի օրինակի հասցեի արժեքը։

Եթե ​​ֆունկցիայի ընտրությունը կատարվում է ծրագրի կատարման փուլում, ապա գործ ունենք դինամիկ կապ.

Այս դեպքում, եթե ծրագրի կատարման ժամանակ բազային դասի ցուցիչին վերագրվի բազային դասի օրինակի հասցեն, կկանչվի բազային դասի մեթոդը. Եթե ​​բազային դասի ցուցիչին վերագրվում է ստացված դասի օրինակի հասցեն, ապա կկանչվի ստացված դասի մեթոդը:

Վիրտուալ գործառույթներ

Լռելյայնորեն, ստացված դասերը ստատիկորեն կապված են: Եթե ​​դինամիկ կապը պետք է օգտագործվի դասի որևէ մեթոդի համար, ապա այդպիսի մեթոդները պետք է հայտարարվեն Վիրտուալ .

Վիրտուալ գործառույթներ.

    ունենալ վիրտուալ բանալի բառը նախատիպի մեջ բազային դասում;

    Դասի պարտադիր անդամի գործառույթները.

    Բոլոր ածանցյալ դասերը պետք է ունենան նույն նախատիպը (ածանցյալ դասերում virtual բառը նշելը պարտադիր չէ):

Եթե ​​ստացված դասերում որևէ մեթոդ ունի նույն անվանումը, ինչ բազային դասում, բայց պարամետրերի այլ ցանկ, մենք գերբեռնված գործառույթներ ունենք:

Օրինակ՝ Point and Circle դասեր:

վիրտուալ void print();

դասի շրջանակը` հանրային կետ (

void print(); // դուք կարող եք վիրտուալ void print();

void Point::print()

կոուտ<< "Point (" << x << ", " << y << ")";

void Circle::print()

կոուտ<< "Circle with center in "; Point::print();

կոուտ<< "and radius " << rad;

Օգտագործումը:

Կետ p1 (3,5), p2 (1,1), * pPtr;

Շրջանակ c1 (1), c2 (p2, 1);

pPtr = pPtr->print(); // ստանալ՝ միավոր (3, 5)

pPtr = pPtr->print(); // ստանալ:

Շրջանակ՝ կենտրոնով (1, 1) կետում և 1 շառավղով

Դինամիկ կապման օրինակ՝ Ցուցակ

Դինամիկ կապի ամենատարածված օգտագործումը կոնտեյներների դասերն են, որոնք պարունակում են ցուցիչ դեպի բազային դաս; Նման բեռնարկղային դասերը կարող են ներառել տեղեկատվություն, որը վերաբերում է ինչպես բազային, այնպես էլ ածանցյալ դասերին:

Դիտարկենք մի օրինակ՝ ցուցակ, որը պարունակում է և՛ կետեր, և՛ շրջանակներ:

// կոնստրուկտոր

Նյութ():info(NULL), հաջորդ(NULL)()

Նյութ(կետ *p):info(p), հաջորդ(NULL)()

Ցուցակ():գլուխ(NULL)()

void insert(Point *p)(p->next = head; head = p;)

void List::print()

համար (հատ *cur = գլուխ; cur; cur = cur-> հաջորդ)(

cur->info->print();

կոուտ<< endl;

Օգտագործելով դասը.

Point *p = new Point(1,2);

mylist.insert(p);

p = նոր ցիկլ (1,2,1);

mylist.insert(p);

Շրջանակ՝ կենտրոնով (1, 2) կետում և 1 շառավղով

Գոյություն ունեն հսկայական և աճող համակարգեր, որտեղ ստատիկ հաղորդակցության ծայրահեղ մակարդակները կարող են հսկայական դրական ազդեցություն ունենալ հավելվածների և համակարգի աշխատանքի վրա:

Ես խոսում եմ այն ​​մասին, ինչը հաճախ կոչվում է «ներկառուցված համակարգեր», որոնցից շատերն այժմ ավելի ու ավելի են օգտագործում ընդհանուր նշանակության օպերացիոն համակարգեր, և այդ համակարգերն օգտագործվում են այն ամենի համար, ինչ կարելի է պատկերացնել:

Չափազանց տարածված օրինակ են սարքերը, որոնք օգտագործում են GNU/Linux համակարգեր՝ օգտագործելով Busybox: Ես դա արել եմ ծայրահեղության մեջ NetBSD-ի հետ՝ ստեղծելով bootable i386 (32-բիթանոց) համակարգի պատկեր, որը ներառում է և՛ միջուկը, և՛ դրա արմատային ֆայլային համակարգը, որը պարունակում է մեկ ստատիկորեն կապված (crunchgen-ի միջոցով) երկուական՝ կոշտ հղումներով բոլոր ծրագրերին: պարունակում է բոլորը(լավ վերջապես հաշվեք 274) (մեծ մասը՝ առանց գործիքների շղթայի) և դա 20-ից քիչ է մեգաբայթ (և, հավանաբար, շատ հարմարավետ է աշխատում 64 ՄԲ հիշողությամբ համակարգի վրա (նույնիսկ արմատային ֆայլային համակարգը չսեղմված է և ամբողջովին RAM-ում), թեև ես չկարողացա գտնել այդքան փոքր մեկը՝ փորձարկելու համար):

Նախորդ գրառումներում նշվում էր, որ ստատիկ կապակցված երկուականների գործարկման ժամանակն ավելի արագ է (և դա կարող է լինել շատ ավելի արագ), բայց դա նկարի միայն մի մասն է, հատկապես, երբ ամբողջ օբյեկտի կոդը միացված է նույն ֆայլին, և նույնիսկ ավելին, երբ օպերացիոն համակարգն աջակցում է փոխանակման հարցման կոդը անմիջապես գործարկվող ֆայլից: Այս իդեալական սցենարում ծրագրի գործարկման ժամանակները բառացիորեն աննշան են, քանի որ կոդի գրեթե բոլոր էջերն արդեն հիշողության մեջ են և կօգտագործվեն shell-ի կողմից (և կսկսվեն ցանկացած այլ ֆոնային գործընթացների կողմից, որոնք կարող են գործարկվել), նույնիսկ եթե պահանջվող ծրագիրը երբեք չի եղել: գործարկվել է բեռնումից ի վեր, քանի որ կարող է բեռնված լինել միայն մեկ էջ՝ ծրագրի գործարկման ժամանակի պահանջները բավարարելու համար:

Սակայն սա ամբողջ պատմությունը չէ։ Ես նաև սովորաբար կառուցում և օգտագործում եմ NetBSD օպերացիոն համակարգի տեղադրում իմ ամբողջական զարգացման համակարգերի համար՝ ստատիկ կերպով կապելով բոլոր երկուականները: Թեև սա պահանջում է սկավառակի հսկայական տարածություն (~6,6 ԳԲ ընդհանուր x86_64-ի համար՝ ամեն ինչով, ներառյալ գործիքաշարը և X11-ը ստատիկ կապակցված) (հատկապես, եթե դուք բոլոր ծրագրերի համար հասանելի եք վրիպազերծման նշանների աղյուսակները ~2 ավելի .5 ԳԲ-ի համար), արդյունքն ընդհանուր առմամբ դեռ ավելի արագ է, և որոշ առաջադրանքներ նույնիսկ ավելի քիչ հիշողություն են օգտագործում, քան սովորական դինամիկ կապակցված համակարգը, որը նախատեսված է գրադարանի կոդերի էջերը փոխանակելու համար: Սկավառակը էժան է (նույնիսկ արագ սկավառակ), և հաճախակի օգտագործվող ֆայլերը սկավառակի վրա պահելու համար հիշողությունը նույնպես համեմատաբար էժան է, բայց պրոցեսորի ցիկլերն իսկապես այդպես չեն, և ld.so-ի սկզբնական եկամուտը վճարելը յուրաքանչյուր գործընթացի համար, որը սկսվում է ամեն անգամ, կպահանջվի ժամեր: և CPU-ի ժամերի ցիկլեր այն առաջադրանքներից, որոնք պահանջում են բազմաթիվ պրոցեսներ գործարկելու համար, հատկապես, երբ նույն ծրագրերն օգտագործվում են նորից ու նորից, օրինակ՝ կոմպիլյատորները զարգացման համակարգի վրա: Ստատիկ փաթեթավորված ծրագրային ծրագրերը կարող են ժամերի ընթացքում կրճատել ամբողջ համակարգի համար բազմաֆունկցիոնալ ճարտարապետություն ստեղծելու համար անհրաժեշտ ժամանակը: Ես դեռ պետք է ստեղծեմ գործիքների շղթան իմ միակ crunchgen-ի երկուական տարբերակում, բայց ես կասկածում եմ, որ երբ դա անեմ, ավելի շատ ժամանակ կխնայվի պրոցեսորի քեշի շահույթի պատճառով: