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

Aug 20, 2017 at 5:44am
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 Sep 1, 2017 at 5:18am
Aug 20, 2017 at 6:36am
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 Aug 20, 2017 at 7:00am
Aug 20, 2017 at 2:20pm
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 Aug 20, 2017 at 2:26pm
Aug 20, 2017 at 3:19pm
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?
Aug 20, 2017 at 4:13pm
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 Aug 20, 2017 at 4:15pm
Aug 20, 2017 at 4:24pm
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.
Aug 21, 2017 at 12:24am
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
}
Aug 21, 2017 at 12:51am
Why should that behavior be considered incorrect?
Last edited on Aug 21, 2017 at 12:51am
Sep 3, 2017 at 4:25pm
OK. But if I chose to increment counter inside the constructor of each class I would get b1? (using ne555's example)
Sep 3, 2017 at 8:44pm
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 Sep 3, 2017 at 8:46pm
Topic archived. No new replies allowed.