In the main() function below, d is a base class pointer (of type A) which points to a derived class (of type B). Yet when the member function f(int) is called on this pointer, i.e. d->f(1), the compiler calls the non-virtual function in the base class A (labelled #2), i.e.
void f(int n) const { std::cout << n; }
Why? I was expecting that since there is also a virtual function in the base class A
virtual void f(int n) { std::cout << n; }
one of the two functions f(int) in the derived class B would be called. Where am I going wrong?
class A
{
public:
A() {}
public:
virtual void f(int n) { std::cout << n; } // #1
virtual ~A() { }
void f(int n) const { std::cout << n; } // #2 this function is called when d->f(1) is executed in main()
};
class B
: public A
{
public:
void f(int n) { std::cout << n; } // #3
void f(int n) const { std::cout << n; } // #4
};
int main()
{
B b;
const A* d = &b;
d->f(1); // this calls function #2 above - why?
std::cout << std::endl;
return 0;
}
d is a pointer to a const A. This means any call to a member function will call the const-qualified overload if one exists. In your case, the const-qualified version of f in the base class (#2) is not virtual, so the fact that d is pointing to a B object doesn't matter. The base class const-qualified overload is the one that is chosen to be called.
If you make the const-qualified overload of f in the base class virtual then the const-qualified overload in the derived class (#4) will be chosen.
Similarly, if d is a pointer to a non-const A, then the non-const-qualified overload of f in the derived class (#3) will be called, since the overload in the base class (#1) is virtual.
Related
#include <iostream>
using namespace std;
class A {
public:
virtual void f() = 0;
};
class B : public A {
public:
void f() {cout << "hi" << endl;}
void g() { cout << "bye" << endl; }
};
int main() {
B b;
A &a = b;
a.f(); // prints "hi"
a.g(); // compile error no member g()
return 0;
}
why does a.g() give compile error while a.f() calls B's f()?
At A &a = b; does the compiler somehow set a boundary of where a's aliasing memory ends?
You are attempting to call g() from an instance of A. A does not have an implementation of g(), so it cannot be called through an A object. The fact that a is a reference to a B does not give a access to any functions that A does not know about.
B, on the other hand is-a A, and defines an implementation of the virtual function f(), so the reference a invokes the correct function.
In the example below I have a abstract class with pure virtual method (aka FUN1) and a normal method (aka FUN2).
#include <iostream>
class A
{
public:
virtual void fun(int i) = 0; // FUN1
void fun() { this->fun(123); } // FUN2
};
class B : public A
{
public:
virtual void fun(int i) { std::cerr << i << std::endl; }
};
int main(int,char**)
{
B b;
b.fun();
}
Why can't I call FUN2 on derived class? g++ gives an error:
main.cpp:19:8: error: no matching function for call to ‘B::fun()’
EDIT: note that Overload of pure virtual function question is different. I don't want to override methods.
This is how derived class member lookup works: in the expression b.fun(), fun is first looked up in the scope of class B, and the lookup finds B::fun(int). So it stops and never finds A::fun().
Relevant section of the standard is 10.2 [class.member.lookup]/4:
If C contains a declaration of the name f, the declaration set contains every declaration of f declared in
C that satisfies the requirements of the language construct in which the lookup occurs. (...) If the resulting declaration set is not empty, the subobject set contains C itself, and calculation is complete.
To make the base class function directly accessible you can use a using declaration in the derived class, i.e. using A::fun;.
For methods that are implemented in the base class an alternative is sometimes to qualify to call, i.e. b.A::fun().
Try to add using A::fun; statement in B class :
#include <iostream>
class A
{
public:
virtual void fun(int i) = 0; // FUN1
void fun() { this->fun(123); } // FUN2
};
class B : public A
{
public:
using A::fun;
virtual void fun(int i) { std::cerr << i << std::endl; }
};
int main(int, char**)
{
B b;
b.fun();
b.fun(5);
}
In the example below I have a abstract class with pure virtual method (aka FUN1) and a normal method (aka FUN2).
#include <iostream>
class A
{
public:
virtual void fun(int i) = 0; // FUN1
void fun() { this->fun(123); } // FUN2
};
class B : public A
{
public:
virtual void fun(int i) { std::cerr << i << std::endl; }
};
int main(int,char**)
{
B b;
b.fun();
}
Why can't I call FUN2 on derived class? g++ gives an error:
main.cpp:19:8: error: no matching function for call to ‘B::fun()’
EDIT: note that Overload of pure virtual function question is different. I don't want to override methods.
This is how derived class member lookup works: in the expression b.fun(), fun is first looked up in the scope of class B, and the lookup finds B::fun(int). So it stops and never finds A::fun().
Relevant section of the standard is 10.2 [class.member.lookup]/4:
If C contains a declaration of the name f, the declaration set contains every declaration of f declared in
C that satisfies the requirements of the language construct in which the lookup occurs. (...) If the resulting declaration set is not empty, the subobject set contains C itself, and calculation is complete.
To make the base class function directly accessible you can use a using declaration in the derived class, i.e. using A::fun;.
For methods that are implemented in the base class an alternative is sometimes to qualify to call, i.e. b.A::fun().
Try to add using A::fun; statement in B class :
#include <iostream>
class A
{
public:
virtual void fun(int i) = 0; // FUN1
void fun() { this->fun(123); } // FUN2
};
class B : public A
{
public:
using A::fun;
virtual void fun(int i) { std::cerr << i << std::endl; }
};
int main(int, char**)
{
B b;
b.fun();
b.fun(5);
}
In the following code
#include <iostream>
using namespace std;
class A {
public:
A() {}
virtual ~A() {};
};
class B : public A {
public:
B() {}
virtual ~B() {};
};
void process(const A&) {
cout << "processing A" << endl;
}
void process(const B&) {
cout << "processing B" << endl;
}
int main(void) {
A* a = new B;
process(*a);
return 0;
}
the output of running it becomes
processing A
but I would have assumed that it should have been
processing B
since a points to the derived class B and not A. So why does it call the first implementation of process function and not the second?
The static type of expression *a is A because a was declared as
A* a = new B;
The compiler resolves the selection of overloaded functions using the static type of the argument.
Even when virtual functions are called the compiler uses the static type of the object to call appropriate function. The difference is only that the compiler uses the table of pointers to virtual functions to indirectly call the required function.
You need to make process() a virtual member function of A, B:
class A {
public:
A() {}
virtual ~A() {};
virtual void process() const { cout << "processing A" << endl; }
};
class B : public A {
public:
B() {}
virtual ~B() {};
virtual void process() const override { cout << "processing B" << endl; }
};
int main(void) {
A* a = new B;
a->process();
return 0;
}
In your current code, *a is of type A&, so the closest match to process(*a); is the first overload (for const A&).
void process(const A&); is a better (exact) match, since dereferencing A* gives you A&.
Short answer, but there isn't much more to say unless you want a reference from the standard.
You could dynamic_cast the result of *a and that would give you a B&, but that's smelly desing. What you probably want is a virtual function in A that's overriden in B (assume it's called foo). Then, calling a->foo() would dispatch to B::foo.
In the below program, the function 'f' in the base class A is hidden for the objects of derived class B. But when I call function f through const A *d which is pointing object of B, function f from the base class is getting invoked. If I remove const specifier for the pointer (i.e. A *d) function 'f' from derived class is called. My query how the constness is making a difference here ? Thanks for any help.
#include <iostream>
class A
{
public:
virtual void f(int n) { std::cout << "A::f\n"; }
virtual ~A() { }
void f(int n) const { std::cout << "A::f const\n"; }
};
class B
: public A
{
public:
void f(int n) { std::cout << "B::f\n"; }
void f(int n) const { std::cout << "B::f const\n"; }
};
int main()
{
const A a;
B b;
A &c = b;
const A *d = &b;
c.f(1);
d->f(1);
return 0;
}
Output (with const A *d):
B::f
A::f const
Output (with A* d)
B::f
B::f
The signature of the function to be called is determined on call site based on the static type of the pointer. The correct overrider of this signature is then chosen at runtime.
In other words, if you have this:
const A *d;
d->f(1);
then the f is searched for in const A. So it finds the non-virtual void f(int) const.
However, if you have this:
A *e;
e->f(1);
then the f is searched for in non-const A. So it finds virtual void f(int), which is then (at runtime) delegated to the final overrider void B::f(int).
EDIT
This follows from the rules on member function selection. When accessing through a const path (pointer or reference), only const member functions are applicable. When accessing through a non-const path, non-const functions are considered. Only if there is none is the pointer (or reference) implicitly converted to a pointer (or-reference) to const and then the const member functions are considered.