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 les mêmes staticVar
ou auront-ils chacun la leur?
Si je voulais qu'ils aient chacun le leur, que recommanderiez-vous que je fasse?
Ils partageront chacun la même instance de staticVar
.
Pour que chaque classe dérivée obtienne sa propre variable statique, vous devrez déclarer une autre variable statique avec un nom différent.
Vous pouvez ensuite utiliser une paire virtuelle de fonctions 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. Alternativement, 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 "Modèle de modèle curieusement récurrent" (CRTP) .
template <typename T>
class Base
{
static int staticVar;
};
template <typename T> int Base<T>::staticVar(0);
class DerivedA : public Base<DerivedA> {};
class DerivedB : public Base<DerivedB> {};
Ils partageront la même instance.
Vous devrez déclarer des variables statiques distinctes pour chaque sous-classe, ou vous pourriez envisager une carte statique simple dans laquelle vous pourriez stocker des variables référencées par des classes dérivées.
Edit: Une solution possible à cela serait de définir votre classe de base comme modèle. Avoir une variable statique définie dans ce modèle signifierait que chaque classe dérivée aura sa propre instance de la statique.
Il n'y a qu'un 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 uniquement. Dans votre cas, DerivedA ne peut même pas voir staticVar
(car il est privé, non protégé ou public), donc il ne sait même pas qu'il existe une variable staticVar
.
L'exemple de code donné par @einpoklum ne fonctionne pas tel quel en raison de l'initialisation manquante du membre statique foo_
, héritage manquant dans la déclaration FooHolder
et mots clés public
manquants car nous avons affaire à des classes. En voici la version fixe.
#include <iostream>
#include <string>
class A {
public:
virtual const int& Foo() const = 0;
};
template <typename T>
class FooHolder : public virtual A {
public:
const int& Foo() const override { return foo_; }
static int foo_;
};
class B : public virtual A, public FooHolder<B> { };
class C : public virtual A, public FooHolder<C> { };
template<>
int FooHolder<B>::foo_(0);
template<>
int FooHolder<C>::foo_(0);
int main()
{
B b;
C c;
std::cout << b.Foo() << std::endl;
std::cout << c.Foo() << std::endl;
}
Hélas, C++ n'a pas de membres de données statiques virtuelles. Il existe plusieurs façons de simuler cela, plus ou moins:
Je suggère une solution basée sur CRTP différente, en utilisant une classe mix-in :
class A {
virtual const int& Foo() const = 0;
}
template <typename T>
class FooHolder {
static int foo_;
const int& Foo() const override { return foo_; }
}
class B : A, virtual FooHolder<B> { }
class C : B, virtual FooHolder<B> { }
La seule chose que vous devez faire dans une sous-classe est également d'indiquer l'héritage mix-in. Il pourrait y avoir quelques mises en garde d'héritage virtuel que je manque ici (car je l'utilise rarement).
Notez que vous devez soit instancier et initialiser la variable statique de chaque sous-classe quelque part, soit en faire une variable inline
(C++ 17) et l'initialiser dans le modèle.
Cette réponse a été adaptée de ma réponse à une question dupe .
Je sais que cette question a déjà été répondue, mais je voudrais fournir un petit exemple d'héritage avec des membres statiques. C'est une très belle 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 <string>
class FooBase {
protected:
std::string _nameAndId;
private:
std::string _id;
static int _baseCounter;
public:
std::string idOfBase();
virtual std::string idOf() const = 0;
protected:
FooBase();
};
#endif // !FOO_BASE_H
FooBase.cpp
#include "FooBase.h"
#include <iostream>
int FooBase::_baseCounter = 0;
FooBase::FooBase() {
_id = std::string( __FUNCTION__ ) + std::to_string( ++_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::string idOf() const override;
};
class DerivedB : public FooBase {
private:
static int _derivedCounter;
public:
DerivedB();
std::string idOf() const override;
};
#endif // !DERIVED_FOOS_H
DerivedFoos.cpp
#include "DerivedFoos.h"
#include <iostream>
int DerivedA::_derivedCounter = 0;
int DerivedB::_derivedCounter = 0;
DerivedA::DerivedA() : FooBase() {
_nameAndId = std::string( __FUNCTION__ ) + std::to_string( ++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 tel que __PRETTY_FUNCTION__
ou __func__
, ou saisissez manuellement le nom de chaque classe :(
.