#include <iostream>
class base
{
public:
virtual void print (int a)
{
std::cout << "a: " << a << " base\n";
}
virtual void print (int a, int b)
{
std::cout << "base\n";
}
};
class derived : public base
{
public:
virtual void print (double d)
{
std::cout << "derived\n";
}
};
int main ()
{
int i = 10;
double d = 10000.0;
base *b = new derived ();
b->print (i, i);
b->print (d);
return 0;
}
The output of this function is:
base
a: 10000 base
Why b->print (d) don't invoke the derived class implementation and
performs static cast on 'd' to provide a match with base class
implementation ?
What rule is applied here during virtual function lookup ?
derived::print does not override any member function in base. It is declared as having a single parameter of type double but the two virtual member functions named print in base are declared as having one and two parameters of type int.
When you use b->print(d), only member functions in base are considered during overload resolution, so only void base::print(int) and void base::print(int, int) are considered. void derived::print(double) can't be found because the compiler has no idea that b points to a derived object.
If derived were to override one of the two print functions declared as virtual member functions in base, then that override would be called at runtime.
(On a somewhat related note, derived::print hides the two base::print member functions, so if you were to try to use one of the base class print functions, e.g., derived().print(1, 1), it would fail. You would need to use a using declaration to make those member functions available during name lookup.)
Overload resolution happens at compile time. Overrides happen at run time.
Therefore, the overload resolution of b->print(d); happens first. This selects Base::print(int) because it's the only one-argument print.
At runtime, b points to a Derived object that has no override for Base::print(int). Therefore, Base::print(int) is still called.
Because double can be automatically converted to an int in the first definition it sees (in the base class)
See explicit keyword or this question
Related
Consider the following class definitions:
class foo {
virtual absl::Span<const Input *const> GetInputs() const = 0;
virtual absl::Span<Input *const> GetInputs() {
auto mutable_inputs = GetMutableInputs();
return absl::MakeSpan(mutable_inputs.begin(), mutable_inputs.end());
}
}
class bar : public foo {
absl::Span<const Input *const> GetInputs() const override {
return absl::MakeConstSpan(inputs_);
}
}
When calling bar.GetInputs() it seems like the only implementation found is the the one that returns a span of constant inputs. If I have an instance of bar, and want to create a span of non-const inputs, then I must cast bar to foo, and then call GetInputs.
If I cast bar to foo, then call GetInputs, I am then able to assign the result to a span of non-const inputs. Why does the compiler fail to identify the inherited non-const method with the correct return type? Is there a way to make the subclass identify that method?
In other words, is there a way to make the following code compile:
absl::Span<Input *const> tmp = bar.GetInputs()
If I understand your question, it has nothing to do with virtual functions or "precedence" of const, but is plain old "name hiding".
#include <iostream>
class Base {
public:
virtual void f(int) { std::cout << "Base(int)\n"; }
virtual void f(double) { std::cout << "Base(double)\n"; }
};
class Derived : public Base {
public:
virtual void f(double) { std::cout << "Derived(double)\n"; }
};
int main() {
Derived d;
int x=0;
d.f(x);
}
output: Derived(double)
The issue is, name lookup doesn't work the way it seems you expect.
For a given scope, it searches for names to build an overload set. Within the context of Derived, there is only one f(), so when it's found, the compiler stops searching further for more overloads.
It finds Derived(double) and that's the entire overload set, and so it is selected. When you cast your derived class to a reference to the base, and then call something, both functions (declared in the base) are considered, and overload resolution selects the best match.
Now, normally, for polymorphic types you are working with the objects in terms of pointers/references to the base, so it's not an issue. But if you are calling directly on the derived class (perhaps from inside a member of derived?) then it'll have this issue of the derived declaration hiding the base names.
To make the base names visible in the derived class, it's easy:
class Derived : public Base {
public:
using base::f; // <<<<<<<< just add this
virtual void f(double) { std::cout << "Derived(double)\n"; }
};
you should add
using foo::GetInputs;
in bar class to expose the base class function.
you will be able to call the base class function if the object is non-const
I would expect that if foo is declared in class D, but not marked virtual, then the following code would call the implementation of foo in D (regardless of the dynamic type of d).
D& d = ...;
d.foo();
However, in the following program, that is not the case. Can anyone explain this? Is a method automatically virtual if it overrides a virtual function?
#include <iostream>
using namespace std;
class C {
public:
virtual void foo() { cout << "C" << endl; }
};
class D : public C {
public:
void foo() { cout << "D" << endl; }
};
class E : public D {
public:
void foo() { cout << "E" << endl; }
};
int main(int argc, char **argv)
{
E& e = *new E;
D& d = *static_cast<D*>(&e);
d.foo();
return 0;
}
The output of the above program is:
E
Standard 10.3.2 (class.virtual) says:
If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name and same parameter list as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides*
[Footnote: A function with the same name but a different parameter list (clause over) as a virtual function is not necessarily virtual and does not override. The use of the virtual specifier in the declaration of an overriding function is legal but redundant (has empty semantics). Access control (clause class.access) is not considered in determining overriding. --- end foonote]
Quick answer may be no, but correct answer is yes
C++ doesn't know about function hiding, so overriding virtual function without virtual keyword marks that function virtual too.
You are not creating any copy of the object of e and putting it in d. So d.foo() follows normal polymorphic behavior and calls derived class method. A method which is declared as virtual in the base class becomes automatically virtual in the derived class also.
The output ("E") behaves exactly as one would expect it to behave.
The reason:
The dynamic (i.e. runtime) type of that reference is E. You are doing a static upcast to D, but that does not change the actual type of the object of course.
That's the very idea behind virtual methods and dynamic dispatches: You see the behavior of the type you were instantiating, which is E, in this case.
Having
#include <iostream>
using namespace std;
class A {
public:
virtual void foo() {
cout << "A" << endl;
}
};
class B : public A {
public:
void foo() {
cout << "B" << endl;
}
};
class C : public B {
public:
void foo() {
cout << "C" << endl;
}
};
int main() {
C c;
B* b = &c;
b->foo();
return 0;
}
The output is C, but I expected B.
I didn't declare B::foo() with the virtual modifier, so I expect the function call to be determined by the static type (no polymorphism).
Why is C::foo() being called?
Is it possible to provide a non-virtual function in a derived class, that hides the virtual function in the base? What signature should the derived member function have so that b->foo() calls it, and not (b->*&A::foo)()
The principle of virtual inheritance of a member function is is a direct consequence of the C++ Standard:
10.3/2: If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base,
a member function vf with the same name, parameter-type-list ,
cv-qualification, and refqualifier (or absence of same) as Base::vf is
declared, then Derived::vf is also virtual.
So regardless of the level of inheritance, the function will be virtual in all the classes derived somehow from A. There is no need to put the keyword virtual.
The goal of this polymorphic approach is to ensure that you always call the appropriate function corresponding to the real idendity of your object, regardless the fact that you use a pointer to a base or a pointer to the real class of the object. This is why you obtain "C" !
In this related SO question I explain a trick to give the impression of removing virtuality at one single level, using multiple inheritance. However it can be done only for a single level (you should do it for the class of your base pointer).
*By the way, you could write pb->B::foo(); no need of *&.
I'm working on C++. Following is my code:
#include <iostream>
using namespace std;
class base
{
public:
virtual void display(int a = 4)
{
cout << "base :: "<< a*a << endl;
}
};
class derived : public base
{
public:
void display(int b = 5)
{
cout << " Derived :: " << b*b*b << endl;
}
};
int main()
{
base *bobj;
derived dobj;
bobj = &dobj;
bobj->display();
return 0;
}
The output is:
Derived :: 64
The function of Base class is called, but default value of the parameter of derived function is used.
Why the derived class method display(), takes the base class method argument value?
Because you're calling it through a pointer to base. That's how it works.
Arguments are pushed on the argument stack (or inside registers) before the actual call. Because you have a pointer to base and no parameters, the default 4 is passed to the function. Then the correct function is called (derived::display), but with base's default parameter. Of course, this is an implementation detail, but the behavior is standard.
C++03 8.4/10
A virtual function call (10.3) uses the default arguments in the declaration of the virtual function determined by the static
type of the pointer or reference denoting the object. An overriding function in a derived class does not acquire default
arguments from the function it overrides.
I would provide emphasis on the quote, but the whole thing is pretty self-explanatory.
dobj.display();
would print 125 (5^3).
Default arguments are inserted by the caller. Your code is equivalent to
class base {
public:
virtual void display(int a) { cout << "base :: "<< a*a << endl; }
inline void display(void) { display(4); }
};
etc.
When calling through a base pointer, the default value from the base class is inserted.
The Standard says it all:
(§8.3.6/10) A virtual function call (10.3) uses the default arguments in the declaration of the virtual function determined by the static type of the pointer or reference denoting the object. An overriding function in a derived class does not acquire default arguments from the function it overrides. [ Example:
struct A {
virtual void f(int a = 7);
};
struct B : public A {
void f(int a);
};
void m() {
B* pb = new B;
A* pa = pb;
pa->f(); // OK, calls pa->B::f(7)
pb->f(); // error: wrong number of arguments for B::f()
}
— end example ]
Make yourself a less contrived test setup, and it becomes clear:
#include "base.hpp"
int compute(base * p)
{
return p->display();
}
Two things are obvious now:
The default argument can only possibly come from the default argument specified in base.
The actual dispatch is dynamic, since display is a virtual member function.
When you use -> i.e. invoke a function using a pointer it uses the object which is being pointed for taking a decision which in this case is an object of Derived class.
As the specification says...
A virtual function call uses the default arguments in the declaration of the virtual function determined by the static type of the pointer or reference denoting the object. An overriding function in a derived class does not acquire default arguments from the function it overrides.
I wanted to have confirmation about the following things:
Virtual Mechanism:
I f I have a base class A and it has a Virtual method, then in the derived class generally, we do not include the virtual statement in the function declaration. But what does a virtual mean when included at the dervied class definition.
class A
{
public:
virtual void something();
}
class B:public A
{
public:
virtual void something();
}
Does, that mean that we want to override the method somethign in the classes that derive from the class B?
Also, another question is,
I have a class A, which is derived by three different classes.Now, there is a virtual method anything(), in the base class A.
Now, if I were to add a new default argument to that method in the base class, A::anything(), I need to add it in all the 3 classes too right.
My pick for the answers:
If a method which is virtual in the base class is redefined in the derived class as virtual then we might mean that it shall be overridden in the corresponding derived classes which uses this class as base class.
Yes.If not overriding does not have any meaning.
Pls let me know if what I feel(above 2) are correct.
Thanks,
Pavan Moanr.
The virtual keyword can be omitted on the override in the derived classes. If the overridden function in the base class is virtual, the override is assumed to be virtual as well.
This is well covered in this question: In C++, is a function automatically virtual if it overrides a virtual function?
Your second question is about default values and virtual functions. Basically, each override can have a different default value. However, usually this will not do what you expect it to do, so my advice is: do not mix default values and virtual functions.
Whether the base class function is defaulted or not, is totally independent from whether the derived class function is defaulted.
The basic idea is that the static type will be used to find the default value, if any is defined. For virtual functions, the dynamic type will be used to find the called function.
So when dynamic and static type don't match, unexpected results will follow.
e.g.
#include <iostream>
class A
{
public:
virtual void foo(int n = 1) { std::cout << "A::foo(" << n << ")" << std::endl; }
};
class B : public A
{
public:
virtual void foo(int n = 2) { std::cout << "B::foo(" << n << ")" << std::endl; }
};
int main()
{
A a;
B b;
a.foo(); // prints "A::foo(1)";
b.foo(); // prints "B::foo(2)";
A& ref = b;
ref.foo(); // prints "B::foo(1)";
}
If all your overrides share the same default, another solution is to define an additional function in the base class that does nothing but call the virtual function with the default argument. That is:
class A
{
public:
void defaultFoo() { foo(1); }
virtual void foo(int n) { .... }
};
If your overrides have different defaults, you have two options:
make the defaultFoo() virtual as well, which might result in unexpected results if a derived class overload one but not the other.
do not use defaults, but explicitly state the used value in each call.
I prefer the latter.
It doesn't matter whether you write virtual in derived class or not, it will always be virtual because of the base class, however it is still better to include virtual to explicitly state that it is virtual and then if you accidentally remove that keyword from base class it will give you compiler error (you cannot redefine non-virtual function with a virtual one). EDIT >> sorry, I was wrong. You can redefine non-virtual function with a virtual one however once it's virtual all derived classes' functions with same signature will be virtual too even if you don't write virtual keyword. <<
If you don't redefine virtual function then the definition from base class will be used (as if it were copied verbatim).
If you wish to specify that a virtual function should be redefined in dervied class you should not provide any implementation i.e. virtual void something() = 0;
In this case your class will be an abstract base class (ABC) and no objects can be instantiated from it. If derived class doesn't provide it's own implementetian it will also be an ABC.
I'm not sure what do you mean about default arguments but function signatures should match so all parameters and return values should be the same (it's best to not mix overloading/default arguments with inheritance because you can get very surprising results for example:
class A
{
public:
void f(int x);
};
class B:public A
{
public:
void f(float x);
};
int main() {
B b;
b.f(42); //this will call B::f(float) even though 42 is int
}
Here is a little experiment to test out what you want to know:
class A {
public:
virtual void func( const char* arg = "A's default arg" ) {
cout << "A::func( " << arg << " )" << endl;
}
};
class B : public A {
public:
void func( const char* arg = "B's default arg" ) {
cout << "B::func( " << arg << " )" << endl;
}
};
class C : public B {
public:
void func( const char* arg ) {
cout << "C::func( " << arg << " )" << endl;
}
};
int main(int argc, char* argv[])
{
B* b = new B();
A* b2 = b;
A* c = new C();
b->func();
b2->func();
c->func();
return 0;
}
result:
B::func( B's default arg )
B::func( A's default arg )
C::func( A's default arg )
conclusion:
1- virtual keyword before A's func declaration makes that function virtual in B and C too.
2- The default argument used is the one declared in the class of pointer/reference you are using to access the object.
As someone pointed out, a function in a derived class with the same name and type signature as a virtual function in the base class is automatically always a virtual function.
But your second question about default arguments is interesting. Here is a tool for thinking through the problem...
class A {
public:
virtual void do_stuff_with_defaults(int a = 5, char foo = 'c');
};
is nearly equivalent to this:
class A {
public:
virtual void do_stuff_with_defaults(int a, char foo);
void do_stuff_with_defaults() { // Note lack of virtual keyword
do_stuff_with_defaults(5, 'c'); // Calls virtual function
}
void do_stuff_with_defaults(int a) { // Note lack of virtual keyword
do_stuff_with_defaults(a, 'c'); // Calls virtual functions
}
};
Therefore you are basically having virtual and non-virtual functions with the same name but different type signatures declared in the class if you give your virtual function default arguments.
On way it isn't equivalent has to do with being able to import names from the base class with the using directive. If you declare the default arguments as separate functions, it's possible to import those functions using the using directive. If you simply declare default arguments, it isn't.