Virtual function overloading - c++

Lets say that we have :
Class A
{
public:
virtual void print(){ std::cout<<" A "<<endl; }
}
Class B : public A
{
public:
virtual void print(int x){ std::cout<<" B "<<endl;}
}
I thought that the definition in Class B of function print will hide the function print from class A. But the following code works and prints " A "
int main()
{
A * a = new B;
a->print();
return 0;
}
If I write the main function like this it doesnt work :
int main()
{
B b;
b.print();
return 0;
}
What i Want to know is...in my first main() example I have a B object that calls print()...shouldnt then print() be hidden and have an error like in the second main() example

The member function print() in B is not overriding the print() in A because it has a different signature. Therefore, when calling print() in your first, unedited version of main(), there is only one matching function to call, as pointed out by user juanchopanza: A::print().
EDIT: To summarize:
Polymorphic behavior: If A::print() and B::print() had the same signature, the appropriate print() would be chosen at runtime as long as you reference the object through pointers or references.
Function overloading: Since a class is a scope and functions do not overload across scopes, the functions from base classes are hidden by functions of the same name in a derived class. For this, the type of the variable you are using to refer to your object is the one that matters, not the type of the object itself. Therefore, in your second example you get an error that there is no matching function to call, but in your first example, only one function is in scope.

The issue here is name lookup. In a call like A *a = new B; a->print() the compiler looks at the type of a, which is A*, and looks in the class A for a member function named print. It finds it and it calls it. Similarly, with B *b = new B; b->print(); the compiler looks in class B for a member function named print; it finds print(int), which can't be called with no arguments. And because it found a function named print in B it stops looking; it doesn't go into A to find A::print(). That's name hiding.
The key here is that name lookup starts with the declared type of the object; in these two examples the types are A* and B*, respectively. Lookup does not pay attention to the actual type of the thing that a pointer or reference points to or refers to.

Named overloading functions in a derived class are hiding those from the base class. However, you'll need to use the derived class interface to see so:
B b;
b.print(); // won't work

That is because two print() functions have different signatures. Two functions - print() and print(int) are considered different and cannot be overloaded overridden by each other.

Check your class definitions; the print functions in A and B have different signatures. When you call
a->print();
There's only one function that fits that signature, which is A::print(). If you remove the int parameter from B's definition you should observe the behaviour you're expecting.

Related

Calling a function of sister class C++

Consider the following code:
#include <iostream>
class A
{
public:
virtual void f() = 0;
virtual void g() = 0;
};
class B : virtual public A
{
public:
virtual void f()
{
g();
}
};
class C : virtual public A
{
public:
virtual void g()
{
std::cout << "C::g" << std::endl;
}
};
class D : public C, public B
{
};
int main()
{
B* b = new D;
b->f();
}
The output of the following program is C::g.
How does the compiler invoke a function of a sister class of class B??
N3337 10.3/9
[ Note: The interpretation of the call of a virtual function depends on the type of the object for which it is
called (the dynamic type), whereas the interpretation of a call of a non-virtual member function depends
only on the type of the pointer or reference denoting that object (the static type) (5.2.2). — end note ]
The dynamic type is type to which pointer really points, not type that was declared as pointed type.
Therefore:
D d;
d.g(); //this results in C::g as expected
is same as:
B* b = new D;
b->g();
And because inside your B::f call to g() is (implicitly) called on this pointer whose dynamic type is D, call resolves to D::f, which is C::f.
If you look closely, it's the (exactly) same behaviour as shown in code above, only that b is now implicit this instead.
That's the whole point of virtual functions.
It's the behavior of virtual: B call g through f but g is resolve at runtime (like f). So, at runtime, the only available override of g for D is the one implemented in C
g is resolved at runtime, like all virtual functions. Because of the way D is defined it's resolved into whatever C implements.
If you don't want this behaviour you should either call a non-virtual implementation of g (you can delegate to that function from the virtual one as well), or explicitly call B's implementation using B::g().
Though if you do this your design will be a lot more complicated than it probably needs to be so try to find a solution that doesn't rely on all these tricks.
Virtual function calls are resolved at runtime, by reference to the instance's VTable. A distinct VTable exists for any virtual class (so in above each of A, B, C and D have a VTable). Every runtime instance has a pointer to one of these tables, determined by its dynamic type.
The VTable lists every virtual function in the class, mapping it to the actual function that should be called at runtime. For normal inheritance these are listed in order of declaration, so a base class can use the VTable of a derived class to resolve virtual functions that it declares (because the derived class, listing the functions in declaration order, will have all the base class's functions listed first in excatly the same order the base class's own VTable). For virtual inheritance (as above), this is slightly more complicated, but essentially the base class within the derived class still has its own VTable pointer that points to the relevant section inside the derived's VTable.
In practice this means your D class has a VTable entry for g that points to C's implementation. Even when accessed through the B static type it will still refer to this same VTable to resolve g.

Early and late binding + polymorphism in c++

Say there was no Hello function and we simply called ob.display in main then it calls the display function of class B and not class A.
Call of the function display() is being set once by the compiler as the version defined in the base class. This is called static resolution of the function call, or static linkage - the function call is fixed before the program is executed. This is also sometimes called early binding because the display() function is set during the compilation of the program.
Now how can it call the display function of the derived class without using the virtual keyword(late binding) before the display function in the base class?
Now in this program, Passing the object as call by value,call by pointer and call by reference to the Hello function works fine. Now if we use Polymorphism and want to display the member function of the derived class if it is called we have to add the virtual keyword before display function in the base. If we pass the object value by call by pointer and call by reference it call the function in the derived class but if we pass the object by value it doesn't why is it so?>
class A
{
public:
void display(); // virtual void display()
{
cout << "Hey from A" <<endl;
}
};
class B : public A
{
public:
void display()
{
cout << "Hey from B" <<endl;
}
};
void Hello(A ob) // &ob //*ob
{
ob.display(); // ob->display()
}
int main()
{
B obj;
Hello(obj); // obj //&ob
return 0;
}
Now how can it call the display function of the derived class without using the virtual keyword(late binding) before the display function in the base class?
A non-virtual function is simply resolved by the compiler, according to the static type of the object (or reference or pointer) it's called on. So given an object of the derived type, and a reference to its sub-object:
B b;
A & a = b;
you'd get different results from calling a non-virtual function:
b.display(); // called as B
a.display(); // called as A
If you know the real type, then you could specify that you want to call that version:
static_cast<B&>(a).display(); // called as B
but that would go horribly wrong if the object that a refers to doesn't have type B.
Now if we use Polymorphism and want to display the member function of the derived class if it is called we have to add the virtual keyword before display function in the base.
Correct. If you make the function virtual, then it's resolved at runtime according to the dynamic type of the object, even if you use a different type of reference or pointer to access it. So both the above examples would call it as B.
If we pass the object value by call by pointer and call by reference it call the function in the derived class but if we pass the object by value it doesn't why is it so?
If you pass it by value, then you're slicing it: copying just the A part of the object, to make a new object of type A. So, whether or not the function is virtual, calling it on that object would choose the A version, since it's an A and nothing but an A.
If you pass by reference or pointer, then you're still accessing the original object, with its dynamic type B. So the virtual function call would resolve to the B version.
Now how can it call the display function of the derived class without using the virtual keyword(late binding) before the display function in the base class?
You can provide a templated base class like this
template<typename Derived>
class A {
public:
void display() {
// call Derived first
static_cast<Derived*>(this)->display();
cout << "Hey from A" <<endl;
}
};
class B : public A<B> {
public:
void display() {
cout << "Hey from B" <<endl;
}
};
This is a well known pattern, called CRTP and Static Polymorphism.

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

Polymorphism or inheritance?

I have a theoretical question about C++. It was part of the final exam at my university and I want to know why the method f of class B is called, while it should be derived by the base class A. Since it is not virtual shouldn't the A::f() be called?
#include <iostream.h>
#include <stdlib.h>
class A{
public:int f(int x){
cout<< x << " ";
}
};
class B:public A{
public:int f(int y){
A::f(y+1);
}
};
void g(A a, B b) {
a.f(3);
b.f(3);
}
int main()
{
B p;
B q;
g(p,q);
system("PAUSE");
return 0;
}
// result is 3 4
The static type if b in g() is B, thus there is no need for virtual here - the compiler can know [at compile time] you want to invoke B::f(), and that is exactly what he is doing. In here, the class B redefined A's f(), and hides it, so invoking f() from a variable whose static type is B results in invoking B::f()
Note that the virtual keyword allows you to use overriding methods where the static type is the parent's type.
The method g takes two arguments, of type A and B repsectively. Since these are no pointer or reference types, dynamic binding does not apply. The compiler knows at compile time the actual type of the objects, and does a static method call.
virtual methods only apply if you have pointers or references!
The function int f(int) in class B "hides" the function with the same name and signature in its base class.
So, when you call b.f(3);, and the variable b has type B, you are calling B::f.
Virtual functions are only needed if you want b.f(3) to call B::f in cases where the type of the variable b is A&, but the object it refers to has runtime type B. In that situation, the function called would be B::f if A::f is virtual, but A::f is called if non-virtual.
Virtual function calls take the runtime type of objects into account even if they're used via a pointer or reference to a base class. But B b; b.f(3) is a call to B::f regardless of whether A::f even exists, never mind whether it's virtual or non-virtual.
There are 2 things happening here:
You are slicing your object.
Your f() function is not an override because it is not virtual, and really you should not be doing this.
You would overcome the slicing by making the function g take its first parameter by reference. If A was given a protected copy-constructor that would also prevent it, although then you would not be able to copy genuine instances of A.
In this case your function g will always call A::f() even with reference to A because there is no polymorphism. To invoke that you will need to declare A::f() as virtual.
"Non-scientific" explanation:
The function g treats a as if it was an instance of A gets a copy of p as an object of type A(see comments below) , and executes the f from within A. b is treated as an instance of B, where the method B.f overrides A.f, so when b is "looked at" as an instance of B and we execute b.f, the method B.f will be executed, because the A.f is not visible
If you'd like to call A.f using b.f you'd have to cast b to A: ((A)b).f().

Virtual functions and polymorphism

Suppose I have this:
class A
{
public:
virtual int hello(A a);
};
class B : public A
{
public:
int hello(B b){ bla bla };
};
So, A it's an abstract class.
1)In the class B, I'm defining a method that its suppose overrides the A class. But the parameter it's slightly different. I'm not sure about this, is this correct? Maybe because of polymorphism, this is ok but its rather confusing.
2) If I do: A a = new B;, and then a.hello(lol); if "lol" it's not of type B, then it would give compile error?, and if it's of type A from another class C (class C : public A), what would happend?
I'm confused about the overriding and virtual thing.. all examples I found work with methods without parameters.
Any answer, link, or whatever it's appreciated.
thanks
pd: sorry for my english
Your class B doesn't override the member function in A, it overloads it. Or tries to anyway, see the bit about hiding later.
Overriding is when a derived class defines its own version of a virtual member function from a base class. Overloading is when you define different functions with the same name.
When a virtual call is made on a pointer or reference that has the type of the base class, it will only "consider" overrides in the derived class, not overloads. This is essential - for an instance of B to be treated by callers as though it does everything an A can do (which is the point of dynamic polymorphism and virtual functions), its hello function needs to be able to take any object of type A. A hello function which only takes objects of type B, rather than any A, is more restrictive. It can't play the role of A's hello function, so it's not an override.
If you experiment a bit with calling hello on A and B, passing objects of type A or B, you should be able to see the difference. A has a function taking an A (which you haven't defined, so if you call it then your program will fail to link, but you can fix that). B has a function taking a B. They happen to have the same name, and of course since B derives from A, you can pass a B to the function taking an A. But B's function doesn't act as an override in virtual calls.
It is possible to call A's function on a B object, but only via a reference or pointer to A. A feature of C++ is that the definition of hello in B hides the definition in A. If overloading is what you want, it's possible to un-hide the base class function by adding using A::hello; to class B. If overriding is what you want, you have to define a function taking the same parameters. For example:
#include <iostream>
class A
{
public:
virtual int hello(A a) {std::cout << "A\n"; }
virtual int foo(int i) { std::cout << "A::Foo " << i << "\n"; }
};
class B : public A
{
public:
using A::hello;
// here's an overload
int hello(B b){ std::cout << "B\n"; };
// here's an override:
virtual int foo(int i) { std::cout << "B::Foo " << i << "\n"; }
};
int main() {
A a;
B b;
a.hello(a); // calls the function exactly as defined in A
a.hello(b); // B "is an" A, so this is allowed and slices the parameter
b.hello(a); // OK, but only because of `using`
b.hello(b); // calls the function exactly as defined in B
A &ab = b; // a reference to a B object, but as an A
ab.hello(a); // calls the function in A
ab.hello(b); // *also* calls the function in A, proving B has not overridden it
a.foo(1); // calls the function in A
b.foo(2); // calls the function in B
ab.foo(3); // calls the function in B, because it is overridden
}
Output:
A
A
A
B
A
A
A::Foo 1
B::Foo 2
B::Foo 3
If you take away the using A::hello; line from B, then the call b.hello(a); fails to compile:
error: no matching function for call to `B::hello(A&)'
note: candidates are: int B::hello(B)
A bunch of good answers telling you WHAT happens, I thought I'd jump in with WHY.
There's this thing called the Liskov Substitution Principle, which says that the function in the subclass has to work under the same preconditions and postconditions as the base class. In this case, the function has to be able to operate on any object of type A. Note that because of the inheritance relationships, every B is-a A, but not every A is-a B. So to replace the base method, the new function in the derived class can weaken the preconditions or strengthed the postconditions, but not strengthen preconditions or weaken postconditions.
Your attempt to override strengthens the precondition, it accepts Bs, not all As.
Note that covariance IS allowed on return types. If your base class returned A, then it guarantees that the return value is-a A. The base class could then return a B, because every B is-a A.
But for input parameters, only contravariance meets the theoretical requirements of the LSP, and in/out parameters are invariants. In C++ in particular, all parameter types are invariant for the purposes of overloading.
First, A is not an abstract class in your code. It must have at least one pure virtual function to be abstract.
different parameters means completely different method, even though the name is the same. Think of it as a different name. That's why it's called "signature". If A would be an abstract class, this code would not compile at all.
A::hello() will be called. No problem with that, and parameter must be type A, as if there was no inheritance.
When you override a method, it redefines what the method will do. You can only override virtual members that are already defined (with their set of parameters). If the type is of A, the method on A will be called. If the type is of B, the method on B will be called even if the variable is typed A but contains an instance of type B.
You can't change the parameter definitions for an overridden method, or else it would cease to be an override.
What you are doing there is overloading not overriding, i.e. it's as if class B is:
class B
{
public:
int hello(A a) {...}
int hello(B b) {...}
};
You have two functions of the same name, but with different signatures, which makes them different functions (just like the standard library has different functions for abs(float) and abs(double) etc.)
If you want to override, then you need to have the same signature, i.e. class B's hello needs to take a parameter of type A. That way, when you call hello on an object of class B, it will use class B's hello rather than class A's.
If you actually want class B's hello to only accept objects of type B then what you have is fine, although you probably want to make class A's hello non-virtual as you are not really wanting to override it -- you are defining a new function with new parameters and new behaviour.
Thansk for the answers, but I have to clarify some things to get my final answer.
Suppose I have the A class exactly how I defined it in the original question. And I add another method:
class A {
...
int yeah();
}
Then I define class B as the following:
class B : public A {
int hello(A a);
};
And another class C analogous to B.
What I know because I'm the programmer, it's that the hello methods of B and C are gonna have obviously A type objects as parameters, but instances of the same class.
In example:
B b;
b.hello(some_other_b_instance);
or
C c;
c.hello(some_other_c_instance);
The problem is that in each hello function of the classes B and C, I want to do particular things with atributes of the particular class B or C. And because of the parameter is of type A, I cannot use them.
What I would need it's a kind of inverse polymorphysm, but its wrong because by definition I can send a C instance to B hello class, but I know it's not gonna happend.
I hope you get the idea of the code... A clase is abstract, and the real work makes sense in the particular clases B and C, each one do the work in their particular way to make the yeah function work. But B and C need to access their members to do the hello work correctly.