Here is a simplified example (OnlineGDB):
#include <iostream>
using namespace std;
class Base {
public:
virtual ~Base() {}
virtual int test(Base* parent) = 0;
};
class Test : public Base {
public:
~Test() {}
int test(Base* parent) { return 10; }
int test(Test* parent) { return 20; }
};
int main(int argc, char* argv[]) {
Test* test = new Test();
Base* base = test;
cout << test->test(test) << endl; // prints 20
cout << base->test(test) << endl; // prints 10
return 0;
}
I would expect both calls to return 20
, because the argument is of type Test
, but the second call returns 10
.
I know I could do dynamic_cast<Test*>(base)->test(test)
and it works again, but in reality I have more classes that are derived from Base
. Of course I could do sth. like this:
auto test1 = dynamic_cast<Test*>(base);
if (test1) {
test1->test(test);
}
auto test2 = dynamic_cast<Test2*>(base);
if (test2) {
test2->test(test);
}
...
But for any new class derived from Base
this would need to be adjusted and there are multiple sections in the code that have to do this.
Is there any way, I can keep the base->test(test)
or sth. similar to get the "right" value based on the argument type?
CodePudding user response:
base->test(test)
base
is a pointer to Base
. Base
has exactly one class method called test()
. That's the class method that gets called. Since that class method's parameter is a Base *
, that's what test
gets converted to. This is how type conversion works in C .
base
is pointing to a base class of a derived object, that overrides that virtual method. That overridden method in the derived class, that takes a Base *
, gets called, because that's the overridden method.
The fact that the pointer, before the conversion, was pointing to Test *
is immaterial. There is no function in Base
that takes a Test *
as a parameter, the only one there takes Base *
as a parameter, so that's the one that gets called.
CodePudding user response:
When you cast a class, the most specific information is related to the type in the hierarchy you are casting it to.
Base
vtable doesn't have that overload so there's no way the compiler can know at compile time that another overload exists.
If you think about how the dynamic dispatch is implemented it's rather trivial why your code is not working and I don't see how it could.
You should provide the exact problem you are trying to solve because there could be a different solution to what you're trying to do, stated as it is it looks like an XY problem.