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.