0

I had functions that were supposed to take an ID number (an int), but I noticed that I was accidentally passing the ID numbers of different things, which broke my program. So I tried to do something like the following to make it type-safe:

struct Number
{
    int ID;
    int operator =(const int& rhs) { ID = rhs; }
}

struct DogID : Number { }
struct CatID : Number { }

void functionTakingDogID(DogID ID) { }
void functionTakingCatID(CatID ID) { }

int main()
{
     DogID dogID;
     dogID = 5; // But the = operator overload isn't inherited
}

The only reason I created classes to hold the numbers was to prevent passing the wrong ID number. And the reason I used inheritance from Number is so that any classes like Dog and Cat could be treated like an ID number (assigned to).

What's the cleanest way to be able to send ID numbers to a function but ensure that you're sending the right IDs to it? I'm not sure enum classes are an option because IDs are given at runtime.

Also I found out that:

All overloaded operators except assignment (operator=) are inherited by derived classes.

Is the reason for why the operator = is the only operator overload not inherited that it was considered too risky given that derived classes may have extra members?

Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • `BOOST_STRONG_TYPEDEF` works for primitives. I was just reaing about it, will find a dupe in a second – 463035818_is_not_an_ai Mar 27 '20 at 12:03
  • this https://stackoverflow.com/questions/34287842/strongly-typed-using-and-typedef or https://stackoverflow.com/questions/28916627/strong-typedefs – 463035818_is_not_an_ai Mar 27 '20 at 12:04
  • 2
    Do you need `operator=`? Perhaps you can pass ID in constructor of each derived class and verify it there. – Yksisarvinen Mar 27 '20 at 12:07
  • @Yksisarvinen Strictly the operator = overload isn't necessary, I could just instead do dogID.ID = 5 instead of dogID = 5. I just overloaded it so I could treat the dogID as a number as I would have before making it type-safe. – Zebrafish Mar 27 '20 at 12:09

1 Answers1

1

What you can do is to use a Tag for your Number

template<typename Tag>
struct Number
{
    int ID;
    Number &operator =(int rhs) { ID = rhs; return *this;}
};

using DogID = Number<struct DogIdTag>;
using CatID = Number<struct CatIdTag>;

int main()
{
     DogID dogID;
     dogID = 5; // But the = operator overload isn't inherited
}

The idea is to give a kind of tag to your Number class. Doing so will ensure that Number<Tag1> is not of the same type of Number<Tag2>

However, in a general architecture, I would not recommand using an operator= on int, because you lose a bit of type safety.

For example, in this code:

void f(int accountId) {DogId id = accountId;}

It is not that good and I recommand you to only use such a thing :

DogId id = DogId{anInteger}

and to continue to use the template Number class we saw above

Note

  1. Your operator= function must return a reference on the current object, not a int.
  2. It is dangerous to not return something from a function that need to return something. In C it is dangerous, In C++ it is an undefined behaviour.
Antoine Morrier
  • 3,930
  • 16
  • 37
  • Thank you, this solution seems good. And there's no need to use external libraries like boost or anything. – Zebrafish Mar 27 '20 at 13:12