views:

413

answers:

8

hey,

there is something i still don't get.

for every class i declare there is a hidden vptr member pointing to the class virtual table.

let's say i have this declaration :

class BASE
{
    virtual_table* vptr; //that's hidden of course , just stating the obvious
    virtual void foo();
}

class DERIVED : public BASE
{
   virtual_table* vptr; //that's hidden of course also
   virtual void foo();
   virtual void cho();
}

first i want to understand something, is it really the same member name for the vptr both for the derived and the base ?

second, what happens in this situation :

base* basic = new derived();

i get it, the basic variable gets derived's vptr, but how is that happening ? cause usually when conversion taking place , derived's base part (including base's vptr) should be assigned to basic, and not derived's vptr. maybe it's different if there is a variable with the same name in both classes, i dunno.

third and last question : when i have

 base* basic = new derived();

is there a way to call with basic - base's member function even though it's virtual ?

thanks

A: 

Calling the parent method from a derived child: old question

Alex
A: 

first: yes: each instance will get that member variable declared by the base.

second: in that situation you'll be able to access only members of the base class.

third: you can call it if it is virtual, as long as it's not pure virtual (which means it doesn't have any implementation and it's declared like this: virtual void foo() = 0;).

JohnIdol
+1  A: 

The vtable (virtual_table, in your words) will point to different addresses for BASE and DERVIVED provided DERIVED overrides at least one virtual function from BASE. Each instance of BASE will have the same vtable pointer however (ditto for DERIVED).

When you do something like:

someobject->foo();

this is translated to:

someobject->vtable[COMPILER_GENERATED_OFFET_FOR_FOO]();

The vtable is an array of function pointers where the offset to some virtual function (say foo) is the same for all classes in the class hierarchy.

Andreas Brinck
"will point" is just a bit too strong. This need not be the case. Compilers can fold vtables: if there is at least one class that doesn't override any virtual function, the start of its vtable will be identical to the vtable of the base class. The result is that you can't use the value to identify an object.
MSalters
True, I updated my answer to reflect this.
Andreas Brinck
+2  A: 

first, yes, it is the same member. It is automaticaly assigned a first time when running base constructor, and assigned a second time when running the derived constructor. (In the case of default empty constructors, the useless assignements of base is optimized away.)

second, there is no real conversion. In fact, the derivation can be named a "is a" relationship. In this case, derived "is a" base. If you consider the first bytes of memory of a derived object, they have the same meaning than the first bytes of a base object.

third, you can call basic member function as follows: base->basic::foo();

Didier Trosset
you meant `basic->base::foo();`
Janusz Lenar
+1  A: 

3). Ya u can .base* basic = new derived();

basic->BASE::foo(); // will call base class method and resolved at compile time.

2). It is possible when there is not virtual stuff in class(if derived class does not override any base class functions), but if derived class has virtual functions (overrided )so to achieve run time polymorphism its necessary for compiler to initialize vptr of base by vptr of derived and it augments that code.

1).Yes the interface function prototype has to be same else base class function get hidden by derived class function (e.g. if parameter defers in derived class function ) .

Ashish
+2  A: 

First of all, virtual tables are not part of the C++ standard. A C++ compiler is free to implement virtual functions any way they feel appropriate. Usually they will use virtual tables, true; but in this case they can implement them any way they feel appropriate.

In most usual implementations, basic does not get derived's vptr; *basic's vptr will point to derived's vtable, which is not really the same. basic is just a pointer, and it is the object pointed that has a vptr. No conversion involved. In any case, vptr is just an internal name for an implementation detail. There is no real class member called vptr.

And you can always call any base-class function just by qualifying it with the class name (in your case, basic->BASE::FOO()).

UPDATE: Just for the record, I have tried creating a class in VC++2008 with a pointer called __vfptr (that is the internal name for the vptr in this compiler), and it works as expected, even though the debugger gets a bit confused by the variable name.

Gorpik
A: 

You can check vtable implementation details here; this is what the GNU compilers, and AFAIK some other mainly Unix compilers use. Especially the "Vtable layout" examples page is instructive.

As others have noted, this is an implementation detail, the C++ standard itself is silent on the matter.

janneb
+1  A: 

On the second question. (And this is not stated in the standard, and can be implemented in other ways, so just take the general ideas out of it. It is also oversimplified for single inheritance hierarchies, multiple inheritance makes everything more complex).

The memory layout of a derived and a base object coincides 100% in as much as the size of the base object (including any data injected by the compiler). This means that a pointer that has base type and actually points to derived will actually point to a piece of memory that can be interpreted as a base object, the layout is the same even if the contents (vptr value) are different.

base          derived

base_vptr     base_vptr
base_attrs    base_attrs

              derived_vptr
              derived_attrs

When you create an instance of derived the compiler will call the appropriate derived constructor, whose initialization list starts by calling the base constructor. At this point the vtable pointer base_vptr is set to point to the virtual table of the base class, and as such all pointers there refer to base::method. After the base constructor has completed, the base_vptr is updated in derived and it is set to point to the derived vtable, so instances there point to derived::method if the method is overriden in derived. At this point derived_vptr points to the derived vtable for virtual methods added in derived and would point to derived::new_method...

Just to make a point: the vtable does not necessarily store pointers into the actual methods. In some cases, intermediate code must be executed whenever a virtual method is called, and that happens whenever multiple inheritance comes into play. Things get more complicated, as the derived class can only be aligned with one of its bases (usually the first one declared). This is where things really get tricky. Upcasting to base2 modifies the pointer so that it points to the memory location that can be directly be interpreted as a base2 instance, so the contents of a pointer (memory location) of type base2 pointing to an object of type derived will not coincide with a pointer of type derived into the same object. At this point, if a virtual method from base2 is called, the system must perform some magic to recalculate the correct position of the implicit this argument that is handed into the derived::method_from2 virtual method (that must point back to the whole derived object and not just the base2 subobject.

David Rodríguez - dribeas