Why is the output of this program "CLASS A"? Isn't this determined to be of type B? Doesn't it mean that this->g() should call the B class's version of g?
#include <iostream>
using namespace std;
class A {
private:
void g() {
cout << "CLASS A" << endl;
}
public:
virtual void f() {
g();
}
};
class B : public A {
public:
void g() {
cout << "CLASS B" << endl;
}
};
int main() {
A* a = new B();
a->f();
}
Isn't this determined to be of type B?
No. B may be the dynamic type, but the static type of *this is A within all its member functions.
The member function g is not virtual, so therefore a call to it uses static binding. In static binding, the dynamic type of the object is irrelevant - only the static type matters. A call to the non-virutal g within a member function of A should be a call to A::g.
Related
Is there a way to make a pointer on member function in base class if it is a virtual function and it is overridden in derived class?
Consider the code as follows
#include <iostream>
#include <functional>
struct Base
{
virtual void g() const
{
std::cout << "Base" << std::endl;
}
};
struct Derived : Base
{
virtual void g() const override
{
std::cout << "Derived" << std::endl;
}
};
int main()
{
Derived d;
(d.*(&Base::g))();
std::mem_fn(&Base::g)(d);
return 0;
}
It prints ‘Derived’ twice despite I make a pointer on Base::g. Is there a way to keep function g virtual and overridden and get member function pointer that will print ‘Base’ for d?
Just call the base function
int main()
{
Derived d;
d.g();
Base* b = &d;
b->Base::g();
//or
d.Base::g();
//or
auto callLater = [&d]() { d.Base::g();};
callLater();
return 0;
}
Output
Derived
Base
Base
Base
This can be made a pointer to the function; but it needs be to the member function Base::g() of the object being pointed to.
You might define a non-virtual function real_g called from g so code
struct Base
{
void real_g() const {
std::cout << "Base" << std::endl;
}
virtual void g() const { real_g(); };
};
Then later in main
std::mem_fn(&Base::real_g)(d);
See wikipage on virtual method table, this C++ reference and the C++ standard n3337 or better. Read also a good C++ programming book and the documentation of your C++ compiler, e.g. GCC
See also this answer (explaining naively what are vtables, in simple cases)
#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.
#include <iostream>
using namespace std;
class A {
};
typedef void (A::*funA)(int);
class B : public A {
public:
void m(int) {std::cout << "mm" << std::endl; }
void n(int) { std::cout << "nn"<<std::endl; }
};
typedef void (B::*funB)(int);
class C : public B {
public:
void g(int) {std::cout << "gg" << std::endl; }
void h(int) { std::cout << "hh"<<std::endl; }
};
typedef void (C::*funC)(int);
int main() {
funB f = static_cast<funB>(&C::m);
A* pa = new A;
(pa->*(static_cast<funA>(f)))(2);
return 0;
}
gcc compile and output "mm".
But why can this work? Class A in fact don't define any function.
It seems the class can use its base class or derived class function by this way, even though it doesn't define them.
Since A doesn't contain the member that f refers to, the behaviour is undefined.
The probable reason why it works anyway is that the function B::m doesn't touch the this pointer, so it doesn't "notice" when it's called on an object of the wrong type. Also, A and B are not polymorphic, so dereferencing the pointer-to-member and calling doesn't require examining any vptr.
The following code prints 1 2, but I would expect it to print 1 1.
#include <iostream>
using namespace std;
class A {
public:
virtual void f() { cout << "0" << endl; }
};
class B : public A{
public:
void f() { cout << "1" << endl; }
};
class C : public B{
public:
void f() { cout << "2" << endl; }
};
int main() {
A *pa = new B();
B *pb = new C();
pa->f();
pb->f();
}
In my understanding, pa->f() executes B's f() function since A's is virtual, but why does pb->f() execute C's f() function when B's f() is not virtual.
Additionally, if I remove 'virtual' from class A, it prints 0 1, which makes sense because A and B execute their own f() functions since they aren't virtual. How come pb->f() changes if it isn't affected since it's only A that changes?
but why does pb->f() execute C's f() function when B's f() is not virtual.
Because the dynamic type of pb is C and C::f is indeed virtual. When you declare
virtual void f();
in the base class, every other void f() of the derived classes in the hierarchy is also virtual, as per §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 (8.3.5), cv-qualification, and ref- qualifier (or absence of same) as Base::vf is declared, then Derived::vf is also virtual (whether or not it is so declared) and it overrides112 Base::vf.
(emphasis mine)
In fact:
class A {
public:
virtual void f() { cout << "0" << endl; }
};
class B : public A{
public:
virtual void f() { cout << "1" << endl; }
};
class C : public B{
public:
virtual void f() { cout << "2" << endl; }
};
is equivalent to your code. It just so happens that the C++ standard allows virtual to be omitted in those cases.
It happens because writing virtual keyword in subclasses is not necessary, it just improves readability.
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.