Reputation: 11
so i've tried multiple ways of creating a counter for my class that's passing the number in the constructor
i want it to output something like this:
input the amount of base class objects: 2
The A# 1:
input SomeVar_one: 3
input SomeVar_two: 2
The A# 2:
input SomeVar_one: 2
input SomeVar_two: 3
input the amount of derived class objects: 2
The A# 1:
input SomeVar_one: 23
input SomeVar_two: 32
The A# 2:
input SomeVar_one: 12
input SomeVar_two: 42
total # of base objects is: 4
total # of derived objects is: 4
where i do get this:
input the amount of base class objects: 2
The A# 1:
input SomeVar_one: 3
input SomeVar_two: 2
The A# 2:
input SomeVar_one: 2
input SomeVar_two: 3
input the amount of derived class objects: 2
The A# 3:
input SomeVar_one: 23
input SomeVar_two: 32
The A# 4:
input SomeVar_one: 12
input SomeVar_two: 42
total # of base objects is: 4
total # of derived objects is: 4
notice the difference between the user prompts for inputting the values that is called from the constructor that is called from the new
operator
ofc there is a need to give them their separate names and this is a question that i'd like to adress as well. anything you might suggest is acceptable.
the main goal is to instantiate objects right at the moment when the new
operator is called without getting in the for
loop at which i ofc can call "The (A/B) # (i)"
here is a code that i've used: it uses the "curiously recurring template pattern" (btw this name is a killer!)
//sample
#include<iostream>
template <typename T>
class counter
{
public:
counter(bool do_count = true) : counted(do_count)
{
if (counted) get_count()++;
}
~counter()
{
if (counted) get_count()--;
}
static unsigned long GetInstancesCount()
{
return get_count();
}
private:
bool counted;
static unsigned long& get_count()
{
static unsigned long count = 0;
return count;
}
};
class base:public counter<base>
{
protected:
int m_SomeVar_one = 0, m_SomeVar_two = 0;
unsigned long ObjectNumber = 0;
public:
base(bool count=true):counter<base>(count),ObjectNumber(counter<base>::GetInstancesCount())
{
std::cout << "The A# " << ObjectNumber <<": " << std::endl;
std::cout << "input SomeVar_one: ";
std::cin >> m_SomeVar_one;
std::cout << "input SomeVar_two: ";
std::cin >> m_SomeVar_two;
}
virtual int get_count()
{
return counter<base>::GetInstancesCount();
}
};
class derived :public base, public counter<derived>
{
protected:
int m_SomeVar_three = 0;
public:
derived(bool count = true) :base(false), counter<derived>(count)
{
std::cout << "input SomeVar_three: ";
std::cin >> m_SomeVar_three;
}
virtual int get_count() override
{
return counter<derived>::GetInstancesCount();
}
};
int main()
{
std::cout << "input the amount of base class objects: ";
int amountOfBaseObjects;
std::cin >> amountOfBaseObjects;
base* BaseArray = new base[amountOfBaseObjects];
std::cout << "input the amount of derived class objects: ";
int amountOfDerivedObjects;
std::cin >> amountOfDerivedObjects;
base* DerivedArray = new base[amountOfDerivedObjects];
std::cout <<"total # of base objects is: "<< BaseArray->get_count() << std::endl;
std::cout << "total # of derived objects is: " << DerivedArray->get_count() << std::endl;
}
Upvotes: 1
Views: 496
Reputation: 4079
CRTP doesn't really gel well with virtual polymorphism - virtual polymorphism involves a common base class, while CRTP generates a different base class for each derived type.
Anyway, you can crack it with composition. Here is a non-template version of counter with a factory method template. Note the rule of 3 is necessary to do accurate reference counting:
class counter
{
public:
template <typename T>
static counter create()
{
static unsigned long count = 0;
return { &count };
}
counter(const counter& that) : count_addr(that.count_addr)
{
(*count_addr)++;
}
counter& operator =(const counter& that)
{
(*count_addr)--;
count_addr = that.count_addr;
(*count_addr)++;
return *this;
}
~counter()
{
(*count_addr)--;
}
unsigned long GetInstancesCount()
{
return *count_addr;
}
private:
unsigned long* count_addr;
counter(unsigned long* count_addr) : count_addr(count_addr)
{
(*count_addr)++;
}
};
Then you can embed a counter as a member of the base class, with the option for a derived class to provide its own counter via a protected constructor. The bit where the public constructors forward a factory method instead of a counter is to ensure there are no living temporary copies, which could could accidentally inflate the count, when ObjectNumber
is assigned.
class base
{
public:
base() : base(counter::create<base>)
{
}
int get_count()
{
return ctr.GetInstancesCount();
}
private:
counter ctr;
protected:
base(counter(*ctr)()) : ctr(ctr()), ObjectNumber(this->ctr.GetInstancesCount())
{
std::cout << "The A# " << ObjectNumber <<": " << std::endl;
}
unsigned long ObjectNumber; // important - must come after counter
};
class derived : public base
{
public:
derived() : base(counter::create<derived>)
{
}
};
After that, I can roughly replicate your intended output: https://godbolt.org/z/eonfb9
Upvotes: 1