C++ unique static id and class name with base class - c++

Having class TaskBase, each derived class of it must have name and unique id.
The TaskBase is something like below:
class TaskBase
{
public:
static const int id()
{
// return an unique id, for each object or derived class, HOW ??
}
static const string name()
{
// return class name for each derived class, HOW ??
// for example : "TaskBase" for this class
}
};
My try was :
template <typename DERIVED>
class TaskBase
{
public:
static const int id()
{
static const int id = reinterpret_cast<int> (typeid (DERIVED).name());
return id;
}
static const string name()
{
static string n;
if (!n.size())
{
int status;
char *realname = abi::__cxa_demangle(typeid (DERIVED).name(), 0, 0, &status);
n = realname;
free(realname);
}
return n;
}
};
I already read this, but i need the ability to have base pointer to each derived classes, something line below:
class MyTask1 : public TaskBase
{
};
MyTask1 myTask1, myTask2;
TaskBase *base = &myTask1;

class TaskBase
{
private:
const void* m_id;
string m_name;
public:
TaskBase(const void* m_id, string m_name): m_id(m_id), m_name(m_name)
{
}
const void* id() const
{
return m_id;
}
string name() const
{
return m_name;
};
};
template< typename DERIVED >
class TaskProxy: public TaskBase
{
public:
static const void* id()
{
//if you want to have for each object a unique id:
//return reinterpret_cast<void*>(this);
//just for each TaskProxy<????>:
return reinterpret_cast<const void*>(typeid( DERIVED ).name());
}
static string name()
{
return typeid( DERIVED ).name();
}
TaskProxy(): TaskBase(id(), name()) {}
};
Usage:
class MyTask1 : public TaskProxy< MyTask1 >
{
};
class MyTask2 : public TaskProxy< MyTask2 >
{
};
...
MyTask1 myTask1;
TaskBase *baseA = &myTask1;
MyTask2 myTask2;
TaskBase *baseB = &myTask2;
cout << "Name: " << baseA->name() << " Id:" << baseA->id() << endl;
cout << "Name: " << baseB->name() << " Id:" << baseB->id() << endl;
Which outputs this (with gcc 4.6):
Name: 7MyTask1 Id:0x401228
Name: 7MyTask2 Id:0x4011c0

I suggest implementing pure virtual methods for obtaining the class name and ID in the base class. The descendants would need to provide the unique names and IDs.
class TaskBase
{
public:
virtual std::string get_task_name(void) const = 0;
virtual unsigned long get_task_id(void) const = 0;
};
I took #VoidStar's suggest a step further and put the names into a (single) common class:
class TaskNames
{
protected:
static std::string get_tas1_name();
};
class Task1: public TaskBase, public TaskNames
{
//...
};

If you are following strictly standard C++, you may need to just bite the bullet and do some additional bookkeeping. Make an enum somewhere that stores all the classnames:
enum ClassID {
MYTASK1_CLASS,
MYTASK2_CLASS
};
It doesn't take that long to add a new classId when you make a new class.
I've done this before. It's sufficient for uniqueness to do what I describe above. But... if the enum values are set with a clever enough macro, you can encode the hierarchy of the classes, and implement dynamic cast and instanceof solely from the ClassID and a bitwise mask!

Related

How to return derived type?

I have a Validator class and derived classes from it;
When i'm trying to return pointer to derived class then method return base class(Validator) instead of Derived.
class Validator
{
public:
std::string m_name = "BaseValidator";
static const std::map<std::string, Validator *> validators();
static Validator *getByName(std::string &name);
};
const std::map<std::string, Validator*> Validator::validators()
{
std::map<std::string, Validator*> result;
//RequiredValidator is derived
result["required"] = new RequiredValidator();
return result;
}
Validator* Validator::getByName(std::string &name)
{
auto g_validators = Validator::validators();
auto validator = g_validators.find(name);
if(validator != g_validators.end()){
std::cout << "getByName: " << validator->second->m_name << std::endl;
return validator->second;
}else{
std::cerr << "Unknow type of validator: " << name << std::endl;
}
return nullptr;
}
//output BaseValidator but i need RequiredValidator
class RequiredValidator : public Validator
{
public:
std::string m_name = "RequiredValidator";
};
It is returning a derived instance, but since validator is a Validator*, you're looking at the m_name member of Validator, not the one of RequiredValidator.
(Despite having the same name, they are distinct variables. There are no "virtual variables".)
There are a couple of options;
You can have a virtual getName function and override it in every subclass.
Set the base m_name in derived classes, for instance by making the name a parameter of the base constructor.
Example:
class Validator
{
public:
Validator(const std::string& name = "BaseValidator") : m_name(name) {};
// ...
};
class RequiredValidator : public Validator
{
public:
RequiredValidator() : Validator("RequiredValidator") {}
// ...
};
You have declared two member variables named m_name, one in Validator and one in RequiredValidator. Other than having the same name these two variables are completely unrelated. Your compiler will probably have printed a warning about the second shadowing the first.
Which variable you access depends on the type of the variable that you are accessing it from.
For example:
RequiredValidator r;
std::cout << r.m_name << "\n"; // prints "RequiredValidator"
Validator* v = &r;
std::cout << v->m_name << "\n"; // prints "BaseValidator"
std::cout << dynamic_cast<RequiredValidator*>(v)->m_name << "\n"; // prints "RequiredValidator"
There are a couple of solutions to this. The first is to simply set the value of the BaseValidator variable in the RequiredValidator constructor:
class Validator
{
public:
std::string m_name;
Validator( const std::string& name = "BaseValidator" )
:m_name( name )
{
}
};
class RequiredValidator : public Valdiator
{
public:
RequiredValidator()
: Validator("RequiredValidator")
{}
};
The more conventional solution would be to use a virtual method instead:
class Validator
{
public:
virtual std::string getName() { return "BaseValidator"; }
};
class RequiredValidator : public Valdiator
{
public:
virtual std::string getName() override { return "RequiredValidator"; }
};

