අපට C ++ හි අථත්‍ය කාර්යයන් අවශ්‍ය වන්නේ ඇයි?


1334

මම C ++ ඉගෙන ගන්නා අතර මම අතථ්‍ය ක්‍රියාකාරකම් වලට පිවිසෙමි.

මා කියවා ඇති දෙයින් (පොතේ සහ මාර්ගගතව), අතථ්‍ය ශ්‍රිත යනු ව්‍යුත්පන්න පංති වලදී ඔබට අභිබවා යා හැකි මූලික පන්තියේ කාර්යයන් වේ.

නමුත් මීට පෙර පොතේ, මූලික උරුමය ගැන ඉගෙන ගන්නා විට, ව්‍යුත්පන්න පංතිවල මූලික කාර්යයන් භාවිතා නොකර අභිබවා යාමට මට හැකි විය virtual.

ඉතින් මට මෙහි නැති වී ඇත්තේ කුමක්ද? අථත්ය කාර්යයන් සඳහා තවත් බොහෝ දේ ඇති බව මම දනිමි, එය වැදගත් බව පෙනේ, එබැවින් එය හරියටම කුමක්ද යන්න පිළිබඳව පැහැදිලි වීමට මට අවශ්යය. මට මාර්ගගතව answer ජු පිළිතුරක් සොයාගත නොහැක.


4
අථත්ය කාර්යයන්හි විශාලතම වාසිය මෙය විය හැකිය - අලුතින් ලබාගත් පන්ති නවීකරණයකින් තොරව පැරණි කේතය සමඟ ස්වයංක්රීයව ක්රියා කරන ආකාරයට ඔබේ කේතය සැකසීමේ හැකියාව!
user3530616

tbh, වර්චුවල් ශ්‍රිතයන් OOP හි ප්‍රධාන ලක්ෂණයකි. මම හිතන්නේ, එය අථත්‍ය නොවන ක්‍රම වන්නේ වස්තු පැස්කල් සහ සී ++ විශේෂිත කිරීම, අනවශ්‍ය විශාල විචල්‍යතාවන් ප්‍රශස්තිකරණය කිරීම සහ POD- අනුකූල පන්ති වලට ඉඩ දීම ය. බොහෝ OOP භාෂා බලාපොරොත්තු වන්නේ සෑම ක්‍රමයක්ම අභිබවා යා හැකි බවයි.
ස්විෆ්ට් - සිකුරාදා පයි

මෙය හොඳ ප්‍රශ්නයකි. ඇත්ත වශයෙන්ම C ++ හි ඇති මෙම අථත්ය දේ ජාවා හෝ PHP වැනි වෙනත් භාෂාවලින් වියුක්ත වේ. C ++ හි ඔබ සමහර දුර්ලභ අවස්ථාවන් සඳහා තව ටිකක් පාලනය කරයි (බහු උරුමය ගැන හෝ DDOD හි විශේෂ අවස්ථාව ගැන සැලකිලිමත් වන්න ). නමුත් මෙම ප්‍රශ්නය stackoverflow.com හි පළ කරන්නේ ඇයි?
එඩ්ගර් ඇලෝරෝ

මම හිතන්නේ ඔබ කලින් බන්ධනය-ප්‍රමාද බන්ධනය සහ VTABLE දෙස බැලුවහොත් එය වඩාත් සාධාරණ හා අර්ථවත් වනු ඇත. එබැවින් මෙහි හොඳ පැහැදිලි කිරීමක් ඇත ( learncpp.com/cpp-tutorial/125-the-virtual-table ).
ceyun

35 user3530616, ඔව් මම "ඔබගේ පැරණි කේතය සමඟ සහ ඔබේ පැරණි ද්විමය (සම්පාදිත කේතය) සමඟ එකතු කරමි. මෙය අතිශයින්ම බලවත් ය, කෙසේ වෙතත් යමෙක් මෙම නම්යශීලීභාවය සඳහා විශාල මිලක් ගෙවන අතර එය බොහෝ විට අනවශ්‍යය. youtube.com/ watch? v = bIhUE5uUFOA . ඔබට නැවත සම්පාදනය කළ හැකි නම් සහ ස්ථාවර ද්විමය මත යැපීමට හෝ ධාවන කාල සම්බන්ධතා අවශ්‍ය නොවන්නේ නම්, තර්ක කිරීමට පහසු වඩා හොඳ විකල්ප තිබේ. ප්‍රමාද වූ බන්ධනය වෙනත් අවස්ථාවලදී සැකිලි සමඟ කළ හැකි අතර එය වඩාත් බලවත් ය නමුත් වෙනත් සංවේදීතාවන්හි (ගණිතමය හෝ අගය-අර්ථකථන තර්කනය)
alfC

Answers:


2760

මෙන්න මම තේරුම් ගත්තේ කෙසේද virtualකාර්යයන් පමණක් නොව ඒවා අවශ්‍ය වන්නේ ඇයි:

ඔබට මෙම පන්ති දෙක ඇති බව කියමු:

class Animal
{
    public:
        void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

ඔබේ ප්‍රධාන කාර්යයේදී:

Animal *animal = new Animal;
Cat *cat = new Cat;

animal->eat(); // Outputs: "I'm eating generic food."
cat->eat();    // Outputs: "I'm eating a rat."

මෙච්චර හොඳයි නේද? සතුන් සාමාන්‍ය ආහාර අනුභව කරයි, බළලුන් මීයන් අනුභව කරති virtual.

දැන් එය ටිකක් වෙනස් කරමු, එවිට eat()එය අතරමැදි ශ්‍රිතයක් ලෙස හැඳින්වේ (මෙම උදාහරණය සඳහා සුළු කාර්යයක්):

// This can go at the top of the main.cpp file
void func(Animal *xyz) { xyz->eat(); }

දැන් අපගේ ප්‍රධාන කාර්යය වන්නේ:

Animal *animal = new Animal;
Cat *cat = new Cat;

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating generic food."

අහ් ... අපි පූසෙක් පසු කළා func(), නමුත් එය මීයන් කන්නේ නැහැ. ඔබ වැඩිපුර යුතු func()එය ගනී නිසා Cat*? ඔබට සත්වයින්ගෙන් තවත් සතුන් ලබා ගැනීමට සිදුවුවහොත් ඒ සියල්ලටම ඔවුන්ගේම දෑ අවශ්‍ය func()වේ.

විසඳුම බවට පත් කිරීම eat()දක්වා Animalඅතථ්ය කාර්යය පන්ති:

class Animal
{
    public:
        virtual void eat() { std::cout << "I'm eating generic food."; }
};

class Cat : public Animal
{
    public:
        void eat() { std::cout << "I'm eating a rat."; }
};

ප්රධාන:

func(animal); // Outputs: "I'm eating generic food."
func(cat);    // Outputs: "I'm eating a rat."

සිදු විය.


172
ඉතින් මම මෙය නිවැරදිව වටහා ගන්නේ නම්, අථත්‍යය උප පංති ක්‍රමය හැඳින්වීමට ඉඩ දෙයි, වස්තුව එහි සුපිරි පන්තිය ලෙස සලකනු ලැබුවද?
කෙනී වර්ඩන්

152
"ෆන්ක්" නම් අතරමැදි ශ්‍රිතයක උදාහරණය හරහා ප්‍රමාද බන්ධනය පැහැදිලි කිරීම වෙනුවට, මෙහි වඩාත් සරල නිරූපණයකි - සත්ව * සත්ව = නව සත්ව; // බළලා * බළලා = නව පූසා; සත්ව * බළලා = නව බළලා; සත්ව-> කන්න (); // ප්‍රතිදානයන්: "මම සාමාන්‍ය ආහාර අනුභව කරමි." cat-> කන්න (); // ප්‍රතිදානයන්: "මම සාමාන්‍ය ආහාර අනුභව කරමි." ඔබ උප පංති වස්තුව (බළලා) පවරා දුන්නද, ආයාචනා කරන ක්‍රමය පදනම් වී ඇත්තේ දර්ශක වර්ගය (සත්ව) මතය. ඔබට "අතථ්‍ය" අවශ්‍ය වන්නේ මේ නිසා ය.
rexbelia

40
C ++ හි මෙම පෙරනිමි හැසිරීම සොයාගත් එකම පුද්ගලයා මමද? "අතථ්‍ය" නොමැතිව කේතය ක්‍රියාත්මක වනු ඇතැයි මම අපේක්ෂා කරමි.
ඩේවිඩ් 天宇 වොන්

23
Av ඩේවිඩ් 天宇 වොං මම සිතන්නේ virtualස්ථිතික එදිරිව ගතික බන්ධන කිහිපයක් හඳුන්වා දෙන අතර ඔව් ඔබ ජාවා වැනි භාෂාවලින් පැමිණෙන්නේ නම් එය අමුතු දෙයක්.
පීටර්චෝලා

33
පළමුවෙන්ම, අතථ්‍ය ඇමතුම් සාමාන්‍ය ක්‍රියාකාරී ඇමතුම් වලට වඩා බෙහෙවින් මිල අධිකය. C ++ දර්ශනය පෙරනිමියෙන් වේගවත් බැවින් පෙරනිමියෙන් අථත්‍ය ඇමතුම් විශාල සංඛ්‍යාවක් නැත. දෙවන හේතුව නම්, ඔබ පුස්තකාලයකින් පන්තියක් උරුම කර ගන්නේ නම් අතථ්‍ය ඇමතුම් ඔබේ කේත බිඳීමට හේතු විය හැකි අතර එය මූලික පන්තියේ හැසිරීම වෙනස් නොකර පොදු හෝ පෞද්ගලික ක්‍රමයක් (අභ්‍යන්තරව අථත්‍ය ක්‍රමයක් ලෙස හඳුන්වන) අභ්‍යන්තරව ක්‍රියාත්මක කිරීම වෙනස් කරයි.
saolof

679

"අතථ්‍ය" නොමැතිව ඔබට "මුල් බැඳීම" ලැබේ. ඔබ භාවිතා කරන දර්ශකයේ වර්ගය මත පදනම්ව සම්පාදනය කරන වේලාවේදී කුමන ක්‍රමය ක්‍රියාත්මක කරන්නේද යන්න තීරණය වේ.

"අතථ්‍ය" සමඟ ඔබට "ප්‍රමාද බන්ධනය" ලැබේ. භාවිතා කරන ක්‍රමවේදය ක්‍රියාත්මක කිරීම ක්‍රියාත්මක වන වේලාවේදී තීරණය කරනු ලබන්නේ යොමු කරන ලද වස්තුවේ වර්ගය මත පදනම්වය - එය මුලින් ඉදිකරන ලද්දේ කුමක් ද යන්නයි. මෙය අනිවාර්යයෙන්ම එම වස්තුව වෙත යොමු වන දර්ශකයේ වර්ගය මත පදනම්ව ඔබ සිතන දේ නොවේ.

class Base
{
  public:
            void Method1 ()  {  std::cout << "Base::Method1" << std::endl;  }
    virtual void Method2 ()  {  std::cout << "Base::Method2" << std::endl;  }
};

class Derived : public Base
{
  public:
    void Method1 ()  {  std::cout << "Derived::Method1" << std::endl;  }
    void Method2 ()  {  std::cout << "Derived::Method2" << std::endl;  }
};

Base* obj = new Derived ();
  //  Note - constructed as Derived, but pointer stored as Base*

obj->Method1 ();  //  Prints "Base::Method1"
obj->Method2 ();  //  Prints "Derived::Method2"

සංස්කරණය කරන්න - මෙම ප්‍රශ්නය බලන්න .

එසේම - මෙම නිබන්ධනය C ++ හි මුල් හා ප්‍රමාද බන්ධන ආවරණය කරයි.


11
විශිෂ්, යි, ඉක්මණින් හා වඩා හොඳ උදාහරණ භාවිතයෙන් ගෙදර එයි. කෙසේ වෙතත් මෙය සරල ය, ප්‍රශ්න කරන්නා සැබවින්ම parashift.com/c++-faq-lite/virtual-functions.html පිටුව කියවිය යුතුය . මෙම ත්‍රෙඩ් එකෙන් සම්බන්ධ කර ඇති SO ලිපිවල වෙනත් පුද්ගලයින් දැනටමත් මෙම සම්පත වෙත යොමු කර ඇත, නමුත් මෙය නැවත සඳහන් කිරීම වටී යැයි මම විශ්වාස කරමි.
සොනී

37
මුල් හා ප්‍රමාද බන්ධන යනු c ++ ප්‍රජාව තුළ විශේෂයෙන් භාවිතා වන වචනදැයි මම නොදනිමි , නමුත් නිවැරදි යෙදුම් ස්ථිතික (සම්පාදක වේලාවේ) සහ ගතික (ධාවන වේලාවේ ) බන්ධන වේ.
මයික්

31
ikemike - "ප්‍රමාද බන්ධනය" යන පදය අවම වශයෙන් 1960 දශකය දක්වා දිව යයි, එහිදී එය ACM හි සන්නිවේදනයන්හි සොයාගත හැකිය. " . සෑම සංකල්පයක් සඳහාම නිවැරදි වචනයක් තිබේ නම් එය හොඳ නොවේද? අවාසනාවට, එය එසේ නොවේ. "මුල් බන්ධනය" සහ "ප්‍රමාද බන්ධනය" යන වචන C ++ ට පෙර සහ වස්තු-නැඹුරු වැඩසටහන්කරණයට පෙරාතුව ඇති අතර ඔබ භාවිතා කරන යෙදුම් මෙන්ම නිවැරදි වේ.
ස්ටීව් 314

4
JBJovke - මෙම පිළිතුර C ++ 11 ප්‍රකාශයට පත් කිරීමට පෙර ලියා ඇත. එසේ වුවත්, මම කිසිදු ප්රශ්න සමග (C ++ 14 පෙරනිමියෙන් භාවිතා කරමින්) සහ ගල්ෆ් 6.3.0 දී, එය සම්පාදනය - පැහැදිලිවම දී විචල්ය ප්රකාශ සහ ඇමතුම් ඔතන mainපොයින්ටර්-කිරීමට ව්යුත්පන්න උත්සවය ආදිය නිසැකයෙන්ම පහිටුම් දක්වනය-කිරීමට පදනම උපද (වඩා විශේෂිත වූ ව්‍යංගයෙන් වඩාත් සාමාන්‍යයට විහිදේ). වීසා බලපත්‍රයක් ලෙස ඔබට පැහැදිලි කාස්ට් එකක් අවශ්‍ය වේ, සාමාන්‍යයෙන් a dynamic_cast. වෙනත් ඕනෑම දෙයක් - නිර්වචනය නොකළ හැසිරීමට බෙහෙවින් නැඹුරු බැවින් ඔබ කරන්නේ කුමක්දැයි දැන ගැනීමට වග බලා ගන්න. මගේ දැනුමට අනුව, C ++ 98 ට පෙර සිට මෙය වෙනස් වී නැත.
ස්ටීව් 314

11
අද වන විට C ++ සම්පාදකයින්ට බොහෝ විට ප්‍රමාද වී බන්ධනය වීමට ප්‍රශස්තිකරණය කළ හැකි බව සලකන්න - බන්ධනය කුමක් වේද යන්න පිළිබඳව ඔවුන්ට නිශ්චිත විය හැකි විට. මෙය "අථත්‍යකරණය" ලෙසද හැඳින්වේ.
einpoklum

84

එය නිරූපණය කිරීම සඳහා ඔබට අවම වශයෙන් 1 මට්ටමේ උරුමයක් සහ අවතක්සේරු කිරීමක් අවශ්‍ය වේ. මෙන්න ඉතා සරල උදාහරණයක්:

class Animal
{        
    public: 
      // turn the following virtual modifier on/off to see what happens
      //virtual   
      std::string Says() { return "?"; }  
};

class Dog: public Animal
{
    public: std::string Says() { return "Woof"; }
};

void test()
{
    Dog* d = new Dog();
    Animal* a = d;       // refer to Dog instance with Animal pointer

    std::cout << d->Says();   // always Woof
    std::cout << a->Says();   // Woof or ?, depends on virtual
}

40
ඔබගේ උදාහරණයෙන් කියැවෙන්නේ ආපසු ලබා දුන් නූල රඳා පවතින්නේ ශ්‍රිතය අථත්‍යද යන්න මතය, නමුත් එය අථත්‍යයට අනුරූප වන සහ අථත්‍ය නොවන දේට අනුරූප වන ප්‍රති result ලය නොකියයි. මීට අමතරව, ඔබ ආපසු ලබා දෙන නූල භාවිතා නොකරන බැවින් එය ටිකක් අවුල් සහගතය.
රොස්

8
අතථ්‍ය මූල පදය සමඟ: වෝෆ් . අතථ්‍ය මූල පදය නොමැතිව : ? .
හේෂාම් එරකි

VersHeshamEraqi අතථ්‍ය නොමැතිව එය කල්තියා බැඳී ඇති අතර එය "?" of base class
අහමඩ්

46

ඔබ වෙනුවෙන්, අථත්ය ක්රම අවශ්ය ආරක්ෂිත downcasting , සරල හා ක්රිඩයා .

අතථ්‍ය ක්‍රම කරන්නේ එයයි: පෙනෙන ආකාරයට සරල හා සංක්ෂිප්ත කේතයක් සහිතව ඒවා ආරක්ෂිතව පහත් කොට, ඔබට වෙනත් ආකාරයකින් තිබිය හැකි වඩාත් සංකීර්ණ හා වාචික කේතයේ අනාරක්ෂිත අත්පොත වළක්වා ගනී.


අතථ්‍ය නොවන ක්‍රමය ⇒ ස්ථිතික බන්ධනය

පහත කේතය හිතාමතාම “වැරදියි”. එය valueක්‍රමවේදය ලෙස ප්‍රකාශ නොකරන virtualඅතර එම නිසා අනපේක්ෂිත “වැරදි” ප්‍රති result ලයක් ලබා දෙයි, එනම් 0:

#include <iostream>
using namespace std;

class Expression
{
public:
    auto value() const
        -> double
    { return 0.0; }         // This should never be invoked, really.
};

class Number
    : public Expression
{
private:
    double  number_;

public:
    auto value() const
        -> double
    { return number_; }     // This is OK.

    Number( double const number )
        : Expression()
        , number_( number )
    {}
};

class Sum
    : public Expression
{
private:
    Expression const*   a_;
    Expression const*   b_;

public:
    auto value() const
        -> double
    { return a_->value() + b_->value(); }       // Uhm, bad! Very bad!

    Sum( Expression const* const a, Expression const* const b )
        : Expression()
        , a_( a )
        , b_( b )
    {}
};

auto main() -> int
{
    Number const    a( 3.14 );
    Number const    b( 2.72 );
    Number const    c( 1.0 );

    Sum const       sum_ab( &a, &b );
    Sum const       sum( &sum_ab, &c );

    cout << sum.value() << endl;
}

“නරක” ලෙස අදහස් දක්වා ඇති රේඛාවේ Expression::valueක්‍රමය හැඳින්වෙන්නේ සංඛ්‍යාත්මකව දන්නා වර්ගය (සම්පාදක වේලාවේ දන්නා වර්ගය) වන Expressionඅතර valueක්‍රමය අථත්‍ය නොවන බැවිනි.


අතථ්‍ය ක්‍රමය ⇒ ගතික බන්ධනය.

සංඛ්‍යානමය valueවශයෙන් virtualදන්නා ආකාරයේ ලෙස Expressionප්‍රකාශ කිරීමෙන් එක් එක් ඇමතුම මෙය සත්‍ය වර්ගයේ වස්තුව කුමක්දැයි පරීක්ෂා කරන valueඅතර එම ගතික වර්ගය සඳහා අදාළ ක්‍රියාත්මක කිරීම අමතන්න :

#include <iostream>
using namespace std;

class Expression
{
public:
    virtual
    auto value() const -> double
        = 0;
};

class Number
    : public Expression
{
private:
    double  number_;

public:
    auto value() const -> double
        override
    { return number_; }

    Number( double const number )
        : Expression()
        , number_( number )
    {}
};

class Sum
    : public Expression
{
private:
    Expression const*   a_;
    Expression const*   b_;

public:
    auto value() const -> double
        override
    { return a_->value() + b_->value(); }    // Dynamic binding, OK!

    Sum( Expression const* const a, Expression const* const b )
        : Expression()
        , a_( a )
        , b_( b )
    {}
};

auto main() -> int
{
    Number const    a( 3.14 );
    Number const    b( 2.72 );
    Number const    c( 1.0 );

    Sum const       sum_ab( &a, &b );
    Sum const       sum( &sum_ab, &c );

    cout << sum.value() << endl;
}

6.86අථත්ය ක්රමය පාහේ හැඳින්වෙන බැවින් මෙහි ප්රතිදානය එය විය යුතුය . මෙය ඇමතුම්වල ගතික බන්ධනය ලෙසද හැඳින්වේ . කුඩා පරීක්‍ෂණයක් සිදු කරනු ලැබේ, සත්‍ය ගතික වර්ගයේ වස්තුව සොයා ගැනීම සහ එම ගතික වර්ගය සඳහා අදාළ ක්‍රමවේදය ක්‍රියාත්මක කිරීම හැඳින්වේ.

අදාළ ක්‍රියාත්මක කිරීම වඩාත් නිශ්චිත (වඩාත්ම ව්‍යුත්පන්න) පන්තියේ එකකි.

මෙහි ව්‍යුත්පන්න පංතිවල ක්‍රම ක්‍රියාත්මක කිරීම සලකුණු කර නැති virtualනමුත් ඒ වෙනුවට සලකුණු කර ඇති බව සලකන්න override. ඒවා සලකුණු කළ හැකි virtualනමුත් ඒවා ස්වයංක්‍රීයව අථත්‍යය. මෙම overrideතිබේ නම් එම මූල පදය වගකීම නොවන සමහර පදනම පන්තියේ එවැනි අතථ්ය ක්රමය, ඔබ (යෝග්ය වන) දෝෂයක් කරන්නම්.


අතථ්‍ය ක්‍රම නොමැතිව මෙය කිරීමේ කැත

virtualකිසිවෙකු නොමැතිව ගතික බන්ධනයේ සමහරක් එය කරන්න . සාමාන්‍යයෙන් අනාරක්ෂිත අත්පොත පහත් කිරීම, සංකීර්ණත්වය සහ වාචිකත්වය ඇතුළත් වන්නේ මෙයයි.

තනි ශ්‍රිතයක් සඳහා, මෙහි දී මෙන්, ශ්‍රිත දර්ශකයක් වස්තුව තුළ ගබඩා කර එම ශ්‍රිත දර්ශකය හරහා ඇමතීමට ප්‍රමාණවත් වේ, නමුත් එසේ වුවද එයට අනාරක්ෂිත පසුබෑම, සංකීර්ණත්වය සහ වාචිකත්වය ඇතුළත් වේ:

#include <iostream>
using namespace std;

class Expression
{
protected:
    typedef auto Value_func( Expression const* ) -> double;

    Value_func* value_func_;

public:
    auto value() const
        -> double
    { return value_func_( this ); }

    Expression(): value_func_( nullptr ) {}     // Like a pure virtual.
};

class Number
    : public Expression
{
private:
    double  number_;

    static
    auto specific_value_func( Expression const* expr )
        -> double
    { return static_cast<Number const*>( expr )->number_; }

public:
    Number( double const number )
        : Expression()
        , number_( number )
    { value_func_ = &Number::specific_value_func; }
};

class Sum
    : public Expression
{
private:
    Expression const*   a_;
    Expression const*   b_;

    static
    auto specific_value_func( Expression const* expr )
        -> double
    {
        auto const p_self  = static_cast<Sum const*>( expr );
        return p_self->a_->value() + p_self->b_->value();
    }

public:
    Sum( Expression const* const a, Expression const* const b )
        : Expression()
        , a_( a )
        , b_( b )
    { value_func_ = &Sum::specific_value_func; }
};


auto main() -> int
{
    Number const    a( 3.14 );
    Number const    b( 2.72 );
    Number const    c( 1.0 );

    Sum const       sum_ab( &a, &b );
    Sum const       sum( &sum_ab, &c );

    cout << sum.value() << endl;
}

මෙය දෙස බැලීමේ එක් ධනාත්මක ක්‍රමයක් නම්, ඉහත සඳහන් කළ පරිදි අනාරක්ෂිත ලෙස පහත් කොට සැලකීම, සංකීර්ණත්වය සහ වාචික භාවය ඔබට හමු වුවහොත් බොහෝ විට අථත්‍ය ක්‍රමයක් හෝ ක්‍රමවේදයක් සැබවින්ම උපකාරී වේ.


41

ධාවන බහුඅවයවිකතාවයට සහය දැක්වීම සඳහා අතථ්‍ය කාර්යයන් භාවිතා කරයි .

එනම්, අථත්ය මූලපදය සම්පාදකයාට පවසන්නේ සම්පාදක වේලාවේදී (ක්‍රියාකාරී බන්ධනය) තීරණයක් නොගන්නා ලෙසයි, ඒ වෙනුවට එය ධාවන කාලය සඳහා කල් දමන්න .

  • virtualඑහි මූලික පංති ප්‍රකාශනයේ මූලික පදයට පෙර ඔබට ශ්‍රිතයක් අථත්‍යයක් කළ හැකිය . උදාහරණයක් වශයෙන්,

     class Base
     {
        virtual void func();
     }
  • කරන විට මූලික පන්තියේ අතථ්ය සාමාජික ශ්රිතය ඇති මූලික පන්තියේ සිට අනුන හැකි බව කිසිදු පන්ති පරතරයන්, විවේකය සමග කාර්යය හරියටම එම මූලාකෘති එනම් එකම ක්රියාකාරිත්වය නොව එම ශ්රිතයේ එම අතුරුමුහුණත ප්රතිනිර්වචනයක් කළ හැක.

     class Derive : public Base
     {
        void func();
     }
  • මූලික පංති වස්තුවක් මෙන්ම ව්‍යුත්පන්න පංති වස්තුවක් වෙත යොමු කිරීම සඳහා මූලික පන්ති දර්ශකයක් භාවිතා කළ හැකිය.

  • මූලික පංති දර්ශකයක් භාවිතා කරමින් අථත්‍ය ශ්‍රිතය කැඳවූ විට, සම්පාදකයා ක්‍රියාත්මක වන වේලාවේදී තීරණය කරන්නේ ශ්‍රිතයේ කුමන අනුවාදයද - එනම් මූලික පන්ති අනුවාදය හෝ අභිබවා ගිය ව්‍යුත්පන්න පන්ති අනුවාදය ලෙස හැඳින්විය යුතුය. මෙය Runtime Polymorphism ලෙස හැඳින්වේ .

34

මූලික පංතිය නම් Base, සහ ව්‍යුත්පන්න පංතියක් නම් Der, ඔබට Base *pඇත්ත වශයෙන්ම නිදසුනක් පෙන්වා දෙන දර්ශකයක් තිබිය හැකිය Der. ඔබ අමතන විට p->foo();, අථත්‍ය නොවේ නම්, fooඑහි අනුවාදය ක්‍රියාත්මක වන්නේ සත්‍ය වශයෙන්ම a වෙත යොමු වන කාරණය නොසලකා හරිමිනි . Foo නම් වේ , අථත්ය, වන "leafmost" අභිබවා ඉටු ගිණුමට උල්-කිරීමට අයිතමය සැබෑ පන්ති සම්පූර්ණයෙන්ම ගනිමින්. එබැවින් අථත්ය හා අථත්ය නොවන අතර වෙනස සැබවින්ම ඉතා වැදගත් ය: කලින් සඳහන් කළ පරිදි OO වැඩසටහන්කරණයේ මූලික සංකල්පය වන ධාවන කාල බහුඅවයවිකතාවයට ඉඩ දෙයි .BasepDerp->foo()foo


8
මම ඔබට පරස්පර විරෝධී වීමට අකමැතියි, නමුත් සම්පාදක-කාලීන බහුමාපකය තවමත් බහුමාපකය වේ. සාමාජික නොවන කාර්යයන් අධික ලෙස පැටවීම පවා බහුමාපකයේ ආකාරයකි - ඔබේ සබැඳියේ ඇති පාරිභාෂිතය භාවිතා කරමින් තාවකාලික බහුමාපකය. මෙහි වෙනස මුල් හා ප්‍රමාද බන්ධන අතර වේ.
ස්ටීව් 314

7
@ ස්ටීව් 314, ඔබ නිවැරදිව නිවැරදියි (සෙසු පදිකයෙකු ලෙස මම එය අනුමත කරමි ;-) - නැතිවූ නාම විශේෂණය එක් කිරීමට පිළිතුර සංස්කරණය කිරීම ;-).
ඇලෙක්ස් මාටෙලි

26

අතථ්‍ය ක්‍රියාකාරිත්වයේ අවශ්‍යතාවය පැහැදිලි කර ඇත [තේරුම් ගැනීමට පහසුය]

#include<iostream>

using namespace std;

class A{
public: 
        void show(){
        cout << " Hello from Class A";
    }
};

class B :public A{
public:
     void show(){
        cout << " Hello from Class B";
    }
};


int main(){

    A *a1 = new B; // Create a base class pointer and assign address of derived object.
    a1->show();

}

ප්‍රතිදානය වනුයේ:

Hello from Class A.

නමුත් අතථ්‍ය ක්‍රියාකාරිත්වය සමඟ:

#include<iostream>

using namespace std;

class A{
public:
    virtual void show(){
        cout << " Hello from Class A";
    }
};

class B :public A{
public:
    virtual void show(){
        cout << " Hello from Class B";
    }
};


int main(){

    A *a1 = new B;
    a1->show();

}

ප්‍රතිදානය වනුයේ:

Hello from Class B.

එබැවින් අථත්‍ය ක්‍රියාකාරිත්වය මඟින් ඔබට ධාවන කාල බහුමාපකය ලබා ගත හැකිය.


26

අථත්ය ශ්‍රිතයේ තවත් භාවිතයක් එක් කිරීමට මා කැමතිය, එය ඉහත සඳහන් කළ පිළිතුරු වලට සමාන සංකල්පයක් භාවිතා කළද එහි සඳහන් කිරීම වටී යැයි මම සිතමි.

VIRTUAL DESTRUCTOR

Base class destructor අතථ්‍ය ලෙස ප්‍රකාශ නොකර මෙම වැඩසටහන පහතින් සලකා බලන්න; කැට් සඳහා මතකය පිරිසිදු නොකෙරේ.

class Animal {
    public:
    ~Animal() {
        cout << "Deleting an Animal" << endl;
    }
};
class Cat:public Animal {
    public:
    ~Cat() {
        cout << "Deleting an Animal name Cat" << endl;
    }
};

int main() {
    Animal *a = new Cat();
    delete a;
    return 0;
}

ප්‍රතිදානය:

Deleting an Animal
class Animal {
    public:
    virtual ~Animal() {
        cout << "Deleting an Animal" << endl;
    }
};
class Cat:public Animal {
    public:
    ~Cat(){
        cout << "Deleting an Animal name Cat" << endl;
    }
};

int main() {
    Animal *a = new Cat();
    delete a;
    return 0;
}

ප්‍රතිදානය:

Deleting an Animal name Cat
Deleting an Animal

12
without declaring Base class destructor as virtual; memory for Cat may not be cleaned up.එය ඊට වඩා නරක ය. ව්‍යුත්පන්න වස්තුවක් මූලික දර්ශකය / යොමු කිරීම හරහා මකා දැමීම නිර්වචනය නොකළ හැසිරීමකි. ඉතින්, එය කිසියම් මතකයක් කාන්දු විය හැකි බව පමණක් නොවේ. යන්ත්රයකට කේතය: ඒ වෙනුවට, මෙම වැඩසටහන, සම්පාදකවරයා දෙයක් බවට පරිවර්තනය විය හැක එසේ රෝගාතුර-සෑදේ සිදු වැඩසටහනක් එවැනි සැලසුම් කර ඇත නම්, වැඩ දඩයකට හෝ කිසිවක් කර නැත, හෝ සිතාසි භූතයන් ඔබේ නාසයෙන්, හෝ ආදිය ඇයි කියලා ඒ සමහර පරිශීලකයා විසින් ව්‍යුත්පන්න නිදසුනක් පාදක යොමුවකින් මකා දැමිය හැකි ක්‍රමයක් නම් , පාදමෙහි අථත්‍ය විනාශකාරකයක් තිබිය යුතුය
underscore_d

23

අතිච්ඡාදනය සහ අධි බර පැටවීම අතර වෙනස හඳුනාගත යුතුය. virtualමූල පදය නොමැතිව ඔබ මූලික පන්තියේ ක්‍රමයක් පමණක් පටවනු ලැබේ. මෙයින් අදහස් කරන්නේ සැඟවීම හැර වෙන කිසිවක් නොවේ. අපි ඔබට මූලික පංතියක් Baseසහ ව්‍යුත්පන්න පංතියක් Specializedඇති බව කියමු void foo(). දැන් ඔබට Baseඋදාහරණයක් පෙන්වා දීමට දර්ශකයක් තිබේ Specialized. ඔබ foo()එය අමතන විට ඇතිවන වෙනස ඔබට නිරීක්ෂණය කළ හැකිය virtual: ක්‍රමය අථත්‍ය නම්, ක්‍රියාත්මක කිරීම Specializedභාවිතා කරනු ඇත, එය අස්ථානගත වී ඇත්නම්, වෙතින් අනුවාදය Baseතෝරා ගනු ලැබේ. මූලික පන්තියකින් කිසි විටෙකත් අධික ලෙස ක්‍රම පැටවීම සුදුසු නොවේ. අථත්ය නොවන ක්රමයක් සෑදීම එහි කර්තෘගේ උප ක්රමවල දිගුව අදහස් නොකරන බව ඔබට පැවසිය හැකිය.


3
virtualඔබ අධික ලෙස පැටවීමකින් තොරව . ඔබ සෙවනැල්ලයි . පදනම පන්ති නම් Bඑකක් හෝ ඊට වැඩි කාර්යයන් foo, සහ ව්යුත්පන්න පන්තිය Dනිර්වචනය fooනම, ඒ foo සම් සියලු දෙනා foo-s දී B. B::fooවිෂය පථ විභේදනය භාවිතා කරමින් ඒවා වෙත ළඟා වේ. අධි බර පැටවීම සඳහා B::fooකාර්යයන් ප්‍රවර්ධනය කිරීම Dසඳහා, ඔබ භාවිතා කළ using B::fooයුතුය.
Kaz

20

අපට C ++ හි අථත්‍ය ක්‍රම අවශ්‍ය වන්නේ ඇයි?

ඉක්මන් පිළිතුර:

  1. එය අපට වස්තු නැඹුරු වැඩසටහන්කරණය සඳහා අවශ්‍ය “අමුද්‍රව්‍ය” 1 ක් සපයයි .

Bjarne Stroustrup C ++ ක්‍රමලේඛනය: මූලධර්ම සහ පුහුණුව, (14.3):

අථත්ය ශ්‍රිතය මඟින් මූලික පන්තියක ශ්‍රිතයක් නිර්වචනය කිරීමේ හැකියාව ලබා දෙන අතර එකම නමේ ශ්‍රිතයක් ඇති අතර පරිශීලකයෙකු මූලික පන්තියේ ශ්‍රිතය අමතන විට ව්‍යුත්පන්න පන්තියක ටයිප් කරන්න. එය බොහෝ විට ධාවන කාල බහුමාපකය , ගතික යැවීම හෝ ධාවන කාල යැවීම ලෙස හැඳින්වේ.

  1. ඔබට අවශ්ය නම් එය වේගවත්ම වඩාත් කාර්යක්ෂම ක්රියාත්මක වන අථත්ය කාර්යය ඇමතුමක් 2 .

අතථ්‍ය ඇමතුමක් හැසිරවීමට යමෙකුට ව්‍යුත්පන්න වස්තුව 3 හා සම්බන්ධ දත්ත එකක් හෝ කිහිපයක් අවශ්‍ය වේ. සාමාන්‍යයෙන් සිදුකරන ආකාරය නම් ශ්‍රිත වගුවේ ලිපිනය එකතු කිරීමයි. මෙම වගුව සාමාන්‍යයෙන් අථත්‍ය වගුව හෝ අථත්‍ය ක්‍රියාකාරී වගුව ලෙස හඳුන්වන අතර එහි ලිපිනය බොහෝ විට අථත්‍ය දර්ශකය ලෙස හැඳින්වේ . සෑම අථත්‍ය ශ්‍රිතයක්ම අථත්‍ය වගුවේ තව් ලබා ගනී. අමතන්නාගේ වස්තුව (ව්‍යුත්පන්න) වර්ගය මත පදනම්ව, අථත්‍ය ශ්‍රිතය, අනෙක් අතට, අදාළ අභිබවා යයි.


1. වස්තු-නැඹුරු වැඩසටහන්කරණයේ වඩාත් පොදු අර්ථ දැක්වීම වන්නේ උරුමය, ධාවන කාල බහුමාපකය සහ සංසරණය භාවිතා කිරීමයි .

2. ක්‍රියාකාරීත්වය වේගවත් කිරීමට හෝ වෙනත් භාෂා විශේෂාංග භාවිතයෙන් අඩු මතකයක් භාවිතා කර ධාවන වේලාවේ විකල්ප අතර තෝරා ගැනීමට ඔබට නොහැකිය. Bjarne Stroustrup C ++ ක්‍රමලේඛනය: මූලධර්ම සහ පුහුණුව (14.3.1) .

3. අථත්‍ය ශ්‍රිතය අඩංගු මූලික පංතිය ලෙස අප හඳුන්වන විට කුමන ශ්‍රිතය සැබවින්ම ආයාචනා කරනවාදැයි කීමට යමක්.


15

වඩා හොඳ කියවීමක් සඳහා සංවාදයක ස්වරූපයෙන් මගේ පිළිතුර:


අපට අතථ්‍ය කාර්යයන් අවශ්‍ය වන්නේ ඇයි?

බහුමාපකය නිසා.

බහුමාපකය යනු කුමක්ද?

පාදක දර්ශකය ව්‍යුත්පන්න වර්ගයේ වස්තූන් වෙත යොමු කළ හැකිය.

බහුමාපකයේ මෙම අර්ථ දැක්වීම අථත්ය කාර්යයන් සඳහා අවශ්ය වන්නේ කෙසේද?

හොඳයි, මුල් බැඳීම හරහා .

කලින් බැඳීම යනු කුමක්ද?

C ++ හි මුල් බැඳීම (සම්පාදක-කාල බන්ධනය) යන්නෙන් අදහස් කරන්නේ වැඩසටහන ක්‍රියාත්මක කිරීමට පෙර ශ්‍රිත ඇමතුමක් සවි කර ඇති බවයි.

නිසා...?

එබැවින් ඔබ ශ්‍රිතයක පරාමිතිය ලෙස පාදක වර්ගයක් භාවිතා කරන්නේ නම්, සම්පාදකයා හඳුනා ගන්නේ මූලික අතුරුමුහුණත පමණක් වන අතර, ඔබ එම ශ්‍රිතය ව්‍යුත්පන්න පංතිවල තර්ක සමඟ අමතන්නේ නම්, එය කපා දමනු ලැබේ, එය ඔබට සිදුවීමට අවශ්‍ය දේ නොවේ.

එය අපට සිදුවීමට අවශ්‍ය දේ නොවේ නම්, මෙය අවසර දෙන්නේ ඇයි?

අපට බහුමාපකය අවශ්‍ය නිසා!

එවිට බහුමාපකයේ වාසිය කුමක්ද?

ඔබට එක් ශ්‍රිතයක පරාමිතිය ලෙස මූලික වර්ගයේ දර්ශකයක් භාවිතා කළ හැකි අතර, පසුව ඔබේ වැඩසටහනේ ක්‍රියාත්මක වන වේලාවේදී, ඔබට කිසිදු ව්‍යුත්පන්න වර්ග අතුරුමුහුණතක් (උදා: ඔවුන්ගේ සාමාජික ක්‍රියාකාරකම්) කිසිදු ගැටළුවක් නොමැතිව ප්‍රවේශ විය හැකිය. පාදක දර්ශකය.

අථත්ය කාර්යයන් සඳහා හොඳ කුමක්දැයි මම තවමත් නොදනිමි ...! මෙය මගේ පළමු ප්‍රශ්නයයි!

හොඳයි, මෙයට හේතුව ඔබ ඉක්මනින් ඔබේ ප්‍රශ්නය ඇසූ බැවිනි!

අපට අතථ්‍ය කාර්යයන් අවශ්‍ය වන්නේ ඇයි?

වස්තුවක ව්‍යුත්පන්න පංතියක ලිපිනය සහිත පාදක දර්ශකයක් සහිත ශ්‍රිතයක් ඔබ හැඳින්වූ බව උපකල්පනය කරන්න. අප ඉහත කතා කළ පරිදි, ධාවන කාලය තුළ, මෙම දර්ශකය අවලංගු වේ, මෙතෙක් එය ඉතා හොඳය, කෙසේ වෙතත්, “අපේ ව්‍යුත්පන්න පන්තියේ සිට” ක්‍රමවේදයක් (== සාමාජික ශ්‍රිතයක්) ක්‍රියාත්මක කිරීමට අපි බලාපොරොත්තු වෙමු! කෙසේ වෙතත්, එකම ක්‍රමයක් (එකම ශීර්ෂයක් ඇති) දැනටමත් මූලික පන්තියේ අර්ථ දක්වා ඇත, එබැවින් ඔබේ ක්‍රමය අනෙක් ක්‍රමය තෝරා ගැනීමට කරදර විය යුත්තේ ඇයි? වෙනත් වචන වලින් කිවහොත්, සාමාන්‍යයෙන් පෙර සිදු වූ දේ අප දුටු දෙයින් ඔබ මෙම තත්වය ඉවත් කරන්නේ කෙසේද?

