Jump to content

  • Log In with Google      Sign In   
  • Create Account

#Actual_for_science

Posted 09 March 2013 - 10:55 AM

Of course, you could go all fancy and generate these unique class IDs automatically using template magic! *Applause*

You want to write your classes, and you don't want to manually assign a unique id to each one of them. Luckily you can make your compiler do the class counting. First you'll need a Base class with a static variable that counts your classes:

class Base {

public:
  // Virtual function to get the unique class id (special number)
  virtual int getUniqueClassId(void) const = 0;
  
private:
  // This static variable counts your classes (it exists exactly once in the entire program)
  static int uid_count;
};


Next you'll need a "SpecialBase" class. A class that exists between your actual class and your base class. Via template magic, this class will automatically do the counting for you. In order for this to work, we use a basic template feature. Your compiler does not consider a class with template parameter a single class. SpecialBase<A> and SpecialBase<B> are considered completely separate classes that just happen to use the same code. So if your SpecialBase class were to have a static variable, that variable would be created once for each specialized class you use in your program.

You can use that to create the following:

template <class SpecialClass>
class SpecialBase : public Base {

public:
  // This function gives you the unique class id of an object
  int getUniqueClassId(void) const { return getUniqueClassIdStatic(); }

  // This function gives you the unique class id
  static int getUniqueClassIdStatic(void) {
    if (uid >= Base::uid_count)   // If the unique id is invalid...
      uid = Base::uid_count++;    // ... set the id and increment uid_count
    return uid;
  }
  
private:
// This static variable is your classes unique id (it exists once for
// each of your classes)
  static int uid;
};

// Initialize the unique id to an invalid value
template <class SpecialClass> int SpecialBase<SpecialClass>::uid = INT_MAX;

