I define 2 classes
class BaseA {
public:
virtual void methodA() = 0;
};
class BaseB {
public:
virtual void methodB(int val) = 0;
};
Child inherits 2 Base Class
class Child : public BaseA, public BaseB {
public:
void methodA() override {
printf("Child A\n");
}
void methodB(int val) override {
printf("Child B %d\n", val);
}
};
Then I write following code.
void callBaseB(void *p) {
BaseB *b = (BaseB *) p;
b->methodB(0);
}
int main() {
auto child = new Child;
callBaseB(child);
return 0;
}
console print
Child A
Why this happened? Why not call method B?
(This is what happend when a Java engineer try to write C++ code)
You should just do this: void callBaseB(BaseB *p) {p->methodB(0);}.
If you want to keep void *p as a parameter, you need to cast it to exactly Child * first. Either:
BaseB *b = (Child *)p;
b->methodB(0);
Or:
Child *b = (Child *)p;
b->methodB(0);
Alternatively, cast to BaseB * before converting to void *. Then casting from void * back to Base * will work.
What happens here is that the BaseB subobject is at non-zero offset inside of Child.
When you convert Child * to BaseB * (either explicitly with a cast, or implicitly, either by assigning pointers or by calling a method of BaseB on the pointer), the compiler automatically offsets the pointer by the required amount, to point to the BaseB subobject.
The offset is determined entirely at compile-time (unless virtual inheritance is involved), based on the two types.
When you obscure the source type using void *, the compiler has no way to determine the correct offset, and doesn't even try to apply any offset, so you get weird behavior, because the resulting BaseB * doesn't point to a BaseB instance, but rather to some junk inside of Child.
Even with virtual inheritance, despite the offset being determined at runtime, the calculation depends on the source pointer type being known.
Casting a void* to a BaseB* cannot be done (as #PaulSanders said), but you can definitely cast a Child* to a BaseB* as follows:
void callBaseB(Child* p)
{
BaseB* b = p;
b->methodB(0);
}
The above code should successfully call methodB().
But if you really need to use void*, you can so something like this:
void callBaseB(void* p)
{
Child* b = (Child*)p;
b->methodB(0);
}
Related
I have the following code:
struct A
{
virtual void foo() {std::cout << "A\n";}
};
struct B : public A
{
virtual void foo() {std::cout << "B\n";}
};
void bar(A * a)
{
a->foo();
}
Without changing this code, is it possible to cast bp pointer to B, so calling bar would print "A"?
int main()
{
B * bp = new B();
bar(/* do somethig*/ bp);
return 0;
}
Tried every cast I remebered:
int main()
{
B * bp = new B();
bar((A*)bp);
bar(static_cast<A*>(bp));
bar(reinterpret_cast<A*>(bp));
bar(dynamic_cast<A*>(bp));
return 0;
}
You could make a shim wrapper around B, and have the shim's virtual function dispatched to BWrap::foo() call directly to A::foo();.
There's not really any point in the example to carrying along the B& member variable reference, but for more interesting examples there may be a use case.
struct BWrap : public A
{
B& b;
BWrap(B& bb) : b{bb} {}
virtual void foo() { b.A::foo(); }
};
int main()
{
B* bp = new B();
BWrap bw{*bp};
bar(&bw);
}
If you insist on the A object being a base class subobject of a B object and on not modifying the first code snippet at all, then the only solution is to add an even more derived class that can override the virtual call as explained in the answer by #Eljay (which I completely forgot to think about when first writing this answer).
Other options are to create a complete A object, not a B object, or to modify bar to do a call without virtual dispatch by using a qualified name:
a->A::foo();
All of the casts you are showing have the same effect as the implicit conversion, except for reinterpret_cast which will cause undefined behavior when used this way.
I made following 3 classes:
struct Parent1
{
virtual void f()
{
cout << "\nParent1::f";
}
};
struct Parent2
{
virtual void g()
{
cout << "\nParent2::g";
}
virtual void z()
{
cout << "\nParent2::z";
}
};
struct Child : public Parent1, public Parent2
{
virtual void h()
{
cout << "\nChild::h";
}
};
In main, when I call function z of Parent2, it instead calls function h of the child class. Why is it happening so?
Following is the main function:
int main()
{
Child obj;
Parent2 * p2 = (Parent2*)(Parent1*)&obj;
p2->z();
return 0;
}
The first explicit conversion from &obj i.e. Child* to Parent1* is an upcast. The result will point to the base class sub-object. The next explicit conversion is from Parent1* to Parent2*. Since these classes are not directly related, this is a reinterpretation cast. But the types are not pointer-interconvertible, so when you call the function through the reinterpreted pointer, the behaviour of the program is undefined.
You should avoid using C-style casts to prevent mistakes like this. In this case, no explicit cast is needed at all. This works correctly:
Parent2 * p2 = &obj;
And never reinterpret pointers unless you know what it means and that it is OK to do so.
Consider the below code.
#include<iostream>
using namespace std;
class Base
{
public:
virtual void function1() {cout<<"Base:function1()\n";};
virtual void function2() {cout<<"Base:function1()\n";};
};
class D1: public Base
{
public:
virtual void function1() {cout<<"D1:function1()\n";};
virtual void function2() {cout<<"D1:function2()\n";};
};
int main()
{
Base *ptr= new D1;
ptr->function1();
ptr->function2();
return 0;
}
The ptr will be pointing to D1 obj.
so whenever i call ptr->function1(), the function address is fetched from virtual table of class D1. It works same way for ptr->function2() as well.
In this case the vtable[0] will have function pointer to function1(), vtable[1] will have function pointer to function2().
My question is how function call to vtable index mapping happens?
How ptr->function1() & ptr->function2() indexes to vtable[0] & vtable[1] respectively?
The first element of the class is usuaylly the (hidden) vtable pointer - vptr. For a polymorphic class, the vtable is first initialized to the vtable of base class in the base class constructor. Then, when the derived class constructor executes the same vtable pointer is initialized to point to the derived class vtable. Note that the base class vtable points to base version of function1 and function2 whereas derived class vtable points to derived version of function1 and function2.
Now, when a pointer to base class points to an instance of derived class, this is what 'typically may' happen:
class base
{
//int* vptr; //hidden vtable pointer, created by compiler for polymorphic class. vptr points to base class vtable for base clas objects
public:
virtual void function1(){std::cout <<"base::function1()"<<std::endl;}
virtual void function2(){std::cout <<"base::function2()"<<std::endl;}
};
class derived: public base
{
//int* vptr; //hidden vtable pointer, inherited from the base class. vptr points to derived class vtable for derived class objects
public:
virtual void function1(){std::cout <<"derived::function1()"<<std::endl;}
virtual void function2(){std::cout <<"derived::function2()"<<std::endl;}
};
int main()
{
typedef void (*vtableFnPtr)();
base* pBase;
base base_obj;
derived derived_obj;
pBase = &derived_obj; //base pointer pointing to derived object
//one of the several possible implementations by compiler
int* vtableCallBack = *(int**)&derived_obj; //read the address of vtable pointed by the hidden vptr in the derived_obj
//pBase->function1();
((vtableFnPtr)vtableCallBack[0])(); //calls derived::function1(), when application calls pBase->function1();
//pBase->function2();
((vtableFnPtr)vtableCallBack[1])(); //calls derived::function2(), when application calls pBase->function2();
pBase = &base_obj;
//one of the several possible implementations by compiler
vtableCallBack = *(int**)&base_obj; //base pointer pointing to base object
//pBase->function1();
((vtableFnPtr)vtableCallBack[0])(); //calls base::function1(), when application calls pBase->function1();
//pBase->function2();
((vtableFnPtr)vtableCallBack[1])(); //calls base::function2(), when application calls pBase->function2();
}
Note that the C++ compiler does not say anything about the implementation methodology to be used for achieving polymorphic behavior and hence it is completly upto the compiler to use vtable or any other implementation as long as the behavior is polymorphic. However, vtable remains one of the most widely used methods to achieve polymorphic behavior.
"All problems in computer science can be solved by another level of indirection"
I referred to excellent and detail blog post and have tried below to explain use of vtable for your simple example. See if you are read thorough it.
struct Base;
// enumerates all virtual functions of A
struct table_Base {
void (*function1)(struct Base *this);
void (*function2)(struct Base *this);
};
struct Base {
const struct table_Base *pvtable; // table maintains pointers to virtual functions. Eventually to implementations
int data;
};
void Base_function1(struct Base *this) {
std::cout << "Base:function1()" << std::endl;
}
void Base_function2(struct Base *this) {
std::cout << "Base:function2()" << std::endl;
}
// table data for Base
static const struct table_Base table_Base_for_Base = { Base_function1, Base_function2};
void Base_Ctor(struct Base *this) {
this->pvtable = &table_Base_for_Base;
this->data = 1;
}
// Now for class D1
struct D1;
struct table_D1 {
void (*function1)(struct D1 *this);
void (*function2)(struct D1 *this);
};
struct D1 {
struct Base base;
const struct table_D1 *pvtable;
int more_data;
};
void D1_function1(struct D1 *this) {
std::cout << "D1:function1()" << std::endl;
}
void D1_function2(struct D1 *this) {
std::cout << "D1:function2()" << std::endl;
}
// Important functions that do re-direction
void D1Base_function1(struct Base *this) {
D1_function1((struct D1*) this);
}
void D1Base_function2(struct Base *this) {
D1_function2((struct D1*) this);
}
// table data for D1
static const struct table_D1 table_D1_for_D1 = {D1_function1, D1_function2};
// IMPORTANT table
static const struct table_Base table_Base_for_D1 = {D1Base_function1, D1Base_function2};
// Constructor for derived class D1
void D1_Ctor(struct D1 *this)
{
Base_Ctor(&this->base); // Base class vtable is initialized.
// Now, Override virtual function pointers
this->base.vtbl = &table_Base_for_D1; // Replace the vtable
this->mode_data = 100;
}
Internally this is the logic followed by the compiler to achieve correct behavior for virtual functions.
ptr->function1();
ptr->function2();
You can trace the method calls above using vtable logic explained and see if it works.
class Base1
{
public:
virtual ~Base1(){}
virtual void whatever()
{
cout << "whatever" << endl;
}
};
class Base2
{
public:
virtual ~Base2(){}
virtual void aFunc(int i) = 0;
};
class A : public Base1, public Base2
{
public:
A()
{}
~A()
{}
virtual void aFunc(int i) final
{
cout << "func" << endl;
}
};
int main()
{
void* a;
a = new A();
(static_cast<Base2*>(a))->aFunc(0);
Base2* ptr = static_cast<Base2*>(a);
ptr->aFunc(0);
return 0;
}
This example prints out "whatever" instead of "func", if I change the line with void* to A* than it prints out "func". Is this a known behavior? I would expect that's the case just don't know why.
Is this a known behavior?
Yes. Behaviour is well-defined if you convert to void* and then back to the same type. It's undefined if you convert back to a different type.
I would expect that's the case just don't know why.
There's no guarantee that a base sub-object has the same address as the complete object; in fact, if there's more than one non-empty base class, then at least one sub-object will have to be at a different address. So a valid conversion from A* to Base2* probably needs to adjust the value of the pointer, not just reinterpret it as a different type. Conversion to void* and back can't make that adjustment.
Suppose in one old project (>1M lines), there is a class named Base which has two virtual functions foo and bar
class Base
{
public:
virtual void foo();
virtual void bar();
};
class Derived: public Base
{
public:
virtual void foo();
virtual void bar();
};
I suspect that Base is not used polymorphically, so foo/bar should not be virtual.
To confirm my ideas, I need to find out whether there is a statement like:
Base *b = new Derived;
but if we pass the pointer among a function, it would be hard to find out, for example:
Base *f()
{
...
Derived *d = /* ... */;
...
return d;
}
Is there any way to do that?
Make Derived inherit privately from Base. This will prevent implicit upcasts making Base* b = new Derived; a compile error.
If you have two classes like following:
class Base
{
virtual void a(){};
};
class Derived : public Base
{
virtual void b(){};
};
when you write code:
Base* ptr = new Derived();
you could see ptr in watch window
ptr->__vfptr 0x00eb5740 const Derived::`vftable' *
[0] 0x00eb1028 Base::a(void) *
You can look at the entire vtable if you add this helper variable:
void (**vt)() = *(void (***)())ptr;
and in watch window you could see:
vt,2 0x00eb5740 const Derived::`vftable' void (void)* *
[0] 0x00eb1028 Base::a(void) void (void)*
[1] 0x00eb10aa Derived::b(void) void (void)*
so ,you could take a try.