Les variables statiques d’une classe de base sont-elles partagées par toutes les classes dérivées?

Si j’ai quelque chose comme

class Base { static int staticVar; } class DerivedA : public Base {} class DerivedB : public Base {} 

Est-ce que DerivedA et DerivedB partageront la même valeur staticVar ou obtiendront-elles les leurs?

Si je voulais qu’ils aient chacun leur propre, que recommanderiez-vous que je fasse?

Ils partageront chacun la même instance de staticVar .

Pour que chaque classe dérivée ait sa propre variable statique, vous devez déclarer une autre variable statique avec un nom différent.

Vous pouvez ensuite utiliser une paire de fonctions virtuelles dans votre classe de base pour obtenir et définir la valeur de la variable, et remplacer cette paire dans chacune de vos classes dérivées pour obtenir et définir la variable statique “locale” pour cette classe. Sinon, vous pouvez utiliser une seule fonction qui renvoie une référence:

 class Base { static int staticVarInst; public: virtual int &staticVar() { return staticVarInst; } } class Derived: public Base { static int derivedStaticVarInst; public: virtual int &staticVar() { return derivedStaticVarInst; } } 

Vous utiliseriez alors ceci comme:

 staticVar() = 5; cout << staticVar(); 

Pour vous assurer que chaque classe possède sa propre variable statique, vous devez utiliser le “modèle de modèle curieusement récurrent” (CRTP) .

 template  class Base { static int staticVar; }; template  int Base::staticVar(0); class DerivedA : public Base {}; class DerivedB : public Base {}; 

Ils partageront la même instance.

Vous devrez déclarer des variables statiques distinctes pour chaque sous-classe ou envisager une simple carte statique dans laquelle vous pourrez stocker des variables référencées par des classes dérivées.


Edit : Une solution possible serait de définir votre classe de base en tant que modèle. Avoir une variable statique définie dans ce modèle signifierait que chaque classe dérivée aura sa propre instance du statique.

Il n’y a qu’un seul staticVar dans votre cas: Base::staticVar

Lorsque vous déclarez une variable statique dans une classe, la variable est déclarée pour cette classe seule. Dans votre cas, DerivedA ne peut même pas voir staticVar (puisqu’il est privé, non protégé ou public), donc il ne sait même pas qu’il existe une variable staticVar .

Je sais que cette question a déjà été répondue mais je voudrais fournir un petit exemple d’inheritance avec des membres statiques. C’est une très bonne façon de démontrer l’utilité ainsi que ce qui se passe avec les variables statiques et les constructeurs respectifs.

FooBase.h

 #ifndef FOO_BASE_H #define FOO_BASE_H #include  class FooBase { protected: std::ssortingng _nameAndId; private: std::ssortingng _id; static int _baseCounter; public: std::ssortingng idOfBase(); virtual std::ssortingng idOf() const = 0; protected: FooBase(); }; #endif // !FOO_BASE_H 

FooBase.cpp

 #include "FooBase.h" #include  int FooBase::_baseCounter = 0; FooBase::FooBase() { _id = std::ssortingng( __FUNCTION__ ) + std::to_ssortingng( ++_baseCounter ); std::cout << _id << std::endl; } std::string FooBase::idOfBase() { return _id; } std::string FooBase::idOf() const { return ""; } // empty 

DerivedFoos.h

 #ifndef DERIVED_FOOS_H #define DERIVED_FOOS_H #include "FooBase.h" class DerivedA : public FooBase { private: static int _derivedCounter; public: DerivedA(); std::ssortingng idOf() const override; }; class DerivedB : public FooBase { private: static int _derivedCounter; public: DerivedB(); std::ssortingng idOf() const override; }; #endif // !DERIVED_FOOS_H 

DerivedFoos.cpp

 #include "DerivedFoos.h" #include  int DerivedA::_derivedCounter = 0; int DerivedB::_derivedCounter = 0; DerivedA::DerivedA() : FooBase() { _nameAndId = std::ssortingng( __FUNCTION__ ) + std::to_ssortingng( ++DerivedA::_derivedCounter ); std::cout << _nameAndId << std::endl; } std::string DerivedA::idOf() const { return _nameAndId; } DerivedB::DerivedB() : FooBase() { _nameAndId = std::string( __FUNCTION__ ) + std::to_string( ++DerivedB::_derivedCounter ); std::cout << _nameAndId << std::endl; } std::string DerivedB::idOf() const { return _nameAndId; } 

main.cpp

 #include "DerivedFoos.h" int main() { DerivedA a1; DerivedA a2; DerivedB b1; DerivedB b2; system( "PAUSE" ); return 0; } 

Si __FUNCTION__ ne fonctionne pas pour vous dans vos constructeurs, vous pouvez utiliser quelque chose de similaire qui peut le remplacer, par exemple __PRETTY_FUNCTION__ ou __func__ , ou taper manuellement le nom de chaque classe :( .

Hélas, C ++ n’a pas de membres de données statiques virtuels. Il y a plusieurs manières de simuler ceci, plus ou moins:

  • La solution @ GregHewgill vous permet de répliquer la variable statique dans chaque classe dérivée. Cette solution est simple, directe et n’introduit pas de classes supplémentaires, mais je n’aime pas celle-ci car elle est verbeuse, et vous devez être assez discipliné avec elle.
  • @MarkIngram a suggéré une solution basée sur CRTP , qui vous permet d’économiser la majeure partie de la frappe. Cependant, cela perturbe la structure d’inheritance, car ce qui était auparavant des sous-classes de A ne sont plus vraiment liées en tant que classes. Après tout, deux types de modèles portant le même nom, mais des arguments de modèle différents peuvent être de deux types.

Je suggère une solution basée sur CRTP différente, en utilisant une classe de mix-in :

  class A { virtual const int& Foo() const = 0; } template  class FooHolder { static int foo_; const int& Foo() const override { return foo_; } } class B : A, virtual FooHolder { } class C : B, virtual FooHolder { } 

La seule chose que vous devez faire dans une sous-classe est également d’indiquer l’inheritance de mélange. Il y a peut-être des problèmes d’inheritance virtuel qui me manquent (car je l’utilise rarement).

Notez que vous devez soit instancier et initialiser la variable statique de chaque sous-classe, soit en faire une variable en inline (C ++ 17) et l’initialiser dans le modèle.

Cette réponse a été adaptée de ma réponse à une question de dupe .