5

I have a base class A with a constant static variable a. I need that instances of class B have a different value for the static variable a. How could this be achieved, preferably with static initialization ?

class A {
public:
    static const int a;
};
const int A::a = 1;

class B : public A {
    // ???
    // How to set *a* to a value specific to instances of class B ?
};
chmike
  • 20,922
  • 21
  • 83
  • 106

4 Answers4

9

You can't. There is one instance of the static variable that is shared by all derived classes.

  • 1
    Yeah, just found out after posting the question. You managed to answer in the 5s after I posted the question and tried to delete the question. Deleting the question was rejected because of your response and 2 up votes :) – chmike Apr 21 '10 at 10:33
3

Static members are unique in the application. There is a single A::a constant in your system. What you can do is create a B::a static constant in B that will hide the A::a static (if you don't use the fully qualified name:

class A {
public:
   static const int a = 10;
};
static const int A::a;
class B : public A {
public:
   static const int a = 20;
   static void test();
};
static const int B::a;
void B::test() {
   std::cout << a << std::endl;    // 20: B::a hides A::a
   std::cout << A::a << std::endl; // 10: fully qualified
}
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Yes I knew that. The problem is when I have a pointer like this A *p = new B. The p->test() would print 10 and 10. That is the problem I have. It seem the only way is to use a virtual method. – chmike Apr 26 '10 at 18:26
  • @chmike: If you need polymorphism (different behavior based on the actual type of the instance and not the pointer/reference) then you do need virtual methods. In the example I provided, `A *p = new B; p->test()` will not even compile since `test()` does not exist at the `A` level. – David Rodríguez - dribeas Apr 27 '10 at 07:28
  • Yes, obviously. I missed that. So the answer is to replace the static variable a with a virtual method and redefine the method in derived class. The method may contain a static local variable if it is needed. If you provide a simple code example I'll grant you the answer. – chmike Apr 28 '10 at 08:01
  • It depends on what the variable represents, it can be either a method static variable or a class static that is returned from the actual function, depending on what makes more sense. – David Rodríguez - dribeas Apr 28 '10 at 08:18
3

You can do this with Curiously recurring template pattern (you'll have to lose the const though).

template <typename T>
class A {
public:
    static int a;
};

template <typename T>
int A<T>::a = 0;

class B : public A<B> {
    struct helper { // change the value for A<B>::a
        helper() { A<B>::a = 42; }
    };
    static helper h;
};
B::helper B::h;
Motti
  • 110,860
  • 49
  • 189
  • 262
  • This creates a different static variable. –  Apr 21 '10 at 10:40
  • @Neil, Sure does, one variable can't have two different values. – Motti Apr 21 '10 at 10:49
  • The proposal of David Rodriguez is simpler. What is the benefit of using a template here ? – chmike Apr 26 '10 at 18:24
  • @chmike, I'm not sure there is a benefit to my way (I wrote it before seeing David's). David's method creates a different variable for B::a which just happens to have the same name while my method has separate variables from the start, if there are many such derived classes (and A is used only as a base) I think mine is slightly more elegant (you don't have to define the static variable over and over). – Motti Apr 26 '10 at 18:39
0

May be we can try this way as below :: The benefit of the below is that you don't have to write the code multiple times, but the actual generated code might be big.

#include <iostream>

using namespace std;
template <int t>
class Fighters {
protected :
    static const double Fattack;
    double Fhealth;
    static const double Fdamage;
    static int count;
public :
    Fighters(double Fh) : Fhealth(Fh) { }
    void FighterAttacked(double damage) {
        Fhealth -= damage;
    }
    double getHealth()
    {
        return Fhealth;
    }

    static int getCount() 
    {
        //cout << count << endl;
        return count;
    }
};

const double Fighters<1>::Fdamage = 200.0f;
const double Fighters<1>::Fattack = 0.6f;
int Fighters<1>::count = 0;

class Humans : public Fighters<1> {
public :
    Humans(double Fh = 250) : Fighters<1>(Fh) { count++; }
};

const double Fighters<2>::Fdamage = 40.0f;
const double Fighters<2>::Fattack = 0.4f;
int Fighters<2>::count = 0;

class Skeletons : public Fighters<2> {
public :
    Skeletons(double Fh = 50) : Fighters<2>(Fh) { count++; }
};

int main()
{

    Humans h[100];
    Skeletons s[300];

    cout << Humans::getCount() << endl;
    cout << Skeletons::getCount() << endl;

    return 0;
}

This is part of my other code example .. don't mind many other data but concept can be seen.