3

Basically what I am trying to do here is make an ID for each derived type of Shape. ( Square is 1, Circle is 2, etc.) How can I make a static member variable that has polymorphic capabilities? How would I create the getters and setters?

class Shape {
public:
    Shape() {}
    static int ID;
};

class Square : public Shape {
public:
    Square() {}

};

class Circle : public Shape {
public:
    Circle() {}

};

class Person {
public:
    int shape_type_ID
    Shape* ptr;
    Person(){}
};

int Shape::var{ 5 };

Is this a copy of this question? How to initialize `static` member polymorphically

EDIT: In my current design, each instance of Person contains a pointer ( I am not sure about the type of pointer ) that points to some Shape object. I want to restrict each Person object to only being able to reference one derived type of Shape.

E.g. Person 1’s pointer can only reference Circles, Person 2’s pointer can only reference Squares, Person 3’s pointer can only reference Triangles.

But I want 1 single Person class with 1 type of pointer ( probably Shape ). In theory that should be do-able. One of the problems is that there should be as many Person objects as there are Shape derived types (one for Square, one for Circle, one for Triangle). How do I know how many Person objects to make?

  • what exactly do you mean with "polymorphic capabilities"? `static` is rather the opposite of `virtual` – 463035818_is_not_an_ai May 13 '21 at 18:53
  • A Square object would access its own version of ID, as well as Circle object would access its own version of ID. – emptyPigeon May 13 '21 at 18:55
  • 3
    You can have a `public virtual int typeId() const;` member and manually assign an ID to each derived type, but this is not a good design pattern. This is a difficult task to automate because polymorphism is designed to be extensible. No single derived type can be sure that it knows about all the other derived types. As there is no easy way to enumerate the types automatically, at some level, you end up having enumerate them yourself manually. – François Andrieux May 13 '21 at 18:56
  • 4
    Ususally, if your design cares about uniquely identifying the concrete type from a base class pointer or reference, it indicates that it is probably using polymorphism incorrectly. There are rare cases where it is correct or required, but usually it indicates a mistake. Consider instead whether you can change your design to not need such an `ID`. – François Andrieux May 13 '21 at 18:58
  • what do you actually need the `ID` for? Diffferent types are different types, often thats already sufficient as "ID". On the other hand with polymorphism you would try to not distinguish the different subtypes. – 463035818_is_not_an_ai May 13 '21 at 18:59
  • @emptyPigeon Note that the term _Static Polymorphism_ usually means [something totally different](https://stackoverflow.com/questions/19062733/what-is-the-motivation-behind-static-polymorphism-in-c). Looks what you actually want is a per class _Singleton_, which provides one, or more specific regular virtual interfaces e.g. for a _Factory_. – πάντα ῥεῖ May 13 '21 at 19:00
  • Its basically just to avoid having to make a static int ID in every single subtype of Shape. I can see that this is not a very good way of designing it but I am having trouble finding other ways of going about it with my situation – emptyPigeon May 13 '21 at 19:11
  • Can you give an example of how you would like to use such a thing? That would make it more clear what you're asking for. – Miles Budnek May 13 '21 at 19:21
  • What this comes down to is we can tell you how to get what you want, Largest Prime does this in their answer, but what you want is often a sign that you're headed in a bad direction. If you expand on your use case perhaps we can prevent you from walking blindly into a morass in the near future. – user4581301 May 13 '21 at 19:27
  • @emptyPigeon "*I am having trouble finding other ways of going about it with my situation*" - it would help to know what your situation actually is, and why you think this was the way to solve it. Sounds like an possible [XY problem](https://meta.stackexchange.com/questions/66377/). – Remy Lebeau May 13 '21 at 20:00
  • @RemyLebeau I think you are right, I edited the post. Maybe that gives more clarity – emptyPigeon May 14 '21 at 14:55
  • @emptyPigeon your edit is basically asking a completely different question that has nothing to do with IDs. In any case, when I read your pointer requirement for the `Person` class, the first thing that comes to mind is to make `Person` a `template` class. But that doesn't fit well with your "1 single Person class" requirement. So you will likely need multiple `Person`-derived classes whose constructors validate your restriction at runtime. Hard to say since you did not describe how `Person` will be used. – Remy Lebeau May 14 '21 at 15:25
  • @RemyLebeau If Shape derived classes were ID'd then you could make an array of those ID's. Therefore you would know how long to make a Person array and you could then assign each Person an ID. Sorry, should have put that in – emptyPigeon May 14 '21 at 15:34
  • @emptyPigeon Using an `enum` would probably make more sense in that case. Using dynamically generated IDs only makes sense if you want users to be able to write their own classes and register them with your code at runtime. – Remy Lebeau May 14 '21 at 16:57

2 Answers2

3

When you want polymorphism you should use virtual methods, not static members.

class Shape {
public:
    virtual int ID(){ return 0; }
    virtual ~Shape(){}
};

class Square : public Shape {
public:
    virtual int ID() override { return 1;}
};

class Circle : public Shape {
public:
    virtual int ID() override { return 2; }
};
463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
1

you can do something like this if you really need to, but I suggest just making a constructor in base that accepts an id and pass it from the childs to the parent

int getNextId()
{
    static int lastId{0};
    return lastId++;
}

template<typename T>
int getDerivedId()
{
    static int id{getNextId()};
    return id;
}

struct Base {
};

struct Derived0 final : Base {
};

struct Derived1 final : Base {
};

int main() {
    return !(getDerivedId<Derived0>() == 0 && getDerivedId<Derived1>() == 1);
}
Yamahari
  • 1,926
  • 9
  • 25