Value semantics C++
What is value and/or reference semantics, and which is best in C++?
With reference semantics, assignment is a pointer-copy (i.e., a reference). Value (or “copy”) semantics mean assignment copies the value, not just the pointer. C++ gives you the choice: use the assignment operator to copy the value (copy/value semantics), or use a pointer-copy to copy a pointer (reference semantics). C++ allows you to override the assignment operator to do anything your heart desires, however the default (and most common) choice is to copy the value.
Pros of reference semantics: flexibility and dynamic binding (you get dynamic binding in C++ only when you pass by pointer or pass by reference, not when you pass by value).
Pros of value semantics: speed. “Speed” seems like an odd benefit for a feature that requires an object (vs. a pointer) to be copied, but the fact of the matter is that one usually accesses an object more than one copies the object, so the cost of the occasional copies is (usually) more than offset by the benefit of having an actual object rather than a pointer to an object.
There are three cases when you have an actual object as opposed to a pointer to an object: local objects, global/static objects, and fully contained member objects in a class. The most important of these is the last (“composition”).
More info about copy-vs-reference semantics is given in the next FAQs. Please read them all to get a balanced perspective. The first few have intentionally been slanted toward value semantics, so if you only read the first few of the following FAQs, you’ll get a warped perspective.
Assignment has other issues (e.g., shallow vs. deep copy) which are not covered here.
What is “virtual data, ” and how-can / why-would I use it in C++?
virtual data allows a derived class to change the exact class of a base class’s member object. virtual data isn’t strictly “supported” by C++, however it can be simulated in C++. It ain’t pretty, but it works.
To simulate virtual data in C++, the base class must have a pointer to the member object, and the derived class must provide a new object to be pointed to by the base class’s pointer. The base class would also have one or more normal constructors that provide their own referent (again via new), and the base class’s destructor would delete the referent.
For example, class Stack might have an Array member object (using a pointer), and derived class StretchableStack might override the base class member data from Array to StretchableArray. For this to work, StretchableArray would have to inherit from Array, so Stack would have an Array*. Stack’s normal constructors would initialize this Array* with a new Array, but Stack would also have a (possibly protected) constructor that would accept an Array* from a derived class. StretchableStack’s constructor would provide a new StretchableArray to this special constructor.
- Easier implementation of StretchableStack (most of the code is inherited)
- Users can pass a StretchableStack as a kind-of Stack
- Adds an extra layer of indirection to access the Array
- Adds some extra freestore allocation overhead (both new and delete)
- Adds some extra dynamic binding overhead (reason given in next FAQ)