-3

I am trying to overload a virtual function, like this:

#include<iostream>
#include<string>
using std::cout;
using std::endl;
using std::string;
class Base{
    public:
        virtual void show(int x){
            cout << "Showing int as Base: " << x << endl;
        }
};
class Derived : public Base{
    public:
        using Base::show;
        virtual void show(string s){
            cout << "Showing string as Derived: " << s << endl;
        }
};
int main(){
    Derived x;
    Base& ref = x;
    ref.show(3);
    ref.show(string("hi")/*in case the compiler refuses to implicitly convert const char* to std::string*/);
}

However, GCC complains error: cannot convert 'std::string' {aka 'std::__cxx11::basic_string<char>'} to 'int', and says note: initializing argument 1 of 'virtual void Base::show(int)'

It seems like gcc just ignored the Derived's overload of show.

I suspect that overloading together with polymorphism is just a BIT too much to handle for the compiler, since that would require storing the type information in the vtable as well, which MAY be not possible.
But then, what should I do to mimic this behaviour?

This worked:

#include<iostream>
#include<string>
#include<any>
using std::cout;
using std::endl;
using std::string;
using std::any;
using std::any_cast;
class Base{
    public:
        virtual void show(int x){
            cout << "Showing int as Base: " << x << endl;
        }
        virtual void show(any x) = 0;
};
class Derived : public Base{
    public:
        using Base::show;
        virtual void show(any s) override{
            if(s.type() != typeid(std::string)){
                if(s.type() != typeid(int)){
                    throw "SOME_ERROR_INDICATING_INVALID_FUNCTION_CALL";
                }
                Base::show(any_cast<int>(s));
                return;
            }
            cout << "Showing string as Derived: " << any_cast<string>(s) << endl;
        }
};
int main(){
    Derived x;
    Base& ref = x;
    ref.show(3);
    ref.show(string("hi")/*invokes show(any) override */);
}

but it seems really stupid. Is there any other workaround?

EDIT: adding virtual void show(string x)=0; to base is NOT desireable. This is just a MRE, and in the real program I have lots of derived classes, and I don't want to add a pure virtual function in Base for each of those customizations.

00001H
  • 22
  • 1
  • 7
  • 2
    `Base` doesn't know anything about `virtual void show(string s)` from `Derived`. – Retired Ninja Jan 07 '23 at 06:14
  • Add a declaration for `virtual void show(string s);` inside base class. – Jason Jan 07 '23 at 06:16
  • the parameters of a function are part of its signature - different parameters, different signature, different functions – Neil Butterworth Jan 07 '23 at 06:16
  • 2
    *"It seems like gcc just ignored the `Derived`'s overload of show."* -- well, yeah. You told gcc to ignore the definition of `Derived` (by assigning `x` to a `Base&`), and gcc did exactly what you said to do. Why did you expect something different? – JaMiT Jan 07 '23 at 06:29
  • @JaMiT Hey,& means polymprohism! – 00001H Jan 07 '23 at 07:14
  • @JasonLiam Yeah, probably I didn't make it clear, but it is undesireable since I am going to have a LOT of derived classes and don't want to make a pure virtual function in Base fore each of those. – 00001H Jan 07 '23 at 07:14
  • It doesn't work that way. Only way without `std::any` will be something similar, for example `std::variant`. What wrong with `std::any` version anyway? – sklott Jan 07 '23 at 08:12
  • @00001H your edit doesn't make any sense in regards to the question. Your question isn't about overloading but about polymorphism. If this is not what you wanted to achieve in the first place - then you have a big design problem. – Milan Š. Jan 07 '23 at 10:41
  • It is not possible to "overload" a function within a derived class, and then be able to use that additional overload in the base class. The base class has no knowledge of the additional overload so, given only a reference to base, that additional overload cannot be used. That is the way things are *designed* in C++. – Peter Jan 07 '23 at 13:34
  • @00001H *"Hey,& means polymprohism"* -- no, it does not. That `&` means "reference", which helps with polymorphism but is not restricted to polymorphism. In your context, `Base` basically means "hey compiler, forget about any derived classes and treat this thing as a `Base` object", while the `&` adds on "but don't change the object". Hence the compiler treated the thing as a `Base` object, with the possibility of polymorphic behavior (if `Derived` were to define its own version of `void show(int)`). – JaMiT Jan 07 '23 at 14:06
  • *"I don't want to add a pure virtual function in `Base` for each of those customizations"* -- Good. Next step: recognize that this means [your design is flawed](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). You might want to review [this principle of polymorphic design](https://stackoverflow.com/questions/56860/what-is-an-example-of-the-liskov-substitution-principle). – JaMiT Jan 07 '23 at 14:14
  • @JaMiT Ok, here's the thing: I'm trying to implement a intepreter, and I have a `Class` type that has `construct(scope,args)` but also a `class StringType : public Class` that also has a `construct(std::wstring)` function. And no, it's not static. I mean `const StringType StringClass{};` and `StringClass.construct(xxx)`. And do note they return an `Object`, and that the `StringClass` HAS NO STATE. It's basically using "an instance as a class" – 00001H Jan 08 '23 at 03:36
  • @JaMiT I know what you're thinking, JUST USE A STATIC METHOD AND A CLASS! NO! This doesn't work, because I'll need to pass around a `Class` object, and *invoke the constructor with polymorphism*, AFAIK I cannot pass C++ classes around, because C++ is not Java and has no reflection(save `typeid`) – 00001H Jan 08 '23 at 03:38
  • @00001H *"I know what you're thinking,"* -- No you don't. My thoughts are more along the lines of "what are you talking about?" – JaMiT Jan 09 '23 at 06:01
  • @JaMiT Okay, here: I'm trying to make sort of a "stateless singleton", or, in other words, "A Buncha Functions", but I'm just using classes here because C++ won't let me pass around a `vector` of functions with different signatures. See, I want to ensure some function(say, `greet()`), has *at least* the implementation I wanted, but can also have more overloads. For example, the "subclasses" MUST HAVE `greet()` and `greet(Person)`, but I also want to have a `greet(Alien)` for, say, the subclass `UniverseGreeter`. – 00001H Jan 10 '23 at 14:00
  • @JaMiT So TWO use cases: Either have a `Greeter` that MAY be a `UniverseGreeter`, which supports SOME `greet()`, and only use that. The must-be-supported `greet()` function has different effects depending on the actual class. Or, have a variable of a specific greeter type, and use its special greeting. e.g. `AlienGreeterSingleton.greet(alienFriend)` – 00001H Jan 10 '23 at 14:05

1 Answers1

1

The problem is that you're calling show through a reference to a base object while passing a std::string as an argument but the base class doesn't have any such method so this call can't succeed.

To solve this you can add a declaration for virtual void show(string s) =0; inside the base class.

class Base{
    public:
        virtual void show(int x){
            cout << "Showing int as Base: " << x << endl;
        }
        //added this declaration for making it pure virtual
        virtual void show(string s)=0;
};
Jason
  • 36,170
  • 5
  • 26
  • 60
  • Sorry I didn't make it clear, see the EDIT in the question: I do not want this workaround if I have a LOT of subclasses. – 00001H Jan 07 '23 at 07:17
  • 3
    What workaround? This isn't a workaround, this is how polymorphism works. – Milan Š. Jan 07 '23 at 10:39
  • This is a workaround to the PROBLEM, and NOT a workaround to polymorphism. I'm not forced to use polymorphism anyway. – 00001H Jan 08 '23 at 03:40
  • Also you mean this is how polymorphism in C++ works, because it's not the case in other languages w/ duck typing that has polymorphism that does not depend on inheritance or anything. E.g. `Python` – 00001H Jan 10 '23 at 14:06