user357269 user357269 - 3 months ago 15
C++ Question

Can I replicate inheritance with overloading?

Prelude: I have updated this question to address NicolBolas' suggestion. Please leave a constructive comment if you downvote, thank you.

I'm writing a function that takes a number (

uint
) or a flag that it's not a number. It then goes on to work with the given number or
-1
.

Here's the idea

struct Numeric {
virtual int to_int() const = 0;
};
struct NotANumber : Numeric {
int to_int () const {
return -1;
}
}
struct Number : Numeric {
const uint n;
Number (const uint n): n(n) {}
int to_int () const {
return n;
}
};


So then my function could be used as:

calculate_stuff(NotANumber());
calculate_stuff(Number(4));


My question is whether it's possible to move the
to_int
method outside of the classes, into the form of an overloaded function:

struct Numeric {};

struct NotANumber : Numeric {}

struct Number : Numeric {
const uint n;
Number (const uint n): n(n) {}
};

int Numeric_to_int (const NotANumber) {
return -1;
}

int Numeric_to_int (const Number n) {
return n.n;
}


This doesn't seem to work. Is it possible to fix this? Is the issue that overloading happens at compile time, whereas overriding is at runtime?

(I think I'm going to use
std::optional
and
value_or
for this specific problem, but I would still like to know the answer to my questions above)

Edit: sorry, I should've clarified what "doesn't work" means:

int calculate_stuff (const Numeric n) {
std::cout << Numeric_to_int(n) << std::endl;
return 0;
}


This doesn't compile:
no matching function for call to ‘Numeric_to_int(const Numeric&)’

Answer
int calculate_stuff (const Numeric n)

How could it work? You passed in a base class. By value. The compiler cannot know what derived class it used to be. In fact, since you took the base class by value, the compiler knows that n is neither of the derived classes.

C++ isn't Java; if you pass something by value, you make a copy (or move to it). And if you passed one of the derived classes, that causes slicing; you only copy the base class data. The parameter is therefore exactly what it says: an object who's dynamic type is Numeric. Exactly and only that, not one of its derived classes.

Even if you took a const Numeric &n instead, that won't help. The compiler doesn't know what type it used to be. And you can't even use dynamic_cast to convert it back, since Numeric is not a polymorphic class.

A better way to handle this is to actually use a proper variant class (optional is effectively a specialized variant).

Comments