Чи успадковуються статичні поля?


102

Коли статичні члени успадковуються, чи є вони статичними для всієї ієрархії чи просто для цього класу, тобто:

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;
}

загалом було б 3 у всіх трьох випадках, або це було б 2 для SomeClassта 1 для SomeDerivedClass?

Відповіді:


55

3 у всіх випадках, оскільки static int totalуспадковане SomeDerivedClassсаме саме вхідне SomeClass, а не окрема змінна.

Редагувати: насправді 4 у всіх випадках, як помітив @ejames і вказав у своїй відповіді, яку див.

Редагувати: код у другому питанні відсутній intв обох випадках, але додавання робить його нормальним, тобто:

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

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

працює чудово і з різними значеннями для A :: MaxHP та Cat :: MaxHP - у цьому випадку підклас "не успадковує" статику від базового класу, оскільки, так би мовити, це "приховує" її власним омонімом один.


12
Гарне пояснення, але чисельний відповідь насправді 4, що не 3. Дивіться мою відповідь ( stackoverflow.com/questions/998247 / ... )
e.James

3
+1, відмінна точка, я редагую відповідь, щоб вказати на ваші, дякую!
Алекс Мартеллі

1
+1, хоча правильніше сказати "+4 до того, до чого статичний член ініціалізований". Статичний член не є ні локальним областю, ні областю простору імен, тому десь повинно бути визначення, яке призначає значення ( не обов'язково нуль). Інакше код не відповідає правилу однієї дефініції і не буде компілюватися.
Деймон

Але якщо хочеться static int totalвиділити для кожного похідного класу єдиний спосіб його додати static int totalдо кожного класу? Або можна використовувати лише визначення базового класу (?), Тому що наявність змінної totalмає бути властивістю кожного класу. З іншого боку, це має бути static.
LRDPRDX

97

Відповідь насправді чотири у всіх випадках, оскільки конструкція SomeDerivedClassпризведе до збільшення загальної суми вдвічі .

Ось повна програма (за допомогою якої я перевіряв свою відповідь):

#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.total = 4
B.total = 4
C.total = 4

10

Це 4, оскільки коли створений похідний об'єкт, конструктор похідного класу викликає конструктор базового класу.
Отже значення статичної змінної збільшується вдвічі.


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;
}

Це було б:

A() total = 1
A() total = 2
A() total = 3
B() total = 4

1

Конструктор SomeClass () викликається автоматично при виклику SomeDerivedClass (), це правило C ++. Ось чому загальна сума збільшується один раз на кожен об'єкт SomeClass, а потім двічі на об’єкт SomeDerivedClass. 2x1 + 2 = 4


0

3 у всіх трьох випадках.

А для вашого іншого питання, схоже, вам дійсно потрібна змінна const замість статичної. Можливо, буде більш зрозумілим, що надає віртуальну функцію, яка повертає потрібну вам змінну, яку буде замінено у похідних класах.

Якщо цей код не викликається критичним шляхом, коли необхідна продуктивність, завжди вибирайте інтуїтивніший код.


0

Так, похідний клас містив би ту саму статичну змінну, тобто - всі вони містили б 3 для загального (якщо припустити, що підсумок десь ініціалізовано до 0).

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.