Pointer-Vector Specialization

This week's project is an extension of the vector template you created in Lab 2. Using the techniques discussed in class, create a partial specialization for vectors of pointers, so that having many different instantiations of vectors-of-pointers won't markedly increase the overall binary file size generated by the compiler.

You will likely want to create a class-template that is a base class for the vector template (e.g. you could call it "vec_base"), so that both vectors-of-pointers and vectors-of-everything-else are able to leverage the same common implementation. This base-class template would handle common details like growing the array of elements, clearing the array of elements, etc.

Don't forget to use protected on the members that shouldn't be public, but that should still be accessible by the subclass template. Also, don't forget about the various pitfalls that one can encounter when attempting to create class-template hierarchies. (Many of them can be resolved by prepending this-> to member-function and data-member access, for the reasons discussed in class.)

The general vector template would derive from this base-class template, and provide support for general types. But then, you would also need to provide a partial specialization for vectors-of-pointers, so that you can provide a special implementation for these. The general approach will be to have these vectors-of-pointers derive from a vector-of-void* base-class instantiation, so that the specialized vector really only has to provide reinterpret-cast operations for reading and writing vectors of T* instead of vectors of void*.

Note that you do not necessarily have to use private subclassing in your implementation; this is merely the approach discussed in class. There are basically three ways you can leverage the implementation of one class in another class:

Public inheritance

This is the kind of inheritance used most often in C++.

  class Base { ... };

  class Derived : public Base { ... };

This approach models an is-a relationship: Derived "is a" Base. This is most appropriate when Derived is in fact a specialization of Base. For example, it makes sense for Triangle to be a subclass of Shape, since a triangle "is a" shape.


This is also a very common approach in C++. When one class needs to use an object of another type, it simply declares a data member of that type. This approach models a has-a relationship.

  class C1 { ... };
  class C2 {
      // Use C1 in the implementation of C2
      C1 c1_obj;

Continuing our shape example, a Circle class "has a" center-point, which might be represented with a 2D Point class. The Circle can rely on the Point implementation, but the circle "has a" center-point; it is not accurate to say that a circle "is a" point.

Private (or protected) inheritance

This is a very uncommon approach in C++, but it is also an option that the language provides.

  class Base { ... };
  // Implement Derived1 and Derived2 in terms of Base
  class Derived1 : private Base { ... };

  class Derived2 : protected Base { ... };

Both of these approaches model an "is-implemented-in-terms-of" relationship, because it is not evident to code outside of Derived1 or Derived2 that they are actually subclasses of Base. In other words, the public and protected members of Base are accessible within Derived1 and Derived2, but the public members of Base are not publicly exposed on Derived1 or Derived2.

The difference between Derived1 and Derived2 is that subclasses of Derived2 are also able to access the public and protected members of Base, but subclasses of Derived1 are not able to access any members of Base.

This approach is not used very frequently for several reasons. The biggest issue is that it weakens encapsulation: the subclasses are allowed to access the protected members of Base. Secondarily, this approach encourages abuse of multiple inheritance, e.g. if you wanted to implement Derived3 in terms of Base1, Base2, and Base3! Finally, there are few differences between this approach and simply using composition (having a data member in Derived that is of type Base). So if you don't get very much from using a very confusing feature, why not just stick to the more basic approaches that work perfectly fine?

The upshot of all of this is that you should not feel like you must use private inheritance in your implementation of this lab, just because we discussed that approach in the lecture. If composition yields an equally straightforward implementation, do that instead!


Unfortunately, life conspired to prevent Donnie from writing a test suite specifically for this assignment this term. Your code should still pass all the tests for the previous lab. Additionally, if you want to write some new tests for vectors-of-pointers, Donnie would be eternally grateful... as long as your tests are actually good...

Binary Size of Vector-of-Pointers Implementation

To see if your partial specialization has been worth the trouble, perform a similar test to what you did last week.

All Done!

When you have completed all of the above, submit your work on csman, including the following: