CannibalSmith ([info]cannibalsmith) rakstīja [info]koderi kopienā,
@ 2006-12-30 23:22:00

Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Konstruktori, destruktori un inheritance iekš C++
Atgādiniet man, kā konstruktori un destruktori uzvedās apakšklasēs.

Ja man bāzes klasei ir konstruktors un apakšklasei arī, vai man apakšklases konstruktorā kā pirmā darbība ir jāizsauc bāzes klases konstruktors, vai arī tas notiek automātiski? Ja jāizsauc, tad kā to pareizi dara? Un kā viss tas pats notiek ar destruktoriem?

Ko izmaina konstruktoru un destruktoru redzamība (public, private, protected)?

Kas ir virtuālie destruktori (konstruktori?) ?


(Lasīt komentārus) - (Ierakstīt jaunu komentāru)


[info]bubu
2006-12-31 00:55 (saite)
Apakšklases konstruktors automātiski pats izsauks virsklases konstruktoru. Bet tas notiks tikai tad, ja virsklasei būs pieejams konstruktors bez argumentiem, vai ar argumentiem, kuriem ir visiem defaultās vērtības.

Virsklases konstrukoru izsauc šādi:
class ApakshKlase : public Virsklase
{
public:
  ApakshKlase(int x) : Virsklase(4.5f)
  {
    // ...
  }
  // ...
}


Desktori paši izsaucās, tb vispirms izpildās apakšklases destruktors, un pēc tam automātiski izsaucās virklases destruktors(-i).

Kontruktoru/destruktoru redzamība itekmē to vai lietotājs varēs pats uztaisīt šīs klases objektu vai nē. Kā arī vai varēs iznīcināt. Tb, ja tu uztaisīsi klases konstruktoru privātu - tu pats nevarēsi uzkonstruēt klases objektu. Ja uztaisīsi konstruktoru protected, tad varēsi uztaisīt tikai šīs klases apakšklašu objektus (protams, ja tiem konstruktors būs publisks).

Virtuāls destruktors vajadzīgs, lai tu droši varētu izdzēst (ar delete) pointeri, kas norāda uz virsklasi. Tb šāda situācija:
class Base
{
public: virtual ~Base() {}
};
class Derived : public Base
{
};
// ...
int main()
{
  Base* obj = new Derived()
  // ...
  delete obj;

}

novedīs pie atmiņas sačakarēšanas, ja tev destruktors nebūs virtuāls. Pie tam, tad netiks izsauks Derived klases destruktors (lai aizvērtu failus/atbrīvotu resursus un tml darbības). Jo ja tas nav virtuāls, tad C++ kompilētājs uzģenerēs kodu, kas atbrīvos atmiņu ko aizņem obj kā Base klases instance. Bet ja destruktors ir virtuāls, tad tiks korekti izsaukts Deriver destrukors.

Virtuālo konstruktoru C++ valodā nav. Tos emulē ar virtual Base* clone() const; veidīgām funkcijām.

Šo visu taču var izlasīt C++ standartā :)
Kā arī, ļoti ieteicami izlasāmajā, C++ FAQ Lite:
Constructors
When should my destructor be virtual?
What is a "virtual constructor"?

(Atbildēt uz šo) (Diskusija)


[info]cannibalsmith
2006-12-31 01:15 (saite)
Super! Paldies! Tieši tas, ko vajadzēja.

(Atbildēt uz šo) (Iepriekšējais)


[info]cannibalsmith
2006-12-31 13:24 (saite)
Bāzes klases pointeri var norādīt uz atvasinātas klases objektu. Node ir atvasināta no List un Item. Node satur mainīgo name. List satur funkciju getItem, kas atgriež Item pointeri. Vai sekojošais kods strādās pareizi, ja funkcijas atgrieztais Item pointeris rādīs uz Node klases objektu? Mans minējums ir jā...
Node* Graph::getNode(char node)
{
    for (int x = 0; x < count; x++)
    {
        if (((Node*)getItem(x))->name == node)
        {
            return (Node*)curr;
        }
    }
    return 0;
}

(Atbildēt uz šo) (Iepriekšējais) (Diskusija)


[info]bubu
2006-12-31 14:50 (saite)
Jā, tas strādās. Bet viens liels Bet. Tas ir dikti slikts C++ kods. Tas jau praktiskir ir C kods. Tik ar C++ sintaksi.
Slikti ir lietot C castus, tb iekavas ar tipu tajā. Šajā gadījumā labāk derētu C++ dynamic_cast:
Node* Graph::getNode(char node)
{
    for (int x = 0; x < count; x++)
    {
        if (Node* curr = dynamic_cast<Node*>(getItem(x)))
        {
            if (curr->name == node)
            {
                return curr;
            }
        }
    }
    return 0;
}

dynamic_cast atgriezīs NULL, ja padotais objekts nevar tikt nokāstots un Node klases pointeri. Un tādā gadījumā if's nemaz neizpildīsies.

Taču šis arī ir nelabs C++ kods. Jebkurai dynamic_cast parādīšanās būtu tev jāliek kārtīgi pārdomāt savu klašu hierarhiju.
Šajā gadījumā nevarētu iztikt ar pure virtual funkciju Item klasē?
virtual char getName() = 0;

Vai pat ne tikai getName, bet paša darba izdarīšanu, ko gribi ar Node/Item objektiem darīt:
virtual char do_your_stuff() = 0;

Tad attiecīgi Node klasē to implementēt (kā arī Graph), un tad:
void Graph::do_your_stuff(char node)
{
    for (int x = 0; x < count; x++)
    {
        Item* item = getItem(x);
        if (item->getName() == node)
        {
            item->do_your_stuff();
        }
    }
}

Kautgan arī neizskatās īpaši skaisti. Taču ko precīzāku ieteikt nezinot, ko tu tur centies izvedot, ir grūti.

(Atbildēt uz šo) (Iepriekšējais) (Diskusija)


[info]cannibalsmith
2007-01-01 19:29 (saite)
Es centos izveidot grafu. Beigās nospļāvos un uztaisīju viņu no STL vektoriem. Nekāda čakara un strādā lieliski.

Vēlreiz paldies par visu.

(Atbildēt uz šo) (Iepriekšējais)


(Lasīt komentārus) -

Neesi iežurnalējies. Iežurnalēties?