Counter object that declared only in the base class but used in every derived class separately.

Suppose I have a class which represents kind of protocol for other classes that inherited from it:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//Protocol.h
class Protocol
{
  protected:
    //each object has a name
    string name;

    //count how many objects have been created
    static unsigned int counter;

  public:
    virtual void Print() = 0;
    virtual ~Protocol() = 0;

    static void AddInstance() { counter++; }
    static unsigned int GetCounter() { return counter; }
};

Protocol::~Protocol() { }

unsigned int Protocol::counter = 0;

and
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
//A.h
#include "Protocol.h"

class A : public Protocol
{
  public:
    A();
    ~A() { }
    virtual void Print { cout << name << endl; }
};

A::A(){
  AddInstance();
  name = "a" + std::to_string( GetCounter() );
}

//B.h
#include "Protocol.h"

class B : public Protocol
{
  public:
    B();
    ~B() { }
    virtual void Print { cout << name << endl; }
};

B::B(){
  AddInstance();
  name = "b" + std::to_string( GetCounter() );
}

Then if I do
1
2
3
4
5
6
7
8
9
#include "A,h"
#include "B.h"

int main() {
  A a;
  B b;

  a.Print(); b.Print();
}

No surprise I get

a1
b2

But I would like to have

a1
b1

Of course, I could just add static member to each of classes A and B but I wonder if I can achieve this by using only Protocol definition?
Last edited on
F-bounded polymorphism is sometimes called "backwards polymorphism" or the "Curiously recurring template pattern". It can be used to accomplish something to this effect.

See:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# include <string>
# include <iostream>

template <typename Derived> 
class Protocol {
protected:
    static unsigned int counter;
};

template <typename Derived>
unsigned int Protocol<Derived>::counter = 0;

struct A: public Protocol<A> { 
    A() { this->counter++; }    
    void print() const { std::cout << "a" << this->counter << '\n'; }
};

struct B: public Protocol<B> { 
    B() { this->counter++; } 
    void print() const { std::cout << "b" << this->counter << '\n'; }
};

int main() {
  A a; B b;
  a.print(); b.print(); 
}

Live demo:
http://coliru.stacked-crooked.com/a/9d2415af427ee0bc

Note that you'll need another base to get runtime polymorphism.

Edit:
Wikipedia has a decent introduction to the idea
https://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
Last edited on
Interesting conception.
I used it except I still have a incremental function in the base class only:
 
static void AddInstance() { counter++; }

So far it is working pretty well. What I was looking for.
I just want to sure that it does not differ from that you posted ( using this pointer inside each class ) and in future I won't meet some surprising errors or unwanted behavior.
According to wiki it is allowed to do so.
Last edited on
can't talk about code that can't see, ¿where do you call the `AddInstance()' function?

Also, ¿how would you make class C that derives from B?
I call AddInstance inside a constructor of each inherited class like so:
1
2
3
4
A::A() {
AddInstance();
...
}

I inherit like you said:
1
2
3
4
class A : public Protocol<A>
{
...
}

May be it would be better if I call AddInstance in the Protocol constructor. But can abstract class have a constructor at all? I will try.
Last edited on
Yes. It works if I increment counter inside the Protocol constructor:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
template <typename T>
class Protocol
{
  protected:
    static unsigned int counter;
    ...

  public:
    Protocol() { ++counter; }
    ...
};

template <typename T>
unsigned int Protocol::counter = 0;
...

Then when I create objects of different derived classes they have their own counter.
Again, ¿what if you do class C that derives from B?
1
2
3
4
5
6
7
8
class B: public Protocol<B>{};
class C: public B, public Protocol<C>{};

int main(){
   B b;
   C c;
   b.print(); //outputs b2
}
Why should that behavior be considered incorrect?
Last edited on
OK. But if I chose to increment counter inside the constructor of each class I would get b1? (using ne555's example)
But if I chose to increment counter inside the constructor of each class would I get b1?

No - I only wrote it that way for brevity, which I see now was at the expense of clarity (my apologies)!

Inheritance models an is-a relationship, so given that C inherits from B, if any C is created, a B is created too, and the counter reflects that.

C does indeed has a separate counter inherited from Protocol<C>, but you'd need to refer to that using a qualified name (i.e., Protocol<C>::counter), because B::counter is found first.

If you wanted to avoid adding one to the counter for B when constructing a C, you'd need to increment only the appropriate counter in the constructor of B and C, which mostly defeats the point of this technique. But I'm not convinced that this is the correct behavior.
Last edited on
Topic archived. No new replies allowed.