There now exists a static uid variable for each variation of the SpecialBase class and they are all initialized to INT_MAX.
The first time anyone asks for the unique class id (by calling getUniqueClassId(), or getUniqueClassIdStatic(), a new unique id is created, based on the current uid_count we defined earlier in the Base class. The counter of the Base class (the one that exists only once in the entire program) is then incremented. Therefore, the next class that asks will automatically get a new and unique id. Keep in mind though: The order the ids are given out is based on the order they are first queried at runtime (see below for more info).

Oh and in some .cpp file somewhere you'll obviously want to initialize uid_count to zero:

#include "Base.h"
// Initialize the unique id count to 0
int Base::uid_count = 0;


How is this actually used?

// Define your classes (yep, that's all)
class A : public SpecialBase<A> { };
class B : public SpecialBase<B> { };
class C : public SpecialBase<C> { };

// Determine an object's class:
C obj;
if (obj.getUniqueId() == A::getUniqueIdStatic()) // false
  std::cout << "Object is of class A";
if (obj.getUniqueId() == B::getUniqueIdStatic()) // false
  std::cout << "Object is of class B"; 
if (obj.getUniqueId() == C::getUniqueIdStatic()) // true
  std::cout << "Object is of class C";


Note that you won't have to touch the getUniqueClassId() functions in your own code. All you have to do, is make sure that your class inherits from SpecialBase and that you use your own classes name as the template parameter. (Thus ensuring that no two classes inherit from the same specialization of SpecialBase)

Oh, but I wanted control over which class gets which index, or at least some kind of order!
Just forcibly query some ids, before doing anything else...

int main(void) {
  A::getUniqueClassIdStatic(); // A is assigned 0
  C::getUniqueClassIdStatic(); // C is assigned 1
  B::getUniqueClassIdStatic(); // B is assigned 2
  F::getUniqueClassIdStatic(); // F is assigned 3

  // your stuff...
}


I hope this helps! Depending on your project, this may be a little much. It just happened to be what I was working on recently. (And you could probably take this even further by using enums instead of static variables... but I'll just doubt that you have several million classes for these few static vars to create any performance issue)


#2_for_science

Posted 09 March 2013 - 09:28 AM

Of course, you could go all fancy and generate these unique class IDs automatically using template magic! *Applause*

You want to write your classes, and you don't want to manually assign a unique id to each one of them. Luckily you can make your compiler do the class counting. First you'll need a Base class with a static variable that counts your classes:

class Base {

public:
  // Virtual function to get the unique class id (special number)
  virtual int getUniqueClassId(void) const = 0;
  
private:
  // This static variable counts your classes (it exists exactly once in the entire program)
  static int uid_count;
};


Next you'll need a "SpecialBase" class. A class that exists between your actual class and your base class. Via template magic, this class will automatically do the counting for you. In order for this to work, we use a basic template feature. Your compiler does not consider a class with template parameter a single class. SpecialBase<A> and SpecialBase<B> are considered completely separate classes that just happen to use the same code. So if your SpecialBase class were to have a static variable, that variable would be created for each specialized class you use in your program.

You can use that to create the following:

template <class SpecialClass>
class SpecialBase : public Base {

public:
  // This function gives you the unique class id of an object
  int getUniqueClassId(void) const { return getUniqueClassIdStatic(); }

  // This function gives you the unique class id
  static int getUniqueClassIdStatic(void) {
    if (uid >= Base::uid_count)   // If the unique id is invalid...
      uid = Base::uid_count++;    // ... set the id and increment uid_count
    return uid;
  }
  
private:
// This static variable is your classes unique id (it exists once for
// each of your classes)
  static int uid;
};

// Initialize the unique id to an invalid value
template <class SpecialClass> int SpecialBase<SpecialClass>::uid = INT_MAX;

There now exists a static uid variable for each variation of the SpecialBase class and they are all initialized to INT_MAX.
The first time anyone asks for the unique class id (by calling getUniqueClassId(), or getUniqueClassIdStatic(), a new unique id is created, based on the current uid_count we defined earlier in the Base class. The counter of the Base class (the one that exists only once in the entire program) is then incremented. Therefore, the next class that asks will automatically get a new and unique id. Keep in mind though: The order the ids are given out is based on the order they are first queried (see below for more info).

Oh and in some .cpp file somewhere you'll obviously want to initialize uid_count to zero:

#include "Base.h"
// Initialize the unique id count to 0
int Base::uid_count = 0;


How is this actually used?

// Define your classes (yep, that's all)
class A : public SpecialBase<A> { };
class B : public SpecialBase<B> { };
class C : public SpecialBase<C> { };

// Determine an object's class:
C obj;
if (obj.getUniqueId() == A::getUniqueIdStatic()) // false
  std::cout << "Object is of class A";
if (obj.getUniqueId() == B::getUniqueIdStatic()) // false
  std::cout << "Object is of class B"; 
if (obj.getUniqueId() == C::getUniqueIdStatic()) // true
  std::cout << "Object is of class C";


Note that you won't have to touch the getUniqueClassId() functions in your own code. All you do is make sure that your class inherits from SpecialBase and that you use your own classes name as the template parameter.

Oh, but I wanted control over which class gets which index, or at least some kind of order!
Just forcibly query some ids, before doing anything else...

int main(void) {
  A::getUniqueClassIdStatic(); // A is assigned 0
  C::getUniqueClassIdStatic(); // C is assigned 1
  B::getUniqueClassIdStatic(); // B is assigned 2
  F::getUniqueClassIdStatic(); // F is assigned 3

  // your stuff...
}


I hope this helps! Depending on your project, this may be a little much. It just happened to be what I was working on recently. (And you could probably take this even further by using enums instead of static variables... but I'll just doubt that you have several million classes for these few static vars to create any performance issue)


#1_for_science

Posted 09 March 2013 - 09:19 AM

Of course, you could go all fancy and generate these unique class IDs automatically using template magic! *Applause*

You want to write your classes, and you don't want to manually assign a unique id to each one of them. Luckily you can make your compiler do the class counting. First you'll need a Base class with a static variable that counts your classes:
class Base {

public:
  // Virtual function to get the unique class id (special number)
  virtual int getUniqueClassId(void) const = 0;
  
private:
  // This static variable counts your classes (it exists exactly once in the entire program)
  static int uid_count;
};
.
Next you'll need a "SpecialBase" class. A class that exists between your actual class and your base class. Via template magic, this class will automatically do the counting for you. In order for this to work, we use a basic template feature. Your compiler does not consider a class with template parameter a single class. SpecialBase<A> and SpecialBase<B> are considered completely separate classes that just happen to use the same code. So if your SpecialBase class were to have a static variable, that variable would be created for each specialized class you use in your program.

You can use that to create the following:
template <class SpecialClass>
class SpecialBase : public Base {

public:
  // This function gives you the unique class id of an object
  int getUniqueClassId(void) const { return getUniqueClassIdStatic(); }

  // This function gives you the unique class id
  static int getUniqueClassIdStatic(void) {
    if (uid >= Base::uid_count)   // If the unique id is invalid...
      uid = Base::uid_count++;    // ... set the id and increment uid_count
    return uid;
  }
  
private:
// This static variable is your classes unique id (it exists once for
// each of your classes)
  static int uid;
};

// Initialize the unique id to an invalid value
template <class SpecialClass> int SpecialBase<SpecialClass>::uid = INT_MAX;
There now exists a static uid variable for each variation of the SpecialBase class and they are all initialized to INT_MAX.
The first time anyone asks for the unique class id (by calling getUniqueClassId(), or getUniqueClassIdStatic(), a new unique id is created, based on the current uid_count we defined earlier in the Base class. The counter of the Base class (the one that exists only once in the entire program) is then incremented. Therefore, the next class that asks will automatically get a new and unique id. Keep in mind though: The order the ids are given out is based on the order they are first queried (see below for more info).

Oh and in some .cpp file somewhere you'll obviously want to initialize uid_count to zero:
#include "Base.h"
// Initialize the unique id count to 0
int Base::uid_count = 0;
.
How is this actually used?
// Define your classes (yep, that's all)
class A : public SpecialBase<A> { };
class B : public SpecialBase<B> { };
class C : public SpecialBase<C> { };

// Determine an object's class:
C obj;
if (obj.getUniqueId() == A::getUniqueIdStatic()) // false
  std::cout << "Object is of class A";
if (obj.getUniqueId() == B::getUniqueIdStatic()) // false
  std::cout << "Object is of class B"; 
if (obj.getUniqueId() == C::getUniqueIdStatic()) // true
  std::cout << "Object is of class C";
.
Note that you won't have to touch the getUniqueClassId() functions in your own code. All you do is make sure that your class inherits from SpecialBase and that you use your own classes name as the template parameter.

Oh, but I wanted control over which class gets which index, or at least some kind of order!
Just forcibly query some ids, before doing anything else...
int main(void) {
  A::getUniqueClassIdStatic(); // A is assigned 0
  C::getUniqueClassIdStatic(); // C is assigned 1
  B::getUniqueClassIdStatic(); // B is assigned 2
  F::getUniqueClassIdStatic(); // F is assigned 3

  // your stuff...
}
.
I hope this helps! Depending on your project, this may be a little much. It just happened to be what I was working on recently.

PARTNERS