C++ (sort of) factory

I've seen a number of posts regarding C++ factories, but so far I haven't seen a solution that solves my problem. (Though I may be missing something.)
Example console app:
#include <memory>
#include <map>
#include <iostream>
using namespace std;
class ResourceManager;
/// abstract base class
class Identity
{
public:
int Id() const { return _id; }
/// make this an abstract class
virtual ~Identity() = 0 {}
protected:
Identity() { _id = _nextId++; }
private:
int _id;
static int _nextId;
};
int Identity::_nextId = int();
/// derived classes
class Component : public Identity
{
friend class ResourceManager;
public:
~Component() { }
};
class Entity : public Identity
{
friend class ResourceManager;
public:
~Entity() { }
};
class ResourceManager
{
public:
template<typename T>
T& Create()
{
auto ptr = std::make_shared<T>();
auto id = ptr->Id();
_resources[id] = std::move(ptr);
return *dynamic_pointer_cast<T>(_resources[id]);
}
private:
std::map<int, std::shared_ptr<Identity>> _resources;
};
int main(int argc, char *argv[])
{
cout << "Factory test" << endl;
ResourceManager r;
auto& e = r.Create<Entity>();
cout << "e.id = " << e.Id() << endl;
Entity e2;
cout << "e2.id = " << e2.Id() << endl;
Component c;
cout << "c.id = " << c.Id() << endl;
std::getchar();
}
I need to make sure that only ResourceManager can instantiate Entity, Component and any classes that derive from them.
I've looked and adding ResourceManager as a friend class to Identity, and making the constructors private or protected, with no success. (This could be a blind alley, or just an implementation problem on my end.)
Any suggestions?
Update and Edit
Replaced code with compilable example. Although the constructor for Identity() is protected, I can still directly instantiate derived classes.
Following should work:
friend class ResourceManager; should be in each derivated classes.
(friend is not inherited).
class ResourceManager;
/// abstract base class
class Identity
{
public:
int Id() const { return _id; }
/// make this an abstract class
virtual ~Identity() = 0;
// Forbid any copy
Identity(const Identity&) = delete;
Identity(const Identity&&) = delete;
Identity& operator = (const Identity&) = delete;
Identity& operator = (Identity&&) = delete;
protected:
Identity() { _id = _nextId++; }
private:
int _id;
static int _nextId;
};
// empty destructor
Identity::~Identity() {}
int Identity::_nextId = 0;
/// derived classes
class Component : public Identity
{
friend class ResourceManager;
public:
~Component() { }
protected:
Component() = default;
};
class Entity : public Identity
{
friend class ResourceManager;
public:
~Entity() { }
protected:
Entity() = default;
};
class ResourceManager
{
public:
template<typename T>
T& Create()
{
std::unique_ptr<T> ptr(new T);
T& res = *ptr;
_resources[ptr->Id()] = std::move(ptr);
return res;
}
/// TODO: need to make sure that resource ID is actually of type T
/// and that _resources contains ID.
template<typename T>
T* Get(int id)
{
auto it = _resources.find(id);
if (it == _resources.end()) {
return nullptr;
}
return dynamic_cast<T*>(it->second.get());
}
private:
std::map<int, std::unique_ptr<Identity>> _resources;
};
Note that since ResourceManager owns the resource I change std::shared_ptr to std::unique_ptr.
I fixed ResourceManager::Get with invalid id.
Have you tried a protected construtor?
class Identity
{
friend class ResourceManager;
public:
int Id() { return _id; }
virtual ~Identity() = 0;
protected:
Identity() {
_id = _nextId++;
}
private:
static int _nextId;
// do not forget to put "int Identity::_nextId = 0;" in a source file
};
Identity::~Identity()
{
}
But you need to repeat this pattern in every derived class. Thus making ResourceManager a friend and making the constructor private or protected.

C++ Inheritance, retrieving children's data members