කෙටි පිළිතුර “පාදමේ අතථ්‍ය සාමාජික ශ්‍රිතයක්” වන අතර මඳක් දිගු පිළිතුර නම්, “මෙම පියවරේදී, වැඩසටහන මූලික පන්තියේ අථත්‍ය ශ්‍රිතයක් දුටුවහොත්, ඔබ භාවිතා කිරීමට උත්සාහ කරන බව එය දනී (අවබෝධ කර ගනී) බහුමාපකය "සහ ඒ අනුව ව්‍යුත්පන්න පංතිවලට ( v-table භාවිතා කිරීම, ප්‍රමාද බන්ධන ආකාරයක් භාවිතා කිරීම) එකම ශීර්ෂයක් සහිත වෙනත් ක්‍රමයක් සොයා ගැනීමට , නමුත් අනපේක්ෂිත ලෙස වෙනස් ක්‍රියාත්මක කිරීමක් සොයා ගැනීමට.

වෙනස් ක්‍රියාත්මක කිරීමක් ඇයි?

ඔයා දණ ගහන්න! හොඳ පොතක් කියවන්න !

හරි, රැඳී සිටින්න රැඳී සිටින්න, ඔහුට / ඇයට සරලවම ව්‍යුත්පන්න ආකාරයේ දර්ශක භාවිතා කළ හැකි විට, මූලික දර්ශක භාවිතා කිරීමට යමෙක් කරදර වන්නේ ඇයි? ඔබ විනිශ්චයකරු වන්න, මේ සියලු හිසරදය වටී ද? මෙම කොටස් දෙක දෙස බලන්න:

// 1:

Parent* p1 = &boy;
p1 -> task();
Parent* p2 = &girl;
p2 -> task();

// 2:

Boy* p1 = &boy;
p1 -> task();
Girl* p2 = &girl;
p2 -> task();

හරි, 1 තවමත් 2 ට වඩා හොඳ යැයි මම සිතුවත් , ඔබට මේ ආකාරයට 1 ක් ලිවිය හැකිය:

// 1:

Parent* p1 = &boy;
p1 -> task();
p1 = &girl;
p1 -> task();

එපමණක් නොව, මෙය මා මෙතෙක් ඔබට පැහැදිලි කර ඇති සියලු දේවල ව්‍යාජ භාවිතයක් පමණක් බව ඔබ දැන සිටිය යුතුය. මේ වෙනුවට, උදාහරණයක් ලෙස ඔබේ වැඩසටහනේ එක් එක් ව්‍යුත්පන්න පංති වලින් ක්‍රම භාවිතා කළ ශ්‍රිතයක් ඇති බව උපකල්පනය කරන්න (getMonthBenefit ()):

double totalMonthBenefit = 0;    
std::vector<CentralShop*> mainShop = { &shop1, &shop2, &shop3, &shop4, &shop5, &shop6};
for(CentralShop* x : mainShop){
     totalMonthBenefit += x -> getMonthBenefit();
}

දැන්, හිසරදයක් නොමැතිව මෙය නැවත ලිවීමට උත්සාහ කරන්න !

double totalMonthBenefit=0;
Shop1* branch1 = &shop1;
Shop2* branch2 = &shop2;
Shop3* branch3 = &shop3;
Shop4* branch4 = &shop4;
Shop5* branch5 = &shop5;
Shop6* branch6 = &shop6;
totalMonthBenefit += branch1 -> getMonthBenefit();
totalMonthBenefit += branch2 -> getMonthBenefit();
totalMonthBenefit += branch3 -> getMonthBenefit();
totalMonthBenefit += branch4 -> getMonthBenefit();
totalMonthBenefit += branch5 -> getMonthBenefit();
totalMonthBenefit += branch6 -> getMonthBenefit();

ඇත්ත වශයෙන්ම, මෙය තව දුරටත් උපක්‍රමශීලී උදාහරණයක් විය හැකිය!


2
තනි (සුපිරි) වස්තු වර්ගයක් භාවිතා කරමින් විවිධ වර්ගයේ (උප) වස්තූන් පුනරාවර්තනය කිරීමේ සංකල්පය ඉස්මතු කළ යුතුය, එය ඔබ දුන් හොඳ කරුණකි, ස්තූතියි
harshvchawla

14

ඔබ පදනම පන්තිය තුල කාර්යය ඇති වූ විට, ඔබ හැකි Redefineහෝ Overrideව්යුත්පන්න පන්තියේ එය.

ක්‍රමයක් නැවත අර්ථ දැක්වීම : ව්‍යුත්පන්න පන්තියේ මූලික පන්තියේ ක්‍රමය සඳහා නව ක්‍රියාත්මක කිරීමක් ලබා දී ඇත. පහසුකම් සපයන්නේ නැතDynamic binding .

ක්‍රමයක් ඉක්මවා යාම : ව්‍යුත්පන්න පන්තියේ මූලික පන්තියේRedefiningavirtual method. අතථ්‍ය ක්‍රමය ගතික බන්ධනයට පහසුකම් සපයයි .

එබැවින් ඔබ පැවසූ විට:

නමුත් මීට පෙර පොතේ, මූලික උරුමය ගැන ඉගෙන ගන්නා විට, 'අතථ්‍ය' භාවිතා නොකර ව්‍යුත්පන්න පංතිවල මූලික ක්‍රම ඉක්මවා යාමට මට හැකි විය.

මූලික පන්තියේ ක්‍රමය අථත්‍ය නොවන බැවින් ඔබ එය අභිබවා ගියේ නැත, ඒ වෙනුවට ඔබ එය නැවත අර්ථ දැක්වීය


11

යටින් පවතින යාන්ත්‍රණයන් ඔබ දන්නේ නම් එය උපකාරී වේ. සී ++ ක්‍රමලේඛකයින් විසින් භාවිතා කරන සමහර කේතීකරණ ක්‍රමවේදයන් සී ++ විධිමත් කරයි, “පංති” වෙනුවට “ආවරණ” භාවිතා කරයි - පොදු ශීර්ෂ කොටස් සහිත ව්‍යුහයන් විවිධ වර්ගවල වස්තූන් හැසිරවීමට භාවිතා කරන නමුත් සමහර පොදු දත්ත හෝ මෙහෙයුම් සමඟ. සාමාන්‍යයෙන් ආවරණයේ පාදක ව්‍යුහය (පොදු කොටස) ශ්‍රිත වගුවකට දර්ශකයක් ඇති අතර එමඟින් එක් එක් වස්තු වර්ගය සඳහා වෙනස් ක්‍රියාකාරකම් මාලාවක් දක්වයි. C ++ එකම දේ කරන නමුත් යාන්ත්‍රණයන් සඟවයි, එනම් C ++ ptr->func(...)ලෙස func අථත්‍ය වන C ++ (*ptr->func_table[func_num])(ptr,...), එහිදී ව්‍යුත්පන්න පංති අතර වෙනස් වන්නේ func_table අන්තර්ගතයයි. [අථත්‍ය නොවන ක්‍රමයක් ptr-> func () යනු mangled_func (ptr, ..) ලෙස පරිවර්තනය කරයි.]

එහි ප්‍රති shot ලය වනුයේ ව්‍යුත්පන්න පංතියක ක්‍රම ඇමතීම සඳහා ඔබට මූලික පන්තිය තේරුම් ගත යුතු වීමයි, එනම් දෛනික ක්‍රියාවක් A පන්තිය තේරුම් ගන්නේ නම්, ඔබට එය ව්‍යුත්පන්න පංතියේ B දර්ශකයක් පසු කළ හැකිය, එවිට අථත්‍ය ක්‍රම වනු ඇත ඔබ B හි ශ්‍රිත වගුව හරහා යන බැවින් A ට වඩා B හි.


9

අථත්ය යතුරුපදය සම්පාදකයාට පවසන්නේ එය කලින් බන්ධනය නොකළ යුතු බවයි. ඒ වෙනුවට, එය ප්‍රමාද බන්ධනය සිදු කිරීමට අවශ්‍ය සියලුම යාන්ත්‍රණ ස්වයංක්‍රීයව ස්ථාපනය කළ යුතුය. මෙය සිදු කිරීම සඳහා, සාමාන්‍ය සම්පාදක 1 මඟින් අථත්ය කාර්යයන් අඩංගු එක් එක් පන්තිය සඳහා තනි වගුවක් (VTABLE ලෙස හැඳින්වේ) නිර්මාණය කරයි. අතථ්‍ය ශ්‍රිත සහිත සෑම පන්තියකම, එය රහසින් vpointer (VPTR ලෙස කෙටියෙන්) නමින් දර්ශකයක් තබයි, එමඟින් එම වස්තුව සඳහා VTABLE වෙත යොමු වේ. ඔබ මූලික පන්තියේ දර්ශකයක් හරහා අතථ්‍ය ශ්‍රිත ඇමතුමක් ලබා ගන්නා විට, සම්පාදකයා නිහ ly ව VPTR ලබා ගැනීම සඳහා කේතය ඇතුල් කර VTABLE හි ක්‍රියාකාරී ලිපිනය සොයා බලයි, එමඟින් නිවැරදි ශ්‍රිතය කැඳවීම හා ප්‍රමාද බන්ධනය සිදුවීමට හේතු වේ.

මෙම සබැඳියේ වැඩි විස්තර http://cplusplusinterviews.blogspot.sg/2015/04/virtual-mechanism.html


7

මෙම අථත්ය ඉඟි පද හමුදා ක්රමය ක්රියාත්මක කිරීම නිර්වචනය කිරීමට බළාධාරීන්ට සම්පාදකවරයා වස්තුව ගේ පන්ති වඩා තුළ පෙන්නුම් කරන්නක් ගේ පන්ති.

Shape *shape = new Triangle(); 
cout << shape->getName();

ඉහත උදාහරණයේ දී, මූලික පන්තියේ හැඩයේ getName () අථත්‍ය ලෙස අර්ථ දක්වා නොමැති නම්, පෙරනිමියෙන් හැඩය :: getName ලෙස හැඳින්වේ. හැඩ පන්තියට වඩා ත්‍රිකෝණ පන්තියේ getName () ක්‍රියාත්මක කිරීම සෙවීමට මෙය සම්පාදකයාට බල කරයි.

මෙම අථත්ය වගුව සම්පාදකවරයා වන උප වර්ගිකරණයන් විවිධ අථත්ය-ක්රමය ක්රියාවට නැංවීම් මාර්ගයේ දිගටම කරන යාන්ත්රණයකි. මෙම ද ගතික සරයක කැඳවා, එතැන එය සමග ආශ්රිත සමහර පොදු කාර්ය.

අවසාන වශයෙන්, C ++ තුළ අතථ්‍ය පවා අවශ්‍ය වන්නේ ඇයි, එය ජාවා මෙන් පෙරනිමි හැසිරීමක් නොකරන්නේ ඇයි?

  1. C ++ පදනම් වී ඇත්තේ "Zero Overhead" සහ "ඔබ භාවිතා කරන දේ සඳහා ගෙවන්න" යන මූලධර්ම මත ය. එබැවින් ඔබට අවශ්‍ය නම් මිස එය ඔබ වෙනුවෙන් ගතික යැවීමක් කිරීමට උත්සාහ නොකරයි.
  2. අතුරු මුහුණතට වැඩි පාලනයක් සැපයීම. අථත්‍ය නොවන ශ්‍රිතයක් සෑදීමෙන්, අතුරු මුහුණත / වියුක්ත පන්තියට එහි සියලු ක්‍රියාත්මක කිරීම් වල හැසිරීම පාලනය කළ හැකිය.

4

අපට අතථ්‍ය කාර්යයන් අවශ්‍ය වන්නේ ඇයි?

අතථ්‍ය ශ්‍රිත මඟින් අනවශ්‍ය යතුරු ලියනය කිරීමේ ගැටළුව මඟහරවා ගත හැකි අතර, ව්‍යුත්පන්න පංතියේ විශේෂිත ශ්‍රිතය ඇමතීමට ව්‍යුත්පන්න පංති දර්ශකය භාවිතා කළ හැකි විට අපට අථත්‍ය කාර්යයන් අවශ්‍ය වන්නේ ඇයි දැයි අපගෙන් සමහරෙකුට විවාද කළ හැකිය! පිළිතුර - එය විශාල පද්ධතියේ උරුමය පිළිබඳ සමස්ත අදහසම අහෝසි කරයි. සංවර්ධනය, තනි දර්ශක පාදක පන්ති වස්තුවක් තිබීම බොහෝ සෙයින් අපේක්ෂා කරයි.

අතථ්‍ය ශ්‍රිතවල වැදගත්කම අවබෝධ කර ගැනීම සඳහා සරල වැඩසටහන් දෙකක් පහත සංසන්දනය කරමු:

අතථ්‍ය කාර්යයන් නොමැති වැඩසටහන:

#include <iostream>
using namespace std;

class father
{
    public: void get_age() {cout << "Fathers age is 50 years" << endl;}
};

class son: public father
{
    public : void get_age() { cout << "son`s age is 26 years" << endl;}
};

int main(){
    father *p_father = new father;
    son *p_son = new son;

    p_father->get_age();
    p_father = p_son;
    p_father->get_age();
    p_son->get_age();
    return 0;
}

නිමැවුම්:

Fathers age is 50 years
Fathers age is 50 years
son`s age is 26 years

අතථ්‍ය ශ්‍රිතය සහිත වැඩසටහන:

#include <iostream>
using namespace std;

class father
{
    public:
        virtual void get_age() {cout << "Fathers age is 50 years" << endl;}
};

class son: public father
{
    public : void get_age() { cout << "son`s age is 26 years" << endl;}
};

int main(){
    father *p_father = new father;
    son *p_son = new son;

    p_father->get_age();
    p_father = p_son;
    p_father->get_age();
    p_son->get_age();
    return 0;
}

නිමැවුම්:

Fathers age is 50 years
son`s age is 26 years
son`s age is 26 years

ප්‍රතිදානයන් දෙකම සමීපව විශ්ලේෂණය කිරීමෙන් කෙනෙකුට අථත්‍ය ශ්‍රිතවල වැදගත්කම වටහා ගත හැකිය.


4

OOP පිළිතුර: උප ප්‍රභේද බහුමාපකය

C ++, අතථ්ය ක්රම අවබෝධ කර ගැනීමට අවශ්ය බහුරූපතාෙව් වඩාත් නිශ්චිතව subtyping හෝ බහුරූපතාෙව් subtype ඔබ විකිපීඩියා, නිදහස් විශ්වකෝෂය වෙතින් අර්ථ දැක්වීම අදාළ කරගන්නවා නම්.

විකිපීඩියා, උප ප්‍රභේදය, 2019-01-09: ක්‍රමලේඛන භාෂා න්‍යායේ දී, උප වර්ගය (උප වර්ග බහුඅවයවිකතාව හෝ ඇතුළත් කිරීමේ බහුමාපකය) යනු එක්තරා ආකාරයක බහුමාපකයකි, එහි උප ප්‍රභේදයක් යනු දත්ත සමුදායක් වන අතර එය වෙනත් දත්ත වර්ගයකට (සුපර් ටයිප්) සම්බන්ධ වේ. ආදේශකතාවයේ, එනම් සුපර් ටයිප් හි මූලද්‍රව්‍යයන් මත ක්‍රියා කිරීම සඳහා ලියා ඇති වැඩසටහන් මූලද්‍රව්‍ය, සාමාන්‍යයෙන් සබ්ට්‍රවුටින් හෝ ශ්‍රිතයන් ද උප ප්‍රභේදයේ මූලද්‍රව්‍ය මත ක්‍රියාත්මක විය හැකිය.

සටහන: උප වර්ගය යනු මූලික පන්තිය වන අතර උප වර්ගය යන්නෙන් අදහස් කරන්නේ උරුම වූ පන්තියයි.

උප ප්‍රභේද බහුමාපකය පිළිබඳ වැඩිදුර කියවීම

තාක්ෂණික පිළිතුර: ගතික යැවීම

ඔබට මූලික පන්තියකට දර්ශකයක් තිබේ නම්, ක්‍රමයේ ඇමතුම (එය අතථ්‍ය ලෙස ප්‍රකාශයට පත් කෙරේ) නිර්මාණය කරන ලද වස්තුවේ සත්‍ය පන්තියේ ක්‍රමයට යවනු ලැබේ. මෙම ආකාරය වේ Subtype බහුරූපතා C ++ යනු අවබෝධ වේ.

වැඩිදුර කියවීම C ++ සහ ඩයිනමික් ඩිස්පැච් හි බහුමාපකය

ක්‍රියාත්මක කිරීමේ පිළිතුර: vtable ප්‍රවේශය නිර්මාණය කරයි

ක්‍රම පිළිබඳ එක් එක් විකරණකාරක “අතථ්‍ය” සඳහා, C ++ සම්පාදකයින් සාමාන්‍යයෙන් ක්‍රමය ප්‍රකාශයට පත් කරන පන්තියේ vtable තුළ ප්‍රවේශයක් සාදයි. පොදු C ++ සම්පාදකයා ගතික විසර්ජනය අවබෝධ කරගන්නේ එලෙස ය .

වැඩිදුර කියවීම vtables


උදාහරණ කේතය

#include <iostream>

using namespace std;

class Animal {
public:
    virtual void MakeTypicalNoise() = 0; // no implementation needed, for abstract classes
    virtual ~Animal(){};
};

class Cat : public Animal {
public:
    virtual void MakeTypicalNoise()
    {
        cout << "Meow!" << endl;
    }
};

class Dog : public Animal {
public:
    virtual void MakeTypicalNoise() { // needs to be virtual, if subtype polymorphism is also needed for Dogs
        cout << "Woof!" << endl;
    }
};

class Doberman : public Dog {
public:
    virtual void MakeTypicalNoise() {
        cout << "Woo, woo, woow!";
        cout << " ... ";
        Dog::MakeTypicalNoise();
    }
};

int main() {

    Animal* apObject[] = { new Cat(), new Dog(), new Doberman() };

    const   int cnAnimals = sizeof(apObject)/sizeof(Animal*);
    for ( int i = 0; i < cnAnimals; i++ ) {
        apObject[i]->MakeTypicalNoise();
    }
    for ( int i = 0; i < cnAnimals; i++ ) {
        delete apObject[i];
    }
    return 0;
}

නිදර්ශන කේතයේ ප්‍රතිදානය

Meow!
Woof!
Woo, woo, woow! ... Woof!

කේත උදාහරණයේ UML පන්ති රූප සටහන

කේත උදාහරණයේ UML පන්ති රූප සටහන


1
බහුඅවයවිකතාවයේ වඩාත්ම වැදගත් භාවිතය ඔබ පෙන්වන නිසා මගේ උඩු යටිකුරු කරන්න: අථත්ය සාමාජික කාර්යයන් සහිත මූලික පන්තියක් අතුරු මුහුණතක් හෝ වෙනත් වචනවලින් කිවහොත් ඒපීඅයි එකක් නියම කරයි. එවැනි පංති රාමු වැඩක් භාවිතා කරන කේතයට (මෙහි: ඔබේ ප්‍රධාන කාර්යය) එකතුවක ඇති සියලුම අයිතමවලට (මෙහි: ඔබේ අරාව) එක හා සමානව සැලකිය හැකි අතර අවශ්‍ය නොවන, අවශ්‍ය නොවන, සහ කුමන කොන්ක්‍රීට් ක්‍රියාවට නැංවිය යුතු දැයි බොහෝ විට දැනගත නොහැක. ධාවන වේලාවේදී, උදාහරණයක් ලෙස එය තවමත් නොපවතින බැවිනි. මෙය වස්තූන් සහ හසුරුවන්නන් අතර වියුක්ත සම්බන්ධතා ඇති කිරීමේ අත්තිවාරමකි.
පීටර් - මොනිකා නැවත

2

කාර්යක්ෂමතාව පිළිබඳ, අථත්ය කාර්යයන් මුල් බන්ධන කාර්යයන් මෙන් තරමක් අඩු කාර්යක්ෂම වේ.

"මෙම අථත්ය ඇමතුම් යාන්ත්රණය" සාමාන්ය ක්රියාකාරී ඇමතුම් "යාන්ත්රණය තරම්ම කාර්යක්ෂම කළ හැකිය (25% ක් ඇතුළත). එහි අවකාශය ඉහළින් අථත්ය කාර්යයන් සහිත පන්තියක එක් එක් වස්තුවෙහි එක් දර්ශකයක් වන අතර එවැනි එක් එක් පන්තිය සඳහා එක් vtbl" [ A C ++ හි සංචාරය Bjarne Stroustrup]


2
ප්‍රමාද බන්ධනය මඟින් ක්‍රියාකාරී ඇමතුම මන්දගාමී නොවේ, එය ක්‍රියාත්මක වන වේලාව තෙක් ඇමතුම් ශ්‍රිතය නොදන්නා බැවින් ක්‍රියාකාරී ඇමතුම හරහා ප්‍රශස්තිකරණය යෙදිය නොහැක. මෙය සෑම දෙයක්ම වෙනස් කළ හැකිය f.ex. අගය ප්‍රචාරණය මඟින් කේත විශාල ප්‍රමාණයක් ඉවත් කරන අවස්ථා වලදී ( if(param1>param2) return cst;සම්පාදකයාට සම්පූර්ණ ක්‍රියාකාරී ඇමතුම නියතයක් දක්වා අඩු කළ හැකි ස්ථානය ගැන සිතන්න ).
කුතුහලයෙන්

2

අතථ්‍ය ක්‍රම අතුරු මුහුණත් සැලසුම් කිරීමේදී භාවිතා වේ. උදාහරණයක් ලෙස වින්ඩෝස් හි පහත දැක්වෙන පරිදි IUnknown නමින් අතුරු මුහුණතක් ඇත:

interface IUnknown {
  virtual HRESULT QueryInterface (REFIID riid, void **ppvObject) = 0;
  virtual ULONG   AddRef () = 0;
  virtual ULONG   Release () = 0;
};

මෙම ක්‍රම ක්‍රියාත්මක කිරීම සඳහා අතුරු මුහුණතේ පරිශීලකයාට ඉතිරි වේ. IUnknown උරුම කර ගත යුතු ඇතැම් වස්තූන් නිර්මාණය කිරීම හා විනාශ කිරීම සඳහා ඒවා අත්‍යවශ්‍ය වේ. මෙම අවස්ථාවෙහිදී, ධාවන කාලය ක්‍රම තුන පිළිබඳව දැනුවත්ව සිටින අතර ඒවා කැඳවූ විට ඒවා ක්‍රියාත්මක කිරීමට අපේක්ෂා කරයි. එබැවින් එක් අතකින් ඔවුන් එම වස්තුව සහ එම වස්තුව භාවිතා කරන ඕනෑම දෙයක් අතර ගිවිසුමක් ලෙස ක්‍රියා කරයි.


the run-time is aware of the three methods and expects them to be implementedඒවා පිරිසිදු අතථ්‍ය බැවින්, නිදසුනක් නිර්මාණය කිරීමට ක්‍රමයක් නොමැත IUnknown, එබැවින් සියලු උප පංති හුදෙක් සම්පාදනය කිරීම සඳහා එවැනි සියලු ක්‍රම ක්‍රියාත්මක කළ යුතුය . ඒවා ක්‍රියාත්මක නොකිරීමේ අනතුරක් නොමැති අතර එය ක්‍රියාත්මක වන වේලාවේදී පමණක් සොයා ගැනීම (නමුත් පැහැදිලිවම කෙනෙකුට ඒවා වැරදි ලෙස ක්‍රියාත්මක කළ හැකිය , ඇත්ත වශයෙන්ම!). ඇවැත්නි, අද මම වින්ඩෝස් #defineසා මැක්‍රෝ යන වචනය ඉගෙන ගත්තේ interface, ඔවුන්ගේ පරිශීලකයින්ට (අ) Iනාමයේ උපසර්ගය බැලීමට හෝ (බී) එය අතුරු මුහුණතක් බැලීමට පන්තිය දෙස බැලීමට නොහැකි බැවිනි. අහ්
underscore_d

2

අථත්ය ක්රමය භාවිතා කරන්නේ ඇයිද යන්න පැහැදිලි කරන සම්පූර්ණ උදාහරණය මෙන්න.

#include <iostream>

using namespace std;

class Basic
{
    public:
    virtual void Test1()
    {
        cout << "Test1 from Basic." << endl;
    }
    virtual ~Basic(){};
};
class VariantA : public Basic
{
    public:
    void Test1()
    {
        cout << "Test1 from VariantA." << endl;
    }
};
class VariantB : public Basic
{
    public:
    void Test1()
    {
        cout << "Test1 from VariantB." << endl;
    }
};

int main()
{
    Basic *object;
    VariantA *vobjectA = new VariantA();
    VariantB *vobjectB = new VariantB();

    object=(Basic *) vobjectA;
    object->Test1();

    object=(Basic *) vobjectB;
    object->Test1();

    delete vobjectA;
    delete vobjectB;
    return 0;
}

1

ක්‍රමවේදයක් අථත්‍ය යැයි ප්‍රකාශයට පත් කළ පසු ඔබ 'අථත්‍ය' මූල පදය අභිබවා යන විට භාවිතා කිරීමට අවශ්‍ය නොවන බව මම සිතමි.

class Base { virtual void foo(); };

class Derived : Base 
{ 
  void foo(); // this is overriding Base::foo
};

ඔබ බේස්ගේ foo ප්‍රකාශයේ 'අතථ්‍ය' භාවිතා නොකරන්නේ නම්, ව්‍යුත්පන්න කළ foo එය සෙවනැල්ල වනු ඇත.


1

පළමු පිළිතුරු දෙක සඳහා C ++ කේතයේ ඒකාබද්ධ අනුවාදය මෙන්න.

#include        <iostream>
#include        <string>

using   namespace       std;

class   Animal
{
        public:
#ifdef  VIRTUAL
                virtual string  says()  {       return  "??";   }
#else
                string  says()  {       return  "??";   }
#endif
};

class   Dog:    public Animal
{
        public:
                string  says()  {       return  "woof"; }
};

string  func(Animal *a)
{
        return  a->says();
}

int     main()
{
        Animal  *a = new Animal();
        Dog     *d = new Dog();
        Animal  *ad = d;

        cout << "Animal a says\t\t" << a->says() << endl;
        cout << "Dog d says\t\t" << d->says() << endl;
        cout << "Animal dog ad says\t" << ad->says() << endl;

        cout << "func(a) :\t\t" <<      func(a) <<      endl;
        cout << "func(d) :\t\t" <<      func(d) <<      endl;
        cout << "func(ad):\t\t" <<      func(ad)<<      endl;
}

වෙනස් ප්‍රති results ල දෙකක්:

# අථත්ය අර්ථ දැක්වීමකින් තොරව , එය සම්පාදනය කරන වේලාවට බන්ධනය වේ. සත්ව * දැන්වීම සහ ෆන්ක් (සත්ව *) සියල්ලම සත්වයාගේ () ක්‍රමයට යොමු කරයි.

$ g++ virtual.cpp -o virtual
$ ./virtual 
Animal a says       ??
Dog d says      woof
Animal dog ad says  ??
func(a) :       ??
func(d) :       ??
func(ad):       ??

# අර්ථ දැක්වීමේ අථත්‍යය සමඟ , එය ධාවන වේලාවට බන්ධනය වේ. බල්ලා * d, සත්ව * දැන්වීම සහ ෆන්ක් (සත්ව *) ලක්ෂ්‍යය / බල්ලා ඔවුන්ගේ වස්තු වර්ගය බැවින් බල්ලාගේ () ක්‍රමය බලන්න. ]

$ g++ virtual.cpp -D VIRTUAL -o virtual
$ ./virtual 
Animal a says       ??
Dog d says      woof
Animal dog ad says  woof
func(a) :       ??
func(d) :       woof
func(ad):       woof

පයිතන් හි ඇති සියලුම පන්ති ගුණාංග (දත්ත සහ ක්‍රම) effectively ලදායී ලෙස අථත්‍ය බව සැලකිල්ලට ගැනීම සිත්ගන්නා කරුණකි . සියලුම වස්තූන් ධාවන වේලාවේදී ගතිකව නිර්මාණය වී ඇති බැවින්, වර්ගය ප්‍රකාශ කිරීම හෝ අථත්‍ය වචන අථත්‍යය අවශ්‍ය නොවේ. පහත දැක්වෙන්නේ පයිතන්ගේ කේත අනුවාදය:

class   Animal:
        def     says(self):
                return  "??"

class   Dog(Animal):
        def     says(self):
                return  "woof"

def     func(a):
        return  a.says()

if      __name__ == "__main__":

        a = Animal()
        d = Dog()
        ad = d  #       dynamic typing by assignment

        print("Animal a says\t\t{}".format(a.says()))
        print("Dog d says\t\t{}".format(d.says()))
        print("Animal dog ad says\t{}".format(ad.says()))

        print("func(a) :\t\t{}".format(func(a)))
        print("func(d) :\t\t{}".format(func(d)))
        print("func(ad):\t\t{}".format(func(ad)))

ප්‍රතිදානය:

Animal a says       ??
Dog d says      woof
Animal dog ad says  woof
func(a) :       ??
func(d) :       woof
func(ad):       woof

එය C ++ හි අථත්‍ය අර්ථ දැක්වීමට සමාන වේ. D සහ දැන්වීම එකම සුනඛ උදාහරණයට යොමු කරන / යොමු කරන වෙනස් දර්ශක විචල්‍යයන් දෙකක් බව සලකන්න . ප්‍රකාශනය (දැන්වීම)) සත්‍යය වන අතර ඒවායේ අගයන් එකම < ප්‍රධාන .ඩොග් වස්තුව 0xb79f72cc> වේ.


1

ක්‍රියාකාරී දර්ශකයන් ගැන ඔබ හුරුපුරුදු ද? අථත්ය කාර්යයන් සමාන අදහසක් වන අතර, ඔබට පහසුවෙන් දත්ත අථත්ය කාර්යයන් සමඟ සම්බන්ධ කළ හැකිය (පන්ති සාමාජිකයන් ලෙස). ක්‍රියාකාරී දර්ශකයන්ට දත්ත බැඳීම එතරම් පහසු නැත. මට නම් මෙය ප්‍රධාන සංකල්පීය වෙනසයි. මෙහි තවත් පිළිතුරු බොහොමයක් කියන්නේ "මොකද ... බහුමාපකය!"


1

අතථ්‍ය කාර්යයන් පිළිබඳ පැහැදිලි කිරීම්වල ඇති ගැටළුව නම්, එය ප්‍රායෝගිකව භාවිතා කරන්නේ කෙසේද යන්න සහ එය නඩත්තු කිරීමට උපකාරී වන්නේ කෙසේද යන්න ඔවුන් පැහැදිලි නොකිරීමයි. මම දැනටමත් අතථ්‍ය ශ්‍රිත නිබන්ධනයක් නිර්මාණය කර ඇති අතර එය දැනටමත් මිනිසුන්ට ඉතා ප්‍රයෝජනවත් වී ඇත. ප්ලස්, එය පදනම් වී ඇත්තේ යුධ පිටියේ පරිශ්‍රයක් මත වන අතර එය එය වඩාත් සිත්ගන්නාසුළු කරයි: https://nrecursions.blogspot.com/2015/06/so-why-do-we-need-virtual-functions.html .

මෙම යුධ බිමේ යෙදුම සලකා බලන්න:
රූප විස්තරය මෙහි ඇතුළත් කරන්න

#include "iostream"

//This class is created by Gun1's company
class Gun1 {public: void fire() {std::cout<<"gun1 firing now\n";}};
//This class is created by Gun2's company
class Gun2 {public: void shoot() {std::cout<<"gun2 shooting now\n";}};

//We create an abstract class to interface with WeaponController
class WeaponsInterface {
 public:
 virtual void shootTarget() = 0;
};

//A wrapper class to encapsulate Gun1's shooting function
class WeaponGun1 : public WeaponsInterface {
 private:
 Gun1* g;

 public:
 WeaponGun1(): g(new Gun1()) {}
 ~WeaponGun1() { delete g;}
 virtual void shootTarget() { g->fire(); }
};

//A wrapper class to encapsulate Gun2's shooting function
class WeaponGun2 : public WeaponsInterface {
 private:
 Gun2* g;

 public:
 WeaponGun2(): g(new Gun2()) {}
 ~WeaponGun2() { delete g;}
 virtual void shootTarget() { g->shoot(); }
};

class WeaponController {
 private:
 WeaponsInterface* w;
 WeaponGun1* g1;
 WeaponGun2* g2;
 public:
 WeaponController() {g1 = new WeaponGun1(); g2 = new WeaponGun2(); w = g1;}
 ~WeaponController() {delete g1; delete g2;}
 void shootTarget() { w->shootTarget();}
 void changeGunTo(int gunNumber) {//Virtual functions makes it easy to change guns dynamically
   switch(gunNumber) {
     case 1: w = g1; break;
     case 2: w = g2; break;
   }
 }
};


class BattlefieldSoftware {
 private:
 WeaponController* wc;
 public:
 BattlefieldSoftware() : wc(new WeaponController()) {}
 ~BattlefieldSoftware() { delete wc; }

 void shootTarget() { wc->shootTarget(); }
 void changeGunTo(int gunNumber) {wc->changeGunTo(gunNumber); }
};


int main() {
 BattlefieldSoftware* bf = new BattlefieldSoftware();
 bf->shootTarget();
 for(int i = 2; i > 0; i--) {
     bf->changeGunTo(i);
     bf->shootTarget();
 }
 delete bf;
}

එතීෙම් පංති නිර්මාණය කළේ ඇයිද යන්න පිළිබඳ සාරාංශය ලබා ගැනීම සඳහා බ්ලොග් අඩවියේ පළමුවෙන්ම ලිපිය කියවීමට මම ඔබව දිරිමත් කරමි.

රූපයේ පෙනෙන පරිදි, යුධ බිමේ මෘදුකාංගයකට සම්බන්ධ කළ හැකි විවිධ තුවක්කු / මිසයිල ඇති අතර, එම ආයුධවලට වෙඩි තැබීම හෝ නැවත ක්‍රමාංකනය කිරීම සඳහා විධානයන් නිකුත් කළ හැකිය. මෙහි ඇති අභියෝගය වන්නේ වෙනස් කිරීමට / ප්‍රතිස්ථාපනය කිරීමට හැකිවීමයි. තුවක්කු / මිසයිල නිල් යුධ බිමේ මෘදුකාංගයේ වෙනස්කම් නොකර, සහ ධාවන වේලාවේදී ආයුධ අතර මාරුවීමට, කේතයේ වෙනස්කම් නොකර නැවත සම්පාදනය කිරීමට.

ඉහත කේතය මඟින් ගැටළුව විසඳන ආකාරය සහ හොඳින් සැලසුම් කරන ලද එතීෙම් පංති සමඟ අථත්‍ය ක්‍රියාකාරිත්වයන් මඟින් කාර්යයන් සංයුක්ත කර ධාවන කාලය තුළ ව්‍යුත්පන්න පන්ති දර්ශක පැවරීමට උපකාරී වේ. පංතිය නිර්මාණය කිරීම WeaponGun1මඟින් ඔබ පන්තියට හැසිරවීම සම්පූර්ණයෙන්ම වෙන් කර ඇති බව සහතික කරයි Gun1. ඔබ කුමක් කළත් Gun1, ඔබට සිදු කළ යුතුව ඇත්තේ වෙනස්කම් පමණක් WeaponGun1වන අතර වෙනත් කිසිදු පන්තියකට බලපෑමක් සිදු නොවන බවට විශ්වාසයක් ඇත.

නිසා WeaponsInterfaceපන්ති, ඔබ දැන් එම පදනම පන්ති හේතුවම ඕනෑම ව්යුත්පන්න පන්තියේ ලබා දිය හැකි WeaponsInterfaceසහ ඔබ කතා කරන විට එය ක්රියාකාරීත්වයට, අතථ්ය නිසා WeaponsInterfaceගේ shootTarget, ව්යුත්පන්න පන්තිය shootTargetපළ කළහ යයි.

හොඳම කොටස නම්, ඔබට ධාවන කාලය තුළ ( w=g1සහ w=g2) තුවක්කු වෙනස් කළ හැකිය . අතථ්‍ය ශ්‍රිතවල ප්‍රධාන වාසිය මෙය වන අතර අපට අථත්‍ය ශ්‍රිත අවශ්‍ය වන්නේ මේ නිසාය.

එබැවින් තුවක්කු වෙනස් කිරීමේදී විවිධ ස්ථානවල කේත විවරණය කිරීමේ අවශ්‍යතාවයක් නොමැත. එය දැන් සරල හා පිරිසිදු ක්‍රියා පටිපාටියක් වන අතර තවත් තුවක්කු පන්ති එකතු කිරීමද පහසු වන්නේ අපට නව WeaponGun3හෝ WeaponGun4පන්තියක් නිර්මාණය කළ යුතු නිසා එය BattlefieldSoftwareකේතය හෝ WeaponGun1/ කේතය අවුල් නොකරන බවට අපට විශ්වාස විය හැකිය WeaponGun2.


නියමයි පැහැදිලි කිරීම! අපේ ගුරුවරු එය මේ ආකාරයෙන් ඉගැන්වූයේ නැත්තේ ඇයි? ධාවන කාලය තුළ වස්තූන් මාරු කිරීමේ වැදගත්කම මට අවසාන වශයෙන් තේරුම් ගැනීමට හැකි විය. මෙම පිළිතුර තවත් ඉහළ නැංවිය යුතුය.
ඇනොන්

0

"ධාවන කාල බහුමාපකය" සඳහා සහය දැක්වීම සඳහා අපට අථත්‍ය ක්‍රම අවශ්‍ය වේ. ඔබ ව්‍යුත්පන්න පංති වස්තුවක් දර්ශකයක් හෝ පාදක පන්තියට යොමු කිරීමක් භාවිතා කරන විට, ඔබට එම වස්තුව සඳහා අථත්‍ය ශ්‍රිතයක් අමතා ව්‍යුත්පන්න පන්තියේ අනුවාදය ක්‍රියාත්මක කළ හැකිය.


0

මෙහි මූලික කරුණ නම් අථත්ය කාර්යයන් ජීවිතය පහසු කිරීමයි. එම් පෙරීගේ සමහර අදහස් භාවිතා කර අපට අතථ්‍ය කාර්යයන් නොමැති නම් කුමක් සිදුවේද යන්න විස්තර කරමු. ඒ වෙනුවට භාවිතා කළ හැක්කේ සාමාජික-ක්‍රියාකාරී දර්ශක පමණි. අතථ්‍ය ශ්‍රිත නොමැතිව සාමාන්‍ය තක්සේරුව තුළ අපට ඇත්තේ:

 class base {
 public:
 void helloWorld() { std::cout << "Hello World!"; }
  };

 class derived: public base {
 public:
 void helloWorld() { std::cout << "Greetings World!"; }
 };

 int main () {
      base hwOne;
      derived hwTwo = new derived();
      base->helloWorld(); //prints "Hello World!"
      derived->helloWorld(); //prints "Hello World!"

හරි, ඒ නිසා අපි දන්නවා. දැන් අපි සාමාජික ක්‍රියාකාරී දර්ශකයන් සමඟ එය කිරීමට උත්සාහ කරමු:

 #include <iostream>
 using namespace std;

 class base {
 public:
 void helloWorld() { std::cout << "Hello World!"; }
 };

 class derived : public base {
 public:
 void displayHWDerived(void(derived::*hwbase)()) { (this->*hwbase)(); }
 void(derived::*hwBase)();
 void helloWorld() { std::cout << "Greetings World!"; }
 };

 int main()
 {
 base* b = new base(); //Create base object
 b->helloWorld(); // Hello World!
 void(derived::*hwBase)() = &derived::helloWorld; //create derived member 
 function pointer to base function
 derived* d = new derived(); //Create derived object. 
 d->displayHWDerived(hwBase); //Greetings World!

 char ch;
 cin >> ch;
 }

සාමාජික-ක්‍රියාකාරී දර්ශකයන් සමඟ අපට සමහර දේවල් කළ හැකි නමුත් ඒවා අථත්‍ය කාර්යයන් තරම් නම්යශීලී නොවේ. පංතියක සාමාජික ක්‍රියාකාරී දර්ශකයක් භාවිතා කිරීම උපක්‍රමශීලී ය; සාමාජික-ක්‍රියාකාරී දර්ශකය, අවම වශයෙන් මගේ ප්‍රායෝගිකව, සෑම විටම ප්‍රධාන ශ්‍රිතයෙන් හෝ ඉහත උදාහරණයේ දී මෙන් සාමාජික ශ්‍රිතයකින් ඇමතිය යුතුය.

අනෙක් අතට, අතථ්‍ය ශ්‍රිත, ඒවාට යම් ක්‍රියාකාරී ලක්ෂ්‍යයක් ඉහළින් තිබිය හැකි නමුත්, දේවල් නාටකාකාර ලෙස සරල කරන්න.

සංස්කරණය කරන්න: eddietree ට සමාන තවත් ක්‍රමයක් තිබේ: c ++ අතථ්‍ය ශ්‍රිතය එදිරිව සාමාජික ශ්‍රිත දර්ශකය (කාර්ය සාධනය සංසන්දනය) .

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.