Using Void Pointers and Generics with the C++ Programming Language

C++ Programming Language is currently a widely used powerful language, which allows for Object Oriented Development with Classes, and also has advanced features such as the Standard Template Library (STL) and also the use of Generics. Not only is it fully Object Oriented, but C++ also allows for low level memory management, and the C Programming Language is backwardly compatible with C++.

C++ is particularly well suited for large, complex systems development. Currently, it is the main software platform for the F-35 Joint Strike Fighter, which is the worlds most technologically advanced aircraft. C++ is also the primary software for launch systems of the NASA SLS Rocket, as well as the launch systems for Missile Defense Agency Rockets.

Artemis SLS Rocket

The NASA Artemis SLS Rocket is the new rocket for moon missions and beyond, The launch systems software for the SLS rocket is primarily C++.

The F-35 Joint Strike Fighter, also known officially as the  Lightning II, is manufactured by Lockheed Martin in a joint partnership with the USA Department of Defense and various USA Allies, such as the United Kingdom, Australia, Canada, Norway, and others. It is the most technologically advanced aircraft ever made. Its software is primarily C++.

One thing I encountered in past software work I did, was the use of VOID Pointers (VOID*). At first I was a little confused by them, and did some research, void pointers are primarily a thing that was used with the C programming language, and were used when the developer was unsure of what the type for a particular variable would be during his development. Also, memory allocation in C with the malloc command always returns a void pointer, which C programmers normally cast to another type right after the method is called. Void pointers have the following properties.

  • Do not have a type, are typeless, but can hold the memory address of another variable
  • A void pointer can point to objects of any type
  • Cannot be dereferenced, since the computer has no idea of the amount of memory taken up
  • Can only be dereferenced after being cast as another variable type
  • Cannot have pointer arithmetic done on them
  • Although some compilers allow deleting a void pointer that points to dynamically allocated memory, doing so should be avoided, as it can result in undefined behavior.

As part of the Department of Defense Joint Strike Fighter Project, a document was released to the public domain on standards for safety-critical C++ software, the F-35 Joint Strike Fighter C++ Coding Standards Document.

F-35 Joint Strike Fighter C++ Coding Standards Document CLICK HERE

According to this document, void pointers and cast of variables to other types SHALL not be used in safety-critical C++ software. In this blog post I will show us how to work with and manage void pointers, and also detail how C++ has replaced void pointers with generic programming with templates. I will show example code of working with both void pointers and also generic type templates.

First we will start with our include files for void pointers and template generics for our example C++ program.

#include <iostream>
#include <string>
#include <vector>
#include <cstdlib>

using namespace std;

Next, we will declare some integer, float, and char string variables, and also our void pointer, to use in our example.

// declare vars
int nNumber = 10;
float fNumber = 10.01;
char cCharArray[] = "This is an example C++ application.";

// void pointer
void* ptrVoid;

Also, not a part of our example program for this blog post, here is an example of how a void pointer is returned by memory allocation using MALLOC command in C programming language, and then immediately cast to another type.

struct zooAnimal *zooKeeper = NULL;
	
// create a 3 year old 300 pound male lion, make start node of list
struct zooAnimal *lion1 = (struct zooAnimal*)malloc(sizeof(struct zooAnimal));
if (NULL == lion1)
{
	printf("\n Lion creation failed \n");
	return 1;
}
lion1->type = Lion;
lion1->sex = Male;
lion1->age = 3;
lion1->weight = 300;
lion1->next = NULL;

// the zoo keeper starts with this lion 
// before going through the list of animals
zooKeeper = lion1;

Then in our next section of code for our example program, we will demonstrate setting the void pointer variable to the memory address of another variable, and then show to cast it to another variable type with two different methods, using the C++ STATIC CAST method, and also doing a C-style cast as well. Take note, it is far safer and much better software development to use a C++ static cast instead of a C-style cast.

// set void pointer to address of integer number,
// then cast to integer so it can be dereferenced
ptrVoid = &nNumber;
cout << endl << "Void pointer to integer address: " << ptrVoid << endl
	<< "dereferenced value static cast: " << *static_cast (ptrVoid) 
	<< endl
	<< "dereferenced value after C-style cast: " << *((int*)ptrVoid) 
	<< endl << endl;

// set void pointer to address of float number,
// then cast to float so it can be dereferenced
ptrVoid = &fNumber;
cout << "Void pointer to float address: " << ptrVoid << endl
	<< "dereferenced value static cast: " << *static_cast (ptrVoid) 
	<< endl
	<< "dereferenced value after C-style cast: " << *((float*)ptrVoid) 
	<< endl << endl;

