1

I need to assign unique integer value to each descendant of class Base that should be accessible by using pointer to those classes or its typenames.

I implemented it such way

class Base {
public:
  int idCompType = InvalidCompType;
  virtual int getCompType() = 0;
}

then in each descendant of base I should declare idCompType (for templates) and override getCompType (for pointers):

class Real1: public Base {
public:
  int idCompType = 1;
  int getCompType() override { return idCompType; }
}

now I can find comp type from pointer to base

Base *comp = getComp(...);
std::cout << comp->getCompType();

or using typename in template:

template <typename T>
int getType() {
  return T::idCompType;
}

Is there a way to make it even simpler without double declaration idCompType and getCompType() in each descendant class? In Object Pascal I achieved this using virtual static methods, but their are not allowed in C++..

PS: the question is not about virtual static methods - virtual static method is just the one of the possible solutions and the way my problem was solved in other language.

Roman Kolesnikov
  • 11,777
  • 11
  • 44
  • 67
  • possible duplicate of [C++ static virtual members?](http://stackoverflow.com/questions/1820477/c-static-virtual-members) – Andrew Cheong Mar 16 '15 at 05:12
  • 1
    Are you aware of `typeid` & associated machinery, such as `std::type_index`? If this is about serialization, look up the serialization support in the Boost library. – Cheers and hth. - Alf Mar 16 '15 at 05:15

3 Answers3

0

My recommendation:

Changes to Base:

class Base {
   public:

      virtual int getCompType() = 0;

   protected:

      static int getNextCompType()
      {
         static int nextType = 0;
         return ++nextType;
      }
 };

Changes to the derived class:

class Real1: public Base {
   public:
  static int getCompTypeImpl()
  {
     static int myType = Base::getNextCompType();
     return myType;
  }

  int getCompType() override
  {
     return getCompTypeImpl();
  }
};

Here's a working program:

#include <iostream>

class Base {
   public:

      virtual int getCompType() = 0;

   protected:

      static int getNextCompType()
      {
         static int nextType = 0;
         return ++nextType;
      }
 };

class Real1: public Base {
   public:

      static int getCompTypeImpl()
      {
         static int myType = Base::getNextCompType();
         return myType;
      }

      int getCompType() override
      {
         return getCompTypeImpl();
      }
};

class Real2: public Base {
   public:
      static int getCompTypeImpl()
      {
         static int myType = Base::getNextCompType();
         return myType;
      }

      int getCompType() override
      {
         return getCompTypeImpl();
      }
};

template <typename T> int getCompType()
{
   return T::getCompTypeImpl();
}

int main()
{
   Real1 v1;
   Real2 v2;

   std::cout << v1.getCompType() << std::endl;
   std::cout << v2.getCompType() << std::endl;

   std::cout << getCompType<Real1>() << std::endl;
   std::cout << getCompType<Real2>() << std::endl;
};

Output:

1
2
1
2
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • Thank you for you answer but here I can see the same double declaration of static and virtual methods. You add automatic id generation.. but I do not need it - my ids saved in files and I need manually adjust them – Roman Kolesnikov Mar 16 '15 at 05:40
  • @Rem, you need the static functions for the function template and the virtual functions for using it through base class pointers and references. Can't get both functionality using one set of functions. – R Sahu Mar 16 '15 at 05:42
  • This will only work if he creates exactly one instance of each derived class. – user207421 Mar 16 '15 at 05:45
  • hm... In such a retrograde language as Delphi I certainly can and could do it 20 years ago.. It's a very strange thing that I can't do it in modern C++14 – Roman Kolesnikov Mar 16 '15 at 05:46
  • @EJP, not really. `static int myType = Base::getNextCompType();` in Impl() function makes sure the same type is returned even if more than 1 instance is created for each derived class. – Jagannath Mar 16 '15 at 07:00
0

Here is a slight variant of @Sahu's version. Instead of implementing the same getCompTypeImpl() in every derived class, put it in Base class.

template<typename T>
static int getCompTypeImpl()
{
    return getNextCompType<T>();
}   

Modify getNextCompType() to

template<typename T>
static int getNextCompType()
{
    auto iter = m_table.find(std::type_index(typeid(T)));
    if (iter != m_table.end())
    {
        return iter->second;
    }
    else
    {
        m_table.insert(std::make_pair(std::type_index(typeid(T)), ++nextType));
        return nextType;
    }
}   

And finally introduce 2 new static data members.

private:
    static std::map<std::type_index, int> m_table;
    static int nextType;

Please find the full code here.

Admittedly this introduces 2 new static members and does a bit more work
than the original version from Sahu. But, this removes the burden of implementing the methods in
all the derived classes.

Jagannath
  • 3,995
  • 26
  • 30
0

Yet another variation of @R Sahu's answer to eliminate duplication of code in the derived classes:

#include <iostream>

class Base {
   public:
      virtual int getCompType() const = 0;

      template <typename T>
      static int getCompTypeOf()
      {
         static int compType = getNextCompType();
         return compType;
      }

   private:
      static int getNextCompType()
      {
         static int nextType = 0;
         return ++nextType;
      }
 };

template <typename Derived, typename DeriveFrom = Base>
class TypeAssigner : DeriveFrom {
   public:
      int getCompType() const override
      {
         return Base::getCompTypeOf<Derived>();
      }
};

class Real1: public TypeAssigner<Real1> {};

class Real2: public TypeAssigner<Real2> {};

class Real3 : public TypeAssigner<Real3, Real2> {};

int main()
{
   Real1 v1;
   Real2 v2;
   Real3 v3;

   std::cout << v1.getCompType() << '\n';
   std::cout << v2.getCompType() << '\n';
   std::cout << v3.getCompType() << '\n';

   std::cout << Base::getCompTypeOf<Real1>() << '\n';
   std::cout << Base::getCompTypeOf<Real2>() << '\n';
   std::cout << Base::getCompTypeOf<Real3>() << '\n';
};
Casey
  • 41,449
  • 7
  • 95
  • 125