How is my method call resolved? - c++

Please definitively explain what the method resolution rules are in the following case. I have an idea, based on the behavior of the code, but would like clarification.
Based on "The const-ness of the calling object determines which version of MyArray::Get() will be invoked and thus whether or not the caller is given a reference with which he can manipulate or only observe the private data in the object. The two methods technically have different signatures because their "this" pointers have different types, allowing the compiler to choose the right one" from wikipedia const correctness, I would conclude that my example should be a case of method overloading, not method overriding (since a const method and a non-const method have two different signatures).
class Base
{
public:
void test()
{ std::cout << "nonconst call" << std::endl; }
};
class Child : public Base
{
public:
void test() const
{
std::cout << "const call" << std::endl;
Child * nonConstThis = const_cast<Child * >(this);
Base * nonConstBase = dynamic_cast<Base * >(nonConstThis);
// This call leads to infinite recursion by calling
// "void Child::test() const", which implies that
// a "Child *" will resolve to calling a const Child function
// before calling a non-const Base function.
//nonConstThis->test();
// This will call "void Base::test()"
nonConstBase->test();
}
};
void main()
{
Child * child = new Child;
child->test();
}

It's actually method hiding, not overloading.
When you create a method with the same name in a derived class, the base class version is no longer visible.
struct A
{
void foo() {}
};
struct B : public A
{
void foo(int x) {}
};
B b;
b.foo(); //error
I'm assuming you expect B::foo() to exist, but, as you can see, it does not. So nothing, not cv-qualifiers (const) or parameters affect this.
In your case the name isn't resolved because it has something to do with the const, but because you're calling test on an object of type Child. You then call Base::test() on an object of type Base, just like the following would work form my example:
((A)b).foo();