I am trying to do this:
class Parameter
{
public:
Parameter(){};
~Parameter(){};
};
class Address : public Parameter
{
public:
Address(uint16_t val) : value(val){};
Address(const Address& b) : value(b.value){};
~Address(){};
private:
uint16_t value;
};
class Constant : public Parameter
{
public:
Constant(int val) : value(val){};
Constant(const Constant& b) : value(b.value){};
~Constant(){};
private:
int value;
};
How can I add set and get methods for the parent class Parameter so that when I create a Constant or Address object, I can use the parent methods to set and get the variable value?
Not sure what you meant, but here is a try:
template <typename T>
class Parameter
{
public:
const T& getValue() { return value; }
protected:
T value;
};
class Address : public Parameter<uint16_t>
{
public:
Address() { value = 2154; }
// ...
}
class Name : public Parameter<std::string>
{
public:
Name() { value = "John Doe"; }
// ...
}
Later you can do:
Address address;
Name name;
cout << name.getValue() << " lives at house no " << address.getValue();
// outputs "John Doe lives at house no 2154".
You could implement it as a pure virtual function and over ride it in the below classes?

C++ Inheritance member functions using static variables

I am trying to convert some Python classes into c++ but am having some trouble. I have a Base class which has a class (static) variable and a method which returns it. I also have a derived class which overrides the class (static) variable like so,
In Python:
class Base:
class_var = "Base"
#classmethod
def printClassVar(cls):
print cls.class_var
class Derived(Base):
class_var = "Derived"
d = Derived()
d.printClassVar()
which prints out the desired derived class variable, "Derived". Any idea how I can get the same functionality in c++? I have tried but end up getting the class variable of the Base class.
In c++
class Base
{
public:
static void printStaticVar(){cout << s_var << endl;}
static string s_var;
};
string Base::s_var = "Base";
class Derived : public Base
{
public:
static string s_var;
};
string Derived::s_var = "Derived";
void main()
{
Derived d;
d.printStaticVar();
}
Write a virtual function which returns a reference to the static member:
class Base
{
public:
void printStaticVar() {cout << get_string() << endl;}
static string s_var;
virtual string const& get_string() { return Base::s_var; }
};
string Base::s_var = "Base";
class Derived : public Base
{
public:
static string s_var;
virtual string const& get_string() { return Derived::s_var; }
};
string Derived::s_var = "Derived";
void main()
{
Derived d;
d.printStaticVar();
}
Note that printStaticVar shouldn't be static.
You could also make the string static local inside the getter:
class Base
{
public:
void printStaticVar() {cout << get_string() << endl;}
virtual string const& get_string() {
static string str = "Base";
return str;
}
};
class Derived : public Base
{
public:
virtual string const& get_string() {
static string str = "Derived";
return str;
}
};
void main()
{
Derived d;
d.printStaticVar();
}
Another possibility might be:
class Base
{
const std::string var;
public:
Base(std::string s="Base") : var(s) {}
void printVar() { std::cout << var << std::endl }
};
class Derived : public Base
{
public:
Derived(std::string s="Derived") : Base(s) {}
};

Initializing static const in a class that extends a template

Consider this pseudocode:
class Foo {
public:
virtual int getID() const = 0;
}
template<typename T>
class Blah : public Foo {
public:
T data;
static const int ID; //static ID
int getID() const { return Blah<T>::ID; } //instance returns the ID
}
class Dude : public Blah<int> {
}
int Dude::ID = 10; //I want to define Blah<int>::ID here, but how?
int receive(const Foo& foo) {
if(foo.getID() == Dude::ID) {
cout << "Received a Dude" << endl;
}
}
This piece of code fails to compile because ISO C++ does not permit the ID in the Blah template to be defined as the ID in the Dude class. I understand why because I could have multiple classes that extend a Blah<int>.
I understand if I put template<typename T> int Blah<T>::ID = 10' in the Blah<T> impl that it will work...but that isn't what I want...I want the derived class to define the ID...
Do I have to push the ID and getID() into the derived class? I guess ultimately I'm interested in some RTTI so I can process the Foo appropriately. If anyone has a better pattern, I'm all ears.
EDIT
In response to some of the comments...I would like to uniquely identify classes that derive from Foo via some ID so I can compare the runtime id of some Foo object to a specific class id.
Thanks!
Make the static int ID; private, and provide GetID in public interface, make SetID a protected interface. But that is not a good solution, because all the derived class will share the same ID, which is not what you want.
A better way should be you use the id as the base class' template parameter, then class Derived : public Base<234>{} will work.
Or add virtual const int GetID() = 0 into Base class.
I think you can simply do this:
class Dude : public Blah<int> {
}
static const int Dude_ID; //declaration!
int receive(const Foo& foo) {
if(foo.getID() == Dude::Dude_ID) {
cout << "Received a Dude" << endl;
}
}
static const int Dude::Dude_ID = 10; // definition!
Similarly, define an ID for each derived class.
Yet another way to have an ID for each class is this:
template<typename T, int ID=1>
class Blah : public Foo {
public:
int getID() const { return ID; }
}
template<int ID=10>
class Dude : public Blah<int> {
public:
int getID() const { return ID; }
}
I found this answer that does exactly what I'm after...sorry if my question was confusing.
in C++, how to use a singleton to ensure that each class has a unique integral ID?