Are static variables in a base class shared by all

2020-01-25 05:08发布

If I have something like

class Base {
    static int staticVar;
}

class DerivedA : public Base {}
class DerivedB : public Base {}

Will both DerivedA and DerivedB share the same staticVar or will they each get their own?

If I wanted them to each have their own, what would you recommend I do?

7条回答
Emotional °昔
2楼-- · 2020-01-25 05:49

They will each share the same instance of staticVar.

In order for each derived class to get their own static variable, you'll need to declare another static variable with a different name.

You could then use a virtual pair of functions in your base class to get and set the value of the variable, and override that pair in each of your derived classes to get and set the "local" static variable for that class. Alternatively you could use a single function that returns a reference:

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

You would then use this as:

staticVar() = 5;
cout << staticVar();
查看更多
一夜七次
3楼-- · 2020-01-25 05:53

The sample code given by @einpoklum is not working as it is because of the missing initialization of the static member foo_, missing inheritance in FooHolder declaration, and missing public keywords since we are dealing with classes. Here is the fixed version of it.

#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;
}
查看更多
霸刀☆藐视天下
4楼-- · 2020-01-25 05:54

I know that this question has already been answered but I would like to provide a small example of inheritance with static members. This is a very nice way to demonstrate the usefulness as well as what is happening with the static variables and the respective constructors.

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

If __FUNCTION__ is not working for you in your constructors then you can use something similar that can replace it such as __PRETTY_FUNCTION__ or __func__, or manually type out each class's name :(.

查看更多
\"骚年 ilove
5楼-- · 2020-01-25 06:01

They will share the same instance.

You'll need to declare separate static variables for each subclass, or you could consider a simple static map in which you could store variables that are referenced by derived classes.


Edit: A possible solution to this would be to define your base class as a template. Having a static variable defined in this template would mean that each derived class will have it's own instance of the static.

查看更多
等我变得足够好
6楼-- · 2020-01-25 06:04

To ensure that each class has its own static variable, you should use the "Curiously recurring template pattern" (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> {};
查看更多
ら.Afraid
7楼-- · 2020-01-25 06:04

Alas, C++ has no virtual static data members. There are several ways to simulate this, more or less:

  • @GregHewgill's solution has you replicate the static variable in each derived class; this solution is simple, straightforward and doesn't introduce additional classes, but I don't like this one since it's verbose, and you have to be rather disciplined with it.
  • @MarkIngram suggested a CRTP-based solution, which saves you most of the typing; however, it messes up the inheritance structure, because what were previously subclasses of A are no longer really related as classes. After all, two templated types with the same name but different template arguments could be just any two types.

I suggest a different CRTP-based solution, using a mix-in class:

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

The only thing you need to do in a subclass is also indicate the mix-in inheritance. There might be some virtual inheritance caveats I'm missing here (as I rarely use it).

Note that you either have to instantiate and initialize each subclass' static variable somewhere, or you can make it an inline variable (C++17) and initialize it within the template.

This answer was adapted from my answer to a dupe question.

查看更多
登录 后发表回答