// set void pointer to address of char array string
// then cast to dereference
// note with char arrays we do not dereference the pointer
// but the non-pointer name of the array
ptrVoid = &cCharArray;
cout << "Void pointer to char array address: " << ptrVoid << endl
	<< "dereferenced value static cast: " << static_cast (ptrVoid) 
 	<< endl 
	<< "dereferenced value after C-style cast: " << (char*)ptrVoid 
	<< endl << endl;

This is what our output will look like after running the example application for void pointers:

Note how the memory addresses for each variable are sequential and occupy the same area in computer memory, this is a good sign that the C++ compiler is compiling machine code that efficiently uses computer memory.

These are good examples of how you would use void pointers in C++ development. However, in C++ there is feature that provides the same functionality as void pointers, but is better to use and allows for object oriented development, which C does not allow. This feature is called generic programming and allows the use of generic class templates and generic function templates, which allow for type-independent development. In our next code examples, we will show to do C++ generic programming.

First, we will define a template function in our C++ code, outside of the main() method, like the following:

// we use a function template for generic programming
template 
T const& Maximum(T const& a, T const& b)
{
	if (a > b) return a;
	if (b > a) return b;
}

Note that there is not a specific type for the Maximum() function parameter, but instead a generic variable called T that can be used for any type.

Next, we will declare variables of different type and call the Maximum() generic function template with them to determine which one is the largest. Note we are using the same function with different types of variables. This is the essence of generic programming in C++, and is a powerful feature for code reusability.

// after the advent of generics in C++
// void pointers, a holdover from C programming, 
// were no longer needed

// vars to use with function template
int x = 11;
int y = 13;
	
float i = 10.56;
float j = 14.32;

string k1 = "C++";
string k2 = "Application";

// output the results
cout << "Maximum integer x or y: " << Maximum(x, y) << endl << endl;
cout << "Maximum float i or j: " << Maximum(i, j) << endl << endl;
cout << "Maximum string k1 or k2: " << Maximum(k1, k2) << endl << endl;

This is what our output will look like after running our example C++ program.

Next, we will define a class template for a class to be used with generic programming in C++. Enter the following code outside of our main method to define our class template. Note we are reusing the generic T type, and not a specific type of variable. Note that in the outputList() method, we are using a vector iterator to loop through the elements, in this case the TYPENAME keyword must be used since it is a generic iterator.

// class template for generic programming
template 
class ElementList {
private:
	vector elements;

public:
	void addElement(T const&); 
	T getLastElement() const;
	void outputList();
};

// addElement method
template 
void ElementList::addElement(T const& element) {
	elements.push_back(element);
}

// getLastElement method
template 
T ElementList::getLastElement() const {

	// return last element
	return elements.back();
}

// output ElementList elements
template 
void ElementList::outputList() {

  cout << "ElementList elements: ";
  for (typename vector::iterator it = elements.begin(); it < elements.end(); it++) {
    cout << (*it) << " ";
  }
  
  cout << endl << endl;
}

Then we will place the following code in our main() method to instantiate objects of type ElementList, and also to output the results of using our generic class template. Note once again we are using only one class for different types of variables, called generic programming.

// vars to use with class template
ElementList strList;
ElementList fList;
ElementList nList;

// add string values to ElementList string object
strList.addElement("C++");
strList.addElement("Object Oriented");
strList.addElement("Application");

// add float value to ElementList float object
fList.addElement(3.14);
fList.addElement(13.1);
fList.addElement(26.2);

// add integer values to ElementList int object
nList.addElement(3);
nList.addElement(11);
nList.addElement(27);

// get the most recent string added to list
cout << "String List last element: " << strList.getLastElement() 
	<< endl << endl;

// get the most recent float element
cout << "Float List last element: " << fList.getLastElement() 
	<< endl << endl;

// get the most recent integer element
cout << "Integer List last element: " << nList.getLastElement() 
	<< endl << endl;

// output the string list
strList.outputList();

// output the integer list
nList.outputList();

// output the float list
fList.outputList();

This is what our output will be after running our example C++ program with generic class template.

