Call base virtual method by pointer to function from derived class - c++

I need to call the base method A::foo() from derived class by pointer.
#include <iostream>
struct A{
virtual void foo() { std::cout << "A::foo()" << std::endl; }
};
struct B:A{
virtual void foo() { std::cout << "B::foo()" << std::endl; }
void callBase(void (A::*f)()){
(this->*f)();
}
};
int main(){
B* p=new B();
p->callBase(&A::foo);
}
This code output "B::foo". Is it possible to call A::foo() by pointer to method?

Well, you can do something similar using some tricks with overwriting the value of this. You probably should never try to do that though, vtable pointers aren't meant to be modified by hand.
To do what you described, we need to have the pointer to A's vtable. Our object p has only pointer to B's vtable, so we need to store second pointer in a field within A's constructor.
Here is the code:
#include <iostream>
struct A{
virtual void foo() { std::cout << "A::foo()" << std::endl; }
int *a_vtable_ptr;
// First, save value of A's vtable pointer in a separate variable.
A() { a_vtable_ptr = *(int**)this; }
};
struct B:A{
virtual void foo() { std::cout << "B::foo()" << std::endl; }
void callBase(void (A::*f)()){
int *my_vtable_ptr = *(int**)this;
// Then modify vtable pointer of given object to one that corresponds to class A.
*(int**)this = a_vtable_ptr;
(this->*f)(); // Call the method as usual.
// Restore the original vtable pointer.
*(int**)this = my_vtable_ptr;
}
};
// Function main() is not modified.
int main(){
B* p=new B();
void (A::*f)() = &A::foo;
p->callBase(f);
}
Output:
A::foo()
Process finished with exit code 0

Virtual methods are designed to implement polymorphism and pointers to virtual methods supports their polymorphic behavior. But you given the possibility to call the base method by explicitly calling p->A::foo().
So if you want to call base method by pointer, you should make it non-virtual (as #PasserBy mentioned in comments).
Code example:
struct A {
virtual void foo() { std::cout << "A::foo()" << std::endl; }
void bar() { std::cout << "A::bar()" << std::endl; }
void callBase(void (A::*f)()) { (this->*f)(); }
};
struct B : A {
virtual void foo() { std::cout << "B::foo()" << std::endl; }
void bar() { std::cout << "B::bar()" << std::endl; }
};
int main()
{
A* p = new B();
p->foo();
p->bar();
p->callBase(&A::foo);
p->callBase(&A::bar);
p->A::foo();
p->A::bar();
}
Output:
B::foo()
A::bar()
B::foo()
A::bar()
A::foo()
A::bar()

Related

Call overridden method from base class

How to call overridden bar method from base class in the following scenario?
There is requirement that callback should always call method foo which should call bar which is overridden by latest derived class.
#include <iostream>
#include <functional>
#include <typeinfo>
using namespace std;
std::function<void(void)> callback = nullptr;
class Base {
public:
Base(Base* ptr) { callback = std::bind(&Base::foo, *ptr); }
virtual ~Base() {}
virtual void foo() {
bar(); // How call foo() from Derived instead of Base?
}
virtual void bar() { cout << "Base::bar" << endl; }
};
class Derived : public Base {
public:
Derived() : Base(this) {}
virtual void bar() override { cout << "Derived::bar" << endl; }
};
int main() {
cout << "Hello World" << endl;
Base* b = new Derived();
cout << "**callback**" << endl;
callback(); // output should be 'Derived::bar'
return 0;
}
You are binding the virtual method with the derived object improperly, slicing the derived object. Try this (* is removed)
Base(Base *ptr){
callback = std::bind(&Base::foo, ptr);
}
An alternative method that avoids std::bind() altogether:
Base(Base *ptr){
callback = [this]() { foo(); };
}
https://godbolt.org/z/pEs9ta
Note that this requires at least C++11.

member function pointer conversion

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

Additive Function Overloading?

Let's say I have a base class and a derived class:
struct A
{
void foo()
{
std::cout << "Do one thing." << std::endl;
}
};
struct B: public A
{
void foo()
{
std::cout << "Do another thing." << std::endl;
}
};
B myB;
myB.foo();
Normally this would print Do another thing., but what if I wanted foo() to also run the base foo() and print:
Do one thing.
Do another thing.
Call A::foo() in B::foo(), that way the base class's function will execute first, then the rest of the derived class function executes after that.
struct A
{
void foo()
{
std::cout << "Do one thing." << std::endl;
}
};
struct B : public A
{
void foo()
{
A::foo();
std::cout << "Do another thing." << std::endl;
}
};

Understanding pure-virtual functions

The following code compiles fine:
struct A
{
const int a;
virtual void foo() = 0;
};
struct B : A{ };
void A::foo(){ std::cout << "foo" << std::endl; }
DEMO
The thing is the struct A is an abstract therefore we can't instanciate it. But we can subclass it and
struct A
{
const int a;
virtual void foo() = 0;
};
struct B : A{ };
void A::foo(){ std::cout << "foo" << std::endl; }
int main(int argc, char ** argv)
{
B b;
b.foo(); //error: implement pure-virtual
}
DEMO
still can't use the A's implementation of foo and I suspect it will never called. So, I have no idea about application of such definition... Yes, it's useful to provide a definition for a virtual destructors, but that's not the case.
Where the definition of pure-virtuals can be used?
You can call it explicitly.
struct A
{
const int a;
virtual void foo() = 0;
};
struct B : A
{
void foo();
};
void A::foo()
{
std::cout << "A::foo" << std::endl;
}
void B::foo()
{
A::foo(); // here
std::cout << "B::foo" << std::endl;
}
int main(int argc, char ** argv)
{
B b;
b.foo(); // prints A::foo followed by B::foo
}
But you can (and MUST) implement (if B is to be instantiable) an override for A's void foo(). And THAT implementation CAN (but definitely not required to) call the BASE implementation:
struct B : public A
{
virtual void foo() {A::foo();}
};
I HAVE implemented this scenario, where I had a very simple "base" implementation, but required all leafs to ACTIVELY decide to utilize this base (or not) by chaining back to this common implementation.
You can call it from within B. And since A::foo() is pure virtual, B needs to define foo:
struct A {
virtual void foo() = 0;
};
void A::foo(){ std::cout << "A::foo() ran" << std::endl; }
struct B : A {
void foo() {
A::foo(); // <--
std::cout << "B::foo() ran" << std::endl;
}
};
int main(int argc, char ** argv)
{
B b;
b.foo();
}
This is how you implement Interfaces in C++. You force subclasses to implement that method to be instantiated, and you operate polymorphically in your own code on that abstract base class, leaving the specific implementation to clients of your interface.
As far as the implementing in base class goes, I can only think of two reasons. One, to allow them to not have to special case destructors. And two, B can define its own implementation in terms of A::foo(), IE, a default implementation.

Is there any possibility that `vptr` is modified outside of constructor and destructor?

I'm reading topics related to object destruction in the book Inside C++ Object Model and encounter this problem.
It says that before the execution of user-defined destructor, the destructor will be augmented. The first step of the augmentation is reset the vptr pointer to the virtual function table of that class. I remember that correspondingly, just before the execution of user code (statements in the blocked constructor body) in the constructor, the vptr has already been properly set in case virtual member functions should be invoked during construction.
The problem is whether the reset vptr step in the destructor augmentation is a must.
If so, there must be some possibility that the vptr in an object be updated somewhere.
When may this happen?
It can happen in the destructor of a derived class. Say you have:
class Foo : public Bar : public Baz
Now, say you have a Foo. In Foo::~Foo, it's a Foo, and that's the virtual function table it must use. But when Foo::~Foo completes, it's not a Foo anymore. It's a Bar, and that's what virtual function table it must use. When Bar::~Bar completes, it's just a Baz, so in Baz::~Baz, it must use the virtual function table for Baz.
The pointer to the virtual function table does not change except when in constructors and destructors.
Here's some example code to play with:
#include <string>
#include <iostream>
class Foo
{
public:
Foo() { print("Foo::Foo"); }
virtual ~Foo() { print("Foo::~Foo"); }
virtual void print(std::string j) { std::cout << j << "(Foo)" << std::endl; }
};
class Bar : public Foo
{
public:
Bar() { print("Bar::Bar"); }
virtual ~Bar() { print("Bar::~Bar"); }
virtual void print(std::string j) { std::cout << j << "(Bar)" << std::endl; }
};
class Baz : public Bar
{
public:
Baz() { print("Baz:Baz"); }
virtual ~Baz() { print("Baz::~Baz"); }
virtual void print(std::string j) { std::cout << j << "(Baz)" << std::endl; }
};
int main(void)
{
std::cout << "Constructing Baz" << std::endl;
{
Baz j;
std::cout << "Baz constructed" << std::endl;
}
std::cout << "Baz destructed" << std::endl;
}
Output is:
Constructing Baz
Foo::Foo(Foo)
Bar::Bar(Bar)
Baz:Baz(Baz)
Baz constructed
Baz::~Baz(Baz)
Bar::~Bar(Bar)
Foo::~Foo(Foo)
Baz destructed
You can see how a Foo is constructed and then used to make a Bar which is used to make the final Baz. At destruction time, ~Baz turns it into a Bar and then ~Bar turns it into a Foo. ~Foo does the final destruction.
No, there's no such possibility. The vptr is only updated from constructor and from destructor.
The update from destructor is done for a very specific reason: to make sure that all virtual functions called from inside the destructor of class A will call virtual functions defined in A or higher in the hierarchy, but not functions from classes located lower in the hierarchy. Basically, this is the same (symmetrical) reason why vptr pointer is updated in each constructor as well.
For example, in this hierarchy
struct A {
virtual void foo() { std::cout << "A" << std::endl; }
~A() { foo(); }
};
struct B : A {
virtual void foo() { std::cout << "B" << std::endl; }
~B() { foo(); }
};
struct C : B {
virtual void foo() { std::cout << "C" << std::endl; }
~C() { foo(); }
};
C c;
Each destructor in the destructor chain for the object c will perform a call to virtual function foo. The destructor of C will call C::foo, the destructor of B will call B::foo (not C::foo) and the destructor of A will call A::foo (again, not C::foo). This happens that way specifically because each destructor explicitly sets the vptr pointer to the virtual table of its own class.
A more convoluted example of the same behavior might look as follows
struct A;
extern void (A::*fun)();
struct A {
virtual void foo() { std::cout << "A" << std::endl; }
~A() { (this->*fun)(); }
};
void (A::*fun)() = &A::foo;
struct B : A {
virtual void foo() { std::cout << "B" << std::endl; }
~B() { (this->*fun)(); }
};
struct C : B {
virtual void foo() { std::cout << "C" << std::endl; }
~C() { (this->*fun)(); }
};
C c;
The difference is that this example is more likely to physically use the vptr and the virtual method table to resolve the calls. The previous example is usually optimized by the compiler into direct non-virtual calls to proper foo.