it-swarm-eu.dev

Jaká jsou pravidla pro volání konstruktoru nadtřídy?

Jaká jsou pravidla C++ pro volání konstruktoru nadtřídy z podtřídy?

Například v Javě vím, musíte to udělat jako první řádek konstruktoru podtřídy (a pokud ne, předpokládá se implicitní volání na super-konstruktor no-arg - což vám poskytne chybu kompilace, pokud to chybí) .

620
levik

Konstruktory základní třídy jsou automaticky volány, pokud nemají žádný argument. Pokud chcete zavolat konstruktoru nadtřídy s argumentem, musíte použít inicializační seznam konstruktoru podtřídy. Na rozdíl od Java podporuje C++ vícenásobné dědičnosti (pro lepší nebo horší), takže základní třída musí být označena spíše jménem než „super ()“.

class SuperClass
{
    public:

        SuperClass(int foo)
        {
            // do something with foo
        }
};

class SubClass : public SuperClass
{
    public:

        SubClass(int foo, int bar)
        : SuperClass(foo)    // Call the superclass constructor in the subclass' initialization list.
        {
            // do something with bar
        }
};

Více informací o inicializačním seznamu konstruktoru zde a zde .

841
luke

V C++ jsou pro vás před voláním konstruktoru volány konstrukty bez argumentů pro všechny nadřazené a členské proměnné. Pokud chcete předat argumenty, existuje samostatná syntaxe pro toto nazývá "řetězec konstruktoru", který vypadá takto:

class Sub : public Base
{
  Sub(int x, int y)
  : Base(x), member(y)
  {
  }
  Type member;
};

Pokud v tomto bodě něco běží, hodí se základny/členové, kteří předtím dokončili stavbu, aby jejich destruktory zavolali a výjimka byla vrácena volajícímu. Chcete-li zachytit výjimky během zřetězení, musíte použít blok vyzkoušení funkce:

class Sub : public Base
{
  Sub(int x, int y)
  try : Base(x), member(y)
  {
    // function body goes here
  } catch(const ExceptionType &e) {
    throw kaboom();
  }
  Type member;
};

V této formě si všimněte, že zkuste blok je tělo funkce, spíše než být uvnitř těla funkce; to umožňuje zachytit výjimky vyvolané implicitními nebo explicitními inicializacemi členů a základní třídy, jakož i během těla funkce. Pokud však blok blokování funkce nevyhodí jinou výjimku, runtime bude znovu vracet původní chybu; výjimky během inicializace nelze ignorovat.

217
puetzk

V C++ existuje koncept inicializačního seznamu konstruktoru, kde můžete a měli byste volat konstruktor základní třídy a kde byste také měli inicializovat členy dat. Inicializační seznam přichází po podpisu konstruktoru za dvojtečkou a před tělem konstruktoru. Řekněme, že máme třídu A:


class A : public B
{
public:
  A(int a, int b, int c);
private:
  int b_, c_;
};

Pak, za předpokladu, že B má konstruktor, který má int, může konstruktor A vypadat takto:


A::A(int a, int b, int c) 
  : B(a), b_(b), c_(c) // initialization list
{
  // do something
}

Jak vidíte, konstruktor základní třídy je volán v inicializačním seznamu. Mimochodem, inicializace datových členů v inicializačním seznamu je výhodnější než přiřazení hodnot pro b_ a c_ uvnitř těla konstruktoru, protože ukládáte dodatečné náklady přiřazení.

Mějte na paměti, že datové členy jsou vždy inicializovány v pořadí, ve kterém jsou deklarovány v definici třídy, bez ohledu na jejich pořadí v inicializačním seznamu. Chcete-li se vyhnout podivným chybám, které mohou vzniknout, pokud jsou členové dat závislí na sobě, měli byste se vždy ujistit, že pořadí členů je v seznamu inicializace a definici třídy stejné. Ze stejného důvodu musí být konstruktor základní třídy první položkou v inicializačním seznamu. Pokud ho zcela vynecháte, bude automaticky vyvolán výchozí konstruktor pro základní třídu. V tomto případě, pokud základní třída nemá výchozí konstruktor, dostanete chybu kompilátoru.

48
Dima

Každý se zmínil o volání konstruktoru prostřednictvím inicializačního seznamu, ale nikdo neřekl, že konstruktor mateřské třídy může být volán explicitně z těla konstruktéra odvozeného člena. Viz otázka Volání konstruktoru základní třídy z těla konstruktoru podtřídy , například. Jde o to, že pokud použijete explicitní volání konstruktoru nadřazené třídy nebo super třídy v těle odvozené třídy, jedná se vlastně o vytvoření instance nadřazené třídy a není vyvolán konstruktor nadřazené třídy na odvozeném objektu. . Jediný způsob vyvolání konstruktoru nadřazené třídy nebo super třídy na objektu odvozené třídy je prostřednictvím inicializačního seznamu a ne v těle konstruktoru odvozené třídy. Takže možná by neměla být nazývána „volání nadřazené konstruktéry“. Tuto odpověď jsem dal, protože někdo by mohl být zmatený (jako já).

20
TT_

Pokud máte konstruktor bez argumentů, bude vyvolán dříve, než bude proveden konstruktor odvozené třídy.

Pokud chcete zavolat konstruktoru base-constructor s argumenty, musíte explicitně napsat, že v takto odvozeném konstruktoru:

class base
{
  public:
  base (int arg)
  {
  }
};

class derived : public base
{
  public:
  derived () : base (number)
  {
  }
};

Nelze vytvořit odvozenou třídu bez volání konstruktoru rodičů v jazyce C++. To se stane automaticky, pokud je to non-arg C'tor, to se stane, když zavoláte odvozený konstruktor přímo, jak je uvedeno výše, nebo váš kód nebude kompilován.

19
Nils Pipenbrinck

Jediný způsob, jak předat hodnoty nadřazenému konstruktoru, je prostřednictvím inicializačního seznamu. Inicializační seznam je implementován pomocí: a poté seznamu tříd a hodnot, které mají být předány konstruktoru dané třídy.

Class2::Class2(string id) : Class1(id) {
....
}

Nezapomeňte také, že pokud máte konstruktor, který nebere žádné parametry do nadřazené třídy, bude vyvolán automaticky před provedením podřízeného konstruktoru.

19
CR.

Pokud máte ve vašem konstruktoru výchozí parametry, základní třída bude volána automaticky.

using namespace std;

class Base
{
    public:
    Base(int a=1) : _a(a) {}

    protected:
    int _a;
};

class Derived : public Base
{
  public:
  Derived() {}

  void printit() { cout << _a << endl; }
};

int main()
{
   Derived d;
   d.printit();
   return 0;
}

Výstup je: 1

11
edW
CDerived::CDerived()
: CBase(...), iCount(0)  //this is the initialisation list. You can initialise member variables here too. (e.g. iCount := 0)
    {
    //construct body
    }
9
Dynite

Nikdo se nezmínil o pořadí volání konstruktorů, když třída pochází z více tříd. Posloupnost je stejná jako při odvozování tříd.

6
darth_coder