You are stumbling on how overload name resolution works in C++. The function "test" in the base class becomes "hidden" (it's called name hiding). When looking for a suitable function to call, the compiler looks in the derived class first, sees a match, then stops looking. This answer has a good description as to why.
You can use a using declaration to look in the base class as well like this:
class Child : public Base
{
public:
using Base::test;
this will tell the compiler to also look in Base for test.

Related

Call overloaded, derived function from C++ class on base object does not call the overloaded function

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?
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.
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.

c++ polymorphic method defined in derived class matches type that should match to the parent

I'm experimenting with this code
class Base
{
public:
virtual void foo(int) {
// void foo(int) {
cout << "int" << endl;
}
};
class Derived : public Base
{
public:
void foo(double) {
cout << "double" << endl;
}
};
int main()
{
Base* p = new Derived;
p->foo(2.1);
Derived d;
d.foo(2); // why isn't this double?
return 0;
}
It's also available in online editor here https://onlinegdb.com/s8NwhfG_Yy
I'm getting
int
double
I don't understand why d.foo(2) calls the double version. Since Derived inherits the int method and has its own double method, wouldn't polymorphism dictate that 2 be matched to the parent? Thanks.
Polymorphism as in calling virtual methods is orthogonal to symbol and overload resolution. The former happens run-time, the rest at compile-time.
object->foo() always resolves the symbol at compile-time - member variable with overloaded operator() or a method. virtual only delays selecting "the body" of the method. The signature is always fixed, including the return value of course. Otherwise the type system would break. This is one of the reasons why there cannot be virtual function templates.
What you are actually experiencing is name hiding and overload resolution.
For Base* p; p->foo(2.1), the list of possible symbol candidates is only Base::foo(int). The compiler cannot know that p points to Derived (in general) because the choice must be done at compile time. Since int is implicitly convertible to double, foo(int) is chosen. Because the method is virtual, if Derived were to provide its own foo(int) override, it would have been called instead of Base::foo(int) at run-time.
For Derived*d; d->foo(2), the compiler first looks for symbol foo in Derived. Since there is foo(double) which is valid as foo(2), it is chosen. If there was no valid candidate, only then the compiler would look into base classes. If there was Derived::foo(int), possibly virtual, the compiler would choose this instead because it is a better match.
You can disable the name hiding by writing
class Derived: public Base{
using Base::foo;
};
It injects all Base::foo methods into Derived scope. After this, Base::foo(int) (now really Derived::foo(int)) is chosen as the better match.
Read Overload resolution. The answer is in Details:
If any candidate function is a member function (static or non-static), but not a constructor, it is treated as if it has an extra parameter (implicit object parameter) which represents the object for which they are called and appears before the first of the actual parameters.
The selecting between the methods void foo(int) and void foo(double) is happening like between the functions void foo(Base, int) and void foo(Derived, double). The second function while calling d.foo(2) is ranked higher.
If you add using Base::foo; in Derived, the resolution will be performed between three functions void foo(Base, int), void foo(Derived, int) and void foo(Derived, double), and int will be printed.

Calling a virtual function from within an inherited function?

I've tried to map it out in my head, but honestly I have no idea what's really going on here.
What exactly is happening when I add and remove the virtual keyword from the below example?
#include <iostream>
#include <string>
class A {
public:
A() { me = "From A"; }
void caller() { func(); }
virtual void func() { std::cout << me << std::endl; } // THIS LINE!
private:
std::string me;
};
class B : public A {
public:
B() { me = "From B"; }
void func() { std::cout << me << std::endl; }
private:
std::string me;
};
int main() {
A a;
a.caller();
B b;
b.caller();
return 0;
}
With the virtual keyword, it prints "From A", then "From B".
Without the virtual keyword, it prints "From A", then "From A".
So far, this is the only time I've found a use for virtual functions without pointers being involved. I thought that if the virtual keyword was removed, the compiler would do the standard thing which is to overload the inherited function and end up printing "From A", and "From B" anyway.
I think this is deeper than just the VTable, and that it's more about the way it behaves in particular circumstances. Does B even have a VTable?
The call
func()
is equivalent to
this->func()
so there is a pointer involved.
Still, there's no need to involve pointers to understand the behavior.
Even a direct call of e.g. b.func() has to work as if it's a virtual call, when func is virtual in the statically known type. The compiler can optimize it based on knowing the most derived type of b. But that's a different kind of consideration (optimizations can do just about anything).
Apart from the issue of virtual dispatch, what may bring extra confusion, is that you have two mes, one declared in A and another declared in B. These are two distinct objects.
An object of type B has two data members of type std::string; one on its own, and one incorporated into the subobject of type A. The latter one, though, is not immediately available in the methods of type B because its name is eclipsed by the new me introduced in this class (though you may use a qualified name, A::me to refer to it).
Therefore, even though the bodies of A::func and B::func seem identical, the identifier me used in both of them refers to different members.
In your example, you won't see the difference:
With the virtual function, the compiler will generate a call via the VTable and at runtime, each objects will call the right function for their real class.
With the non virtual function, the compiler determines at compile time the right function to call, based on the objects defined class.
Now try the following, to see the virtual function in action:
A *pa = &b; // pointer to an A: valid as b is a B wich is also an A.
pa -> caller(); // guess what will be called if virtual or not.
No need for pointer to experimenting with virtual functions. You can observe the same effect with references as well:
A& ra = b; // create a reference to an A, but could as well be a parameter passed by reference.
ra.caller();
Virtual functions are useful for polymorphism. The idea is that you work with a general object of a class, but you don't know at compile time, if at runtime the object will really be of this class, or if it will not be a more specialiszed object (inheriting from the class).

C++ Programm calls superclass method instead of subclass method in factory pattern

I'd like to build a factory for my Source-Plugins like that:
class PluginFactory {
public:
PluginFactory(){};
virtual ~PluginFactory(){};
static MySource* getSourceById(int id, ParameterList& pList){
switch (id){
case 1:
return new StringSource(pList);
default:
std::cout << "Unknown PluginId!" << std::endl;
return nullptr;
}
}
};
MySource cannot be abstract like usual in the pattern because it will later be used in a template class.
When I call a method of the returned MySource* I get the method of the superclass MySource instead of the overridden method of the subclass StringSource.
Any ideas how to fix this?
EDIT:
I declared the superclass method as vritual:
MySource{
...
virtual std::streamsize read(char* s, std::streamsize n){
...
}
};
I added the override command to the subclasses' read-Method:
class StringSource: public MySource {
...
std::streamsize read(char* s, std::streamsize n) override
{
...
}
};
But it still uses the superclass method. There has to be another reason...
Btw. I put the Source-Class into a boost::iostream::filtering_istream like this:
MySource* source = PluginFactory::getSourceById(1, pluginList[0].second);
boost::iostreams::filtering_istream in;
in.push(*source);
So I don't call the read-method myself.
The problem is this:
in.push(*source);
According to the documentation, this will copy the argument. Since your base class is copyable and not abstract, you encounter the slicing problem where only the base sub-object is copied.
You should be able to fix it by passing a reference wrapper instead:
in.push(std::ref(*source));
I would suggest that you make the base class abstract (or at the very least uncopyable), to prevent the possiblity of slicing. I don't understand your reason for not making it abstract; but whatever requires it to be concrete sounds scary and error-prone.
UPDATE: Since you made it concrete just so you could pass it to this function, you should make it abstract again, and pass a reference wrapper instead.
When I call a method of the returned MySource* i get the method of the superclass MySource instead of the overridden method of the subclass StringSource.
I'm not sure this will work (without seeing any relevant code), but it sounds like you need to declare your superclass method (the one you call) as virtual, so that the compiler knows to run the overridden version (in this case, of StringSource), rather than the superclass version.
Hope this helps!
The method in MySource that you call must be virtual otherwise, the one in the derived class doesn't override but, instead, hides it. For instance,
class Base {
public:
void foo() const { std::cout << "Base::foo()\n"; }
virtual void bar() const { std::cout << "Base::bar()\n"; }
};
class Derived : public Base {
public:
void foo() const { std::cout << "Derived::foo()\n"; } // hides Base::foo
void bar() const { std::cout << "Derived::bar()\n"; } // overrides Base::bar
};
Derived d;
Base& b = d;
d.foo(); // outputs Derived::foo()
b.foo(); // outputs Base::foo()
b.bar(); // outputs Derived::bar()
If you're using C++11, I would advise to use the override keyword in the declaration of Derived::bar():
void bar() const override { std::cout << "Derived::bar()"; }
More precisely, you should use override in the declaration of all derived methods that are meant to override the one in the base class. If you make a mistake and the method in the derived class doesn't override any method in the base, then the compiler will raise an error.
Herb Sutter explains the issues here.
Update: After the OP's addition of more information.
Another possible reason for the issue is as follows. If the base class is copied (e.g. when it's passed to a function by value), then the copy looses information on the dynamic type. For instance, reconsider the example above and these functions:
void call_bar_pass_by_value(Base x) {
x.bar();
}
void call_bar_pass_by_reference(const Base& x) {
x.bar();
}
Then, calling them with b gives:
call_bar_pass_by_value(b); // outputs Base::bar()
call_bar_pass_by_reference(b); // outputs Derived::bar()
I'm not familiar with Boost.Iostreams but looking at the reference documentation of filtering_stream::push() here we can see that this function does take its argument by reference. Hence, the problem that I just described doesn't happen here. However, this function might call another one which call another one ... and one of them might make take the argument by value (or make a copy of it).
The OP states that "MySource cannot be abstract like usual in the pattern because it will later be used in a template class". This suggests that an attempt to copy the object is made.
I don't know what to advise now but just to test my theory above (it doesn't solve the issue) I would temporarily make MySource's copy constructor protected to see whether Boost.Iostreams tries to copy MySource. If so, then the code will fail to compile.

Double dispatch produces 'hides virtual function' warnings, why?

I would like to implement interactions between two objects whose types are derived from a common base class. There is a default interaction and specific things may happen once objects of the same type interact.
This is implemented using the following double dispatch scheme:
#include <iostream>
class A
{
public:
virtual void PostCompose(A* other)
{
other->PreCompose(this);
}
virtual void PreCompose(A* other)
{
std::cout << "Precomposing with an A object" << std::endl;
}
};
class B : public A
{
public:
virtual void PostCompose(A* other) // This one needs to be present to prevent a warning
{
other->PreCompose(this);
}
virtual void PreCompose(A* other) // This one needs to be present to prevent an error
{
std::cout << "Precomposing with an A object" << std::endl;
}
virtual void PostCompose(B* other)
{
other->PreCompose(this);
}
virtual void PreCompose(B* other)
{
std::cout << "Precomposing with a B object" << std::endl;
}
};
int main()
{
A a;
B b;
a.PostCompose(&a); // -> "Precomposing with an A object"
a.PostCompose(&b); // -> "Precomposing with an A object"
b.PostCompose(&a); // -> "Precomposing with an A object"
b.PostCompose(&b); // -> "Precomposing with a B object"
}
I have two, unfortunately quite different questions regarding this code:
Do you think this is a reasonable approach? Would you suggest something different?
If I omit the first two B methods, I get compiler warnings and errors that the last two B methods hide the A methods. Why is that? An A* pointer should not be cast to a B* pointer, or should it?
Update: I just found out that adding
using A::PreCompose;
using A::PostCompose;
makes the errors and warnings vanish, but why is this necessary?
Update 2: This is neatly explained here: http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.9, thank you. What about my first question? Any comments on this approach?
Double dispatch is usually implemented differently in C++, with the base class having all different versions (which makes it a maintenance nightmare, but that is how the language is). The problem with your attempt to double dispatch is that dynamic dispatch will find the most derived type B of the object on which you are calling the method, but then the argument has static type A*. Since A does not have an overload that takes B* as argument, then the call other->PreCompose(this) will implicitly upcast this to A* and you are left with single dispatch on the second argument.
As of the actual question: why is the compiler producing the warnings? why do I need to add the using A::Precompose directives?
The reason for that are the lookup rules in C++. Then the compiler encounters a call to obj.member(), it has to lookup the identifier member, and it will do so starting from the static type of obj, if it fails to locate member in that context it will move up in the hierarchy and lookup in the bases of the static type of obj.
Once the first identifier is found, lookup will stop and try to match the function call with the available overloads, and if the call cannot be matched it will trigger an error. The important bit here is that lookup will not look further up in the hierarchy if the function call cannot be matched. By adding the using base::member declaration, you are bringing the identifier member from the base class into the current scope.
Example:
struct base {
void foo( const char * ) {}
void foo( int ) {}
};
struct derived : base {
void foo( std::string const & ) {};
};
int main() {
derived d;
d.foo( "Hi" );
d.foo( 5 );
base &b = d;
b.foo( "you" );
b.foo( 5 );
d.base::foo( "there" );
}
When the compiler encounters the expression d.foo( "Hi" ); the static type of the object is derived, and lookup will check all member functions in derived, the identifier foo is located there, and lookup does not proceed upwards. The argument to the only available overload is std::string const&, and the compiler will add an implicit conversion, so even if there could be a best potential match (base::foo(const char*) is a better match than derived::foo(std::string const&) for that call) it will effectively call:
d.derived::foo( std::string("Hi") );
The next expression d.foo( 5 ); is processed similarly, lookup starts in derived and it finds that there is a member function there. But the argument 5 cannot be converted to std::string const & implicitly and the compiler will issue an error, even if there is a perfect match in base::foo(int). Note that this is an error in the call, not an error in the class definition.
When processing the third expression, b.foo( "you" ); the static type of the object is base (note that the actual object is derived, but the type of the reference is base&), so lookup will not search in derived but rather start in base. It finds two overloads, and one of them is a good match, so it will call base::foo( const char* ). The same goes for b.foo(5).
Finally, while adding the different overloads in the most derived class hide the overloads in the base, it does not remove them from the objects, so you can actually call the overload that you need by fully qualifying the call (which disables lookup and has the added side effect of skipping dynamic dispatch if the functions were virtual), so d.base::foo( "there" ) will not perform any lookup at all and just dispatch the call to base::foo( const char* ).
If you had added a using base::foo declaration to the derived class, you would add all the overloads of foo in base to the available overloads in derived, and the call d.foo( "Hi" ); would consider the overloads in base and find that the best overload is base::foo( const char* );, so it will actually be executed as d.base::foo( "Hi" );
In many cases, developers are not always thinking on how the lookup rules actually work, and it might be surprising that the call to d.foo( 5 ); fails without the using base::foo declaration, or worse, that the call to d.foo( "Hi" ); is dispatched to derived::foo( std::string const & ) when it is clearly a worse overload than base::foo( const char* ). That is one of the reasons why compilers warn when you hide member functions. The other good reason for that warning is that in many cases when you actually intended to override a virtual function you might end up mistakenly changing the signature:
struct base {
virtual std::string name() const {
return "base";
};
};
struct derived : base {
virtual std::string name() { // missing const!!!!
return "derived";
}
}
int main() {
derived d;
base & b = d;
std::cout << b.name() << std::endl; // "base" ????
}
A small mistake while trying to override the member function name (forgetting the const qualifier) means that you are actually creating a different function signature. derived::name is not an override to base::name and thus a call to name through a reference to base will not be dispatched to derived::name!!!
using A::PreCompose;
using A::PostCompose;
makes the errors and warnings vanish, but why is this necessary?
If you add new functions to your derived class with same name as your base class contains and if you don't override the virtual functions from base class, then new names hide the old names from the base class.
That is why you need to unhide them by explicity writing:
using A::PreCompose;
using A::PostCompose;
Other way to unhide them (in this particular case) is , override the virtual functions from base class which you've done in the code you've posted. I believe that code would compile just fine.
Classes are scopes and the look up in a base class is described as looking up in an enclosing scope.
When looking up overload of a function, looking up in enclosing scope is not done if a function was found in the nested one.
A consequence of the two rules is the behaviour you experimented. Adding the using clauses import the definition from the enclosing scope and is the normal solution.