Is it possible to declare a virtual static constant value in a C++ class?

11,436

A static method cannot be virtual, and no data members can be virtual.

But you can hide static fields in derived classes and use a virtual method to return them.

class A
{
public:
    static const int ID = 0;
    virtual int getID() { return A::ID; }
};
class B : A
{
public:
    static const int ID = 1;
    virtual int getID() { return B::ID; }
};

Alternative:

class A
{
public:
    A(int id = 0) : ID(id) {}
    const int ID;
    getID() { return ID; }
};
class B : public A
{
public:
    B() : A(1) {}
};
Share:
11,436

Related videos on Youtube

Siska Ádám
Author by

Siska Ádám

Updated on June 03, 2022

Comments

  • Siska Ádám
    Siska Ádám about 2 years

    I'd like to have a base class that has a constant field (like an unique ID associated with the class that can't be modified after compile time). So far the static const declaration would be just fine. Now, I'd like to inherit this base class and make sure that the children of this class do have the same field, but with their own values. How can I do this?

    Let's say, I'd like to have a base class called Base with an ID field that holds the int value of 0. Then, I'd like to have the classes A, B and C, all of them being public children of Base and I'd like to make sure that these children would also have the ID fields with the respective values of 1, 2 and 3 (by 'making sure', I mean something like getting a compiler error if they don't have a ID explicitly declared).

    If I could manage to build this scenario, my expectation would be that asking for the ID field of a Base* pointer, I should get different values depending whether the pointer was created as new A(), new B() or new C().

    My guess would be to declare ID as virtual static const, which of course doesn't make sense and gives a compiler error.

    But then what can I do to achieve the described result? (The only thing that I could imagine would be to declare ID as a virtual function returning an integer and then hard-code the value into the function body, but I'm looking for something more elegant.)

    Thank you in advance!

    • Mahesh
      Mahesh about 12 years
      Polymorphism works only for member functions and is not valid for data members.
    • 56ka
      56ka about 8 years
      I have written an alternative based on templates : stackoverflow.com/a/36797199/1529139
  • Siska Ádám
    Siska Ádám about 12 years
    Yes, this is the only solution that I knew so far. But is there no way to solve this in a more elegant/simple way? Or if this is the only way to go, then my question is rather: what is the reason why the virtual inheritance that works with functions will not work with data members? I understand why actually static virtual wouldn't make sense, but I can't really understand why, let's say, a simple virtual const int field wouldn't make sense...
  • Luchian Grigore
    Luchian Grigore about 12 years
    @SiskaÁdám because polymorphic behavior is not defined for data members. It's the way the language is designed. And it's a good thing IMO.
  • Luchian Grigore
    Luchian Grigore about 12 years
    @SiskaÁdám I posted an alternative, but I still find the first one better.
  • Damon
    Damon about 12 years
    What's crazy, in C++11 you can even make the virtual function constexpr. Which is not terribly useful, since it will fail to compile when you actually make use of virtual inheritance. Though f<A().getID()>(); actually compiles, given f is a template function taking an integer...
  • Siska Ádám
    Siska Ádám about 12 years
    @LuchianGrigore I see. This was the point what I missed probably. However, could you please clarify in a few words why this is a good thing? I just can't think of an example where data member polymorphism could lead to more trouble than function polymorphism. Thanks, Ádám
  • Luchian Grigore
    Luchian Grigore about 12 years
    @SiskaÁdám usually members denote state. If you use inheritance, you assume that class B is-a class A, and has all its members, plus others, but it has A's members. Not override. They can be different, but not overriden. I can't find an example where this would be helpful other than the one you posted, which is probably not a good design - there are other mechanism that can be used to determine the run-time type of an object (see RTTI). This ID thing seems like a hack. Maybe it's just me, because I'm not used to the concept of data member polymorphism, but I honestly can't see any utility.
  • Siska Ádám
    Siska Ádám about 12 years
    @LuchianGrigore Thanks for the help. Actually the ID thing was just a dummy example. In my actual scenario, I have an abstract base class for drawing commands, and the inherited classes will be the actual drawing commands. For efficiency reasons, the coordinates used by the drawing commands are stored separately in an array (having all points one after the other in a memory block I can make transformations faster) and the drawing commands just hold a pointer to their data. The inherited constant what I was dreaming of is the actual number of points required by the different drawing commands.
  • Luchian Grigore
    Luchian Grigore about 12 years
    @SiskaÁdám I think if you need something like this, your design is faulty. But that would be to broad of a question for SO. I suggest you read Head First Design Patterns (no affiliation).
  • David Rodríguez - dribeas
    David Rodríguez - dribeas about 12 years
    @Damon: Do you mean virtual inheritance or plain inheritance and the use of a virtual function? Those are completely different. At any rate, constexpr on a virtual function makes sense for those cases where dynamic dispatch is disabled (either the final overrider is known at the place of call at compile time or dynamic dispatch is explicitly disabled)
  • Damon
    Damon about 12 years
    @DavidRodríguez-dribeas: The former is meant, e.g. A a; [...] f<a.getID()>;. This will (for rather obvious reason) fail to compile (it is not provably a compiletime constant, after all). It's crazy that you can still make the virtual function constexpr though, and it really works as intended too, with static dispatch (e.g. f<A().getID()>;).
  • David Rodríguez - dribeas
    David Rodríguez - dribeas about 12 years
    @Damon: So that is not the former, but the latter: plain inheritance and virtual functions (Virtual inheritance is a whole different beast). AFAIK, your example should compile. Because a is in the scope where it is accessed (i.e. the call to getID() is not performed through a reference/pointer) that does not require dynamic dispatch, which means that the appropriate override can be detected at compile time and that would allow inlining of the function in C++03, which in turn means that there should be no issue in using that particular call as a constexpr.
  • Meta
    Meta almost 8 years
    Actually, the standard explicitly forbids 'constexpr' from being used on virtual methods. Some compilers may still allow it, but it is not standard.