基类中的静态变量是否由所有派生类共享?

时间:2009-09-07 20:52:07

标签: c++ inheritance static

如果我有类似

的话
class Base {
    static int staticVar;
}

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

DerivedADerivedB都会共享相同的staticVar,还是他们各自得到自己的?{/ p>

如果我希望每个人都有自己的,你会建议我做什么?

7 个答案:

答案 0 :(得分:41)

他们将分享staticVar的相同实例。

为了让每个派生类获得自己的静态变量,您需要声明另一个具有不同名称的静态变量。

然后,您可以在基类中使用一对虚函数来获取和设置变量的值,并在每个派生类中覆盖该对,以获取和设置该类的“本地”静态变量。或者,您可以使用返回引用的单个函数:

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

然后您可以将其用作:

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

答案 1 :(得分:29)

要确保每个类都有自己的静态变量,您应该使用"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> {};

答案 2 :(得分:3)

他们将共享同一个实例。

您需要为每个子类声明单独的静态变量,或者您可以考虑一个简单的静态映射,您可以在其中存储由派生类引用的变量。


编辑:可能的解决方案是将基类定义为模板。在此模板中定义静态变量意味着每个派生类都将拥有自己的静态实例。

答案 3 :(得分:3)

您的案例中只有一个staticVarBase::staticVar

在类中声明静态变量时,仅为该类声明变量。在您的情况下,DerivedA甚至看不到staticVar(因为它是私有的,不受保护的或公开的),所以它甚至不知道存在staticVar变量。

答案 4 :(得分:1)

唉,C ++没有虚拟静态数据成员。有多种方法可以模拟这个,或多或少:

  • @GregHewgill's solution您是否在每个派生类中复制静态变量;这个解决方案简单明了,并没有引入额外的类,但我不喜欢这个,因为它很冗长,而且你必须对它有一定的纪律性。
  • @MarkIngram建议CRTP-based solution,这可以节省大部分打字费用;但是,它会混淆继承结构,因为之前的A子类不再真正与类相关。毕竟,具有相同名称但不同模板参数的两个模板化类型可以是任何两种类型。

我建议使用CRTP类的基于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> { }

您在子类中唯一需要做的事情也是指示混合继承。可能会有一些我在这里缺少的虚拟继承警告(因为我很少使用它)。

请注意,您必须在某处实例化并初始化每个子类的静态变量,或者您可以将其设为inline变量(C ++ 17)并在模板中对其进行初始化。

这个答案改编自我对dupe question的答案。

答案 5 :(得分:1)

我知道这个问题已经得到解答,但我想提供一个静态成员继承的小例子。这是展示静态变量和各个构造函数的有用性以及发生的事情的一种非常好的方法。

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

如果__FUNCTION__在您的构造函数中不适合您,那么您可以使用可替换它的类似内容,例如__PRETTY_FUNCTION____func__,或手动输入每个类的名称{{ 1}}。

答案 6 :(得分:1)

由于缺少静态成员foo_的初始化,缺少FooHolder声明的继承以及缺少public关键字,因此@einpoklum提供的示例代码无法正常工作我们正在上课。这是它的固定版本。

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