Here is a copy-and-pastable listing of our entire C++ example application.

 // CPPTemplatesPointers.cpp
 //
 // By Michael G. Workman
 //
 // This C++ console application displays 
 // usage of VOID pointers and generic templates
 //
 // This example application is freely distributable 
 // under terms of MIT open source license
 // https://opensource.org/licenses/MIT

 #include <iostream>
 #include <string>
 #include <vector>
 #include <cstdlib>

 using namespace std;

 // class template for generic programming
 template <class T>
 class ElementList {
     private:
       vector<T> elements;

     public:
       void addElement(T const&); 
       T getLastElement() const;
       void outputList();
 };

 // addElement method
 template <class T>
 void ElementList<T>::addElement(T const& element) {
     elements.push_back(element);
 }

 // getLastElement method
 template <class T>
 T ElementList<T>::getLastElement() const {

     // return last element
     return elements.back();
 }

 // output ElementList elements
 template <class T>
 void ElementList<T>::outputList() {

     cout << "ElementList elements: ";
     for (typename vector<T>::iterator it = elements.begin(); it < elements.end(); it++) {
       cout << (*it) << " ";
     }
     cout << endl << endl;
 }

 // we use a function template for generic programming
 template <typename T>
 T const& Maximum(T const& a, T const& b)
 {
     if (a > b) return a;
     if (b > a) return b;
 }

 int main()
 {
     // declare vars
     int nNumber = 10;
     float fNumber = 10.01;
     char cCharArray[] = "This is an example C++ application.";

     // void pointer
     void* ptrVoid;

     // change void pointer to address of integer number,
     // then cast to integer so it can be dereferenced
     ptrVoid = &nNumber;
     cout << endl << "Void pointer to integer address: " << ptrVoid
     << endl;
     cout << "dereferenced value static cast: " << *static_cast<int> (ptrVoid)
     << endl;
     cout << "dereferenced value C-style cast: " << *((int*)ptrVoid)
     << endl;

     // set void pointer to address of float number, 
     // then cast to float so it can be dereferenced
     ptrVoid = &fNumber;
     cout << "Void pointer to float address: " << ptrVoid 
     << endl;
     cout << "dereferenced value static cast: " << *static_cast<float> (ptrVoid)
     << endl;
     cout << "dereferenced value C-style cast: " << *((float*)ptrVoid)
      << endl;

     // set void pointer to address of char array string, 
     // then cast to dereference
     // note with char arrays we do not dereference the pointer, 
     // but the non-pointer name of the array
     ptrVoid = &cCharArray;
     cout << "Void pointer to char array address: " << ptrVoid
     << endl;
     cout << "dereferenced value static cast: " << static_cast<char> (ptrVoid)
     << endl;
     cout << "dereferenced value C-style cast: " << (char*)ptrVoid
     << endl;

     // after the advent of generics in C++
     // void pointers, a holdover from C programming, 
     // were no longer needed

     // vars to use with function template
     int x = 11;
     int y = 13;
 
     float i = 10.56;
     float j = 14.32;

     string k1 = "C++";
     string k2 = "Application";

     // output the results
     cout << "Maximum integer x or y: " 
     << Maximum(x, y) 
     << endl << endl;
     
     cout << "Maximum float i or j: " 
     << Maximum(i, j) 
     << endl << endl;
     
     cout << "Maximum string k1 or k2: " 
     << Maximum(k1, k2) 
     << endl << endl;

     // vars to use with class template
     ElementList<string> strList;
     ElementList<float> fList;
     ElementList<int> nList;

     // add string values to ElementList string object
     strList.addElement("C++");
     strList.addElement("Object Oriented");
     strList.addElement("Application");

     // add float values to ElementList float object
     fList.addElement(3.14);
     fList.addElement(13.1);
     fList.addElement(26.2);

     // add integer values to ElementList int object
     nList.addElement(3);
     nList.addElement(11);
     nList.addElement(27);

     // get the most recent string element
     cout << "String List last element: " 
     	<< strList.getLastElement() 
        << endl << endl;

     // get the most recent float element
     cout << "Float List last element: " 
     << fList.getLastElement() 
     << endl << endl;

     // get the most recent integer element
     cout << "Integer List last element: " 
     << nList.getLastElement() 
     << endl << endl;

     // output the string list
     strList.outputList();

     // output the integer list
     nList.outputList();

     // output the float list
     fList.outputList();

     return 0;
 }
 

This example C++ program was created in Microsoft Visual Studio IDE running on Windows 10. Microsoft Visual Studio Community Edition is a free download, while the Professional and Enterprise versions can be purchased. This example C++ program will run equally well on Unix and Linux with either the g++ compiler or the CLANG compiler.

For those who wish to try out and learn Unix, there is a NetBSD Unix shell account available from SDF at http://sdf.org for $9 every 3 months. Also, a free OpenBSD Unix shell account is available on https://tilde.institute. There is free Linux offerings on the internet as well. A free Ubuntu Linux shell account is available at https://tilde.team. Many Linux versions are available as free downloads on the internet as well.

I hope these examples have been very helpful for you to understand void pointers and generic programming in C++. Generic programming is a powerful feature of the C++ programming language that allows for code reusability and simplicity.

To see my Curriculum Vitae, go to

To see this project in Azure DevOps version control, go to C++ Void Pointers and Generics

To see all my projects on Azure DevOps, go to https://dev.azure.com/AbionTechnology/

To see my Posts and Answers on Stack Overflow,
      go to Michael G. Workman on Stack Overflow

 If you have any questions about CC++Microsoft C# .NET,  Microsoft Azure Cloud, Unix, Linux, and/or Mobile Apps, please feel free to contact me by email at:

michael.g.workman@outlook.com


Popular Posts