Czy pola statyczne są dziedziczone?

102

Kiedy statyczne elementy członkowskie są dziedziczone, czy są statyczne dla całej hierarchii, czy tylko dla tej klasy, tj .:

class SomeClass
{
public:
    SomeClass(){total++;}
    static int total;
};

class SomeDerivedClass: public SomeClass
{
public:
    SomeDerivedClass(){total++;}
};

int main()
{
    SomeClass A;
    SomeClass B;
    SomeDerivedClass C;
    return 0;
}

czy łącznie wyniosą 3 we wszystkich trzech przypadkach, czy też 2 dla SomeClassi 1 dla SomeDerivedClass?

BartoszKP
źródło

Odpowiedzi:

55

3 we wszystkich przypadkach, ponieważ static int totaldziedziczone przez SomeDerivedClassjest dokładnie tą SomeClass, a nie odrębną zmienną.

Edycja: właściwie 4 we wszystkich przypadkach, jak @ejames zauważył i wskazał w swojej odpowiedzi, którą widzisz.

Edycja: w drugim pytaniu brakuje kodu w intobu przypadkach, ale dodanie go sprawia, że ​​wszystko jest w porządku, tj .:

class A
{
public:
    static int MaxHP;
};
int A::MaxHP = 23;

class Cat: A
{
public:
    static const int MaxHP = 100;
};

działa dobrze iz różnymi wartościami dla A :: MaxHP i Cat :: MaxHP - w tym przypadku podklasa „nie dziedziczy” statycznej z klasy bazowej, ponieważ, że tak powiem, „ukrywa” ją własną homonimiczną jeden.

Alex Martelli
źródło
12
Dobre wyjaśnienie, ale odpowiedź liczbowa to tak naprawdę 4, a nie 3. Zobacz moją odpowiedź ( stackoverflow.com/questions/998247/… )
e.James
3
+1, Doskonała uwaga, edytuję odpowiedź, aby wskazywała na twoją, dzięki!
Alex Martelli
1
+1, chociaż należałoby raczej powiedzieć „+4 do tego, do czego jest zainicjowany statyczny element członkowski”. Statyczny element członkowski nie jest ani zasięgiem lokalnym, ani zakresem przestrzeni nazw, więc gdzieś musi istnieć definicja, która przypisuje wartość ( niekoniecznie zero). W przeciwnym razie kod nie spełnia reguły jednej definicji i nie będzie się kompilował.
Damon
Ale jeśli ktoś chce static int totalbyć odrębny dla każdej klasy pochodnej, to jedyny sposób, aby to osiągnąć, to dodać static int totaldo każdej klasy? A może można użyć tylko definicji klasy bazowej (?), Ponieważ posiadanie zmiennej totalpowinno być własnością każdej klasy. Z drugiej strony tak powinno być static.
LRDPRDX
97

W rzeczywistości we wszystkich przypadkach odpowiedź to cztery , ponieważ konstrukcja SomeDerivedClassspowoduje dwukrotny wzrost sumy .

Oto kompletny program (którego użyłem do weryfikacji mojej odpowiedzi):

#include <iostream>
#include <string>

using namespace std;

class SomeClass
{
    public:
        SomeClass() {total++;}
        static int total;
        void Print(string n) { cout << n << ".total = " << total << endl; }
};

int SomeClass::total = 0;

class SomeDerivedClass: public SomeClass
{
    public:
        SomeDerivedClass() {total++;}
};

int main(int argc, char ** argv)
{
    SomeClass A;
    SomeClass B;
    SomeDerivedClass C;

    A.Print("A");
    B.Print("B");
    C.Print("C");

    return 0;
}

A wyniki:

A.total = 4
B.total = 4
C.total = 4
e.James
źródło
10

Jest to 4, ponieważ podczas tworzenia obiektu pochodnego konstruktor klasy pochodnej wywołuje konstruktor klasy bazowej.
Zatem wartość zmiennej statycznej jest zwiększana dwukrotnie.

VenuGopal
źródło
5
#include<iostream>
using namespace std;

class A
{
public:
    A(){total++; cout << "A() total = "<< total << endl;}
    static int total;
};

int A::total = 0;

class B: public A
{
public:
    B(){total++; cout << "B() total = " << total << endl;}
};

int main()
{
    A a1;
    A a2;
    B b1;

    return 0;
}

To byłby:

A() total = 1
A() total = 2
A() total = 3
B() total = 4
rocky4android
źródło
1

Konstruktor SomeClass () jest wywoływany automatycznie po wywołaniu SomeDerivedClass (), jest to reguła C ++. Dlatego suma jest zwiększana raz dla każdego obiektu SomeClass, a następnie dwukrotnie dla obiektu SomeDerivedClass. 2x1 + 2 = 4

Darko Maksimovic
źródło
0

3 we wszystkich trzech przypadkach.

A jeśli chodzi o twoje drugie pytanie, wygląda na to, że naprawdę potrzebujesz zmiennej const zamiast statycznej. Zapewnienie funkcji wirtualnej, która zwraca potrzebną zmienną, która jest zastępowana w klasach pochodnych, może być bardziej oczywiste.

O ile ten kod nie jest wywoływany na ścieżce krytycznej, w której wymagana jest wydajność, zawsze wybieraj bardziej intuicyjny kod.

adzm
źródło
0

Tak, klasa pochodna zawierałaby tę samą zmienną statyczną, tj. Wszystkie zawierałyby 3 dla total (zakładając, że suma została gdzieś zainicjowana na 0).

Niki Yoshiuchi
źródło