The Secret Life of C++: Objects

We talked about structs in C. Lets take a look at C++ structs and classes.

Just Fields

First, a basic struct with no constructor:

        

        

        

        

        
basic-struct.cc, basic-struct.s, basic-struct.listing. Some of the symbols we see here bear explaining:
_Znwj
Translates into the new operator over the type unsigned int
_ZdlPv
delete a pointer to a void.

Simple Methods

Next, a basic class this time (really no difference), still no constructor, this time we call some simple get/set methods:

        

        

        

        

        
basic-method, basic-method.s, basic-method.listing. Some symbols again:
_ZN8onefield8setFieldEi
method onefield::setField(int)
_ZNK8onefield8getFieldEv
Konst method onefield::getField(void)

Notice that the this pointer gets passed as the first argument to both functions, as you might expect.

Constructors

Lets give our simple object a constructor and a destructor, and see how that goes:

        

        

        

        

        
basic-constructor.cc, basic-constructor.s, basic-constructor.listing. And we get more symbols to decode:
_ZN8onefieldC1Ei
onefield Constructor (C1 means it a is complete object constructor) that takes an int parameter.
_ZN8onefieldD1Ev
onefield complete object desctructor, no parameters.

Temporary Objects

When you call a function with an object, and you don't pass a pointer/reference, the function gets a copy of the object. Similarly when you return an object, there is a temporary one created for the return.

Temporary Objects as Arguments

When passing a temporary object as an argument, the caller must make space on the stack, call the constructor, pass a reference/pointer to the object, and then call the destructor when the life of the object is over. It could also be allocated on the heap.

Lets look at the first case, using our onefield object again:


        

        

        

        

        
object-arg.cc, object-arg.s, object-arg.listing. And some more symbols:
_ZN8onefieldC1ERKS_
onefield constructor that takes a Reference to a Konst onefield. S_ is shorthand. In this case for onefield.
_Z5print8onefield_Z5print8onefield
This is our print(onefield) function.

Temporary Objects as Return Values

When returning an object from a function, if the object is non-trivial, than the caller allocates temporary space and passes a pointer to the space as a first argument to the function. The function calls the constructor. The caller is responsible for calling the destructor when the object is no longer needed.

Examples, using a twofield object:


        

        

        

        

        
object-ret.cc, object-ret.s, object-ret.listing. Covered in class, but have to add it here: TODO: cover the following basic virtual dispatch material, which was covered on day 1 2015. TODO: This wanted a picture. As we have seen, calling non-virtual methods with objects isn't very complicated. Now lets talk about virtual methods and subclassing.

Virtual Methods - Call by Pointer/Reference

How do virtual methods work? With a vtable. What a vtable? Lets look at an example: basic-vtable.cc, basic-vtable.s, basic-vtable.listing.
_ZTV8onefield
A pointer to the VTable of the onefield object.
_ZTI8onefield
A pointer to the typeinfo structure for onefield.
_ZTVN10__cxxabiv117__class_type_infoE+8
Pointer to the VTable for the implementation object of class_type_info.

Virtual Methods - Overriding

Lets do an example where we override a virtual method: subclass-vtable.cc, subclass-vtable.s, subclass-vtable.listing.
_ZTV17onefield_subclass
This is the vtable for onefield_subclass.
As we can see, the subclass vtable has the same entries as the superclass, but where they are overridden we see the subclass methods replacing the superclass methods where appropriate.

Virtual Methods - Call by "Value"

When you call a virtual method on a local or temporary variable, the compiler really does know the type of the variable, and so it doesn't have to go through the vtable. This is a useful optimization. It can be seen in the basic-vtable example above.

It is also why you have to make sure to pass a subclass into a method expecting a superclass by reference, not by copyconstructing an instance of the superclass. Becuase the later technique will cause the superclass functions to get called, rather than the subclass ones, even if they are virtual.

Pure Virtual Methods

Pure virtual methods are just funny entries in the vtable. Specifically pointers to __cxa_pure_virtual. An example: vtable-null.cc, vtable-null.s, vtable-null.listing.

Virtual Destructors

You want a virtual destructor becuase otherwise someone might delete your object when they have a pointer to a superclass, and your destructor won't get run. Simple as that.

Subclasses

To see subclasses that add data values, we can look back at our subclass-vtable example: subclass-vtable.cc, subclass-vtable.s, subclass-vtable.listing. Fork me on GitHub