A Demonstration of Object Pointers in C++

Posted in software by Christopher R. Wirz on Sun Feb 18 2018



Using array indexing to store data has its utility in a C style API. With a single header include, you can use the functionality of a compiled library though its C bindings. Let's see an example...

First declare the API with the functions we need. This api always has a constructor and cleanup/dispose method.


// ClassName_API.h
#ifndef ClassName_API_H_Include
#define ClassName_API_H_Include

#ifdef WIN32 // declared when compiling with windows (if not, declare it)
    #ifdef API_EXPORT // must be declared in Preprocessor Definitions
        #define API __declspec(dllexport)
    #else
        #define API __declspec(dllimport)
    #endif
#else
    #define API
#endif

extern "C" {
    // Constructor...  Could also be written  void ClassName_ctor(void** ptr)
    API void* ClassName_ctor();
    API void ClassName_Dispose(void* ptr);

    // Create an array (specific to the ClassName object)
    API void ClassName_CreateArray(void* ptr, unsigned char** arr);

    // Write out the array created by the ClassName object
    API void ClassName_WriteArray(void* ptr, unsigned char* arr);
}
#endif

Now we need to define the class that does the heavy lifting.


// ClassName.hpp
#ifndef ClassName_HPP_Include
#define ClassName_HPP_Include

#include <iostream>

class ClassName {
    public:
        ClassName(){}
        unsigned char* CreateArray(){
            unsigned char* ptr = (unsigned char*)malloc(sizeof(unsigned char)*26);
            for (int n = 0; n < 26; n++){
                ptr[n] = 65+n;
            }
            return ptr;
        }
        void WriteArray(unsigned char* arr){
            unsigned char* ptr = arr;
            for (int n = 0; n < 26; n++){
                cout << "arr[" << n <<"] = " << *ptr << "\n";
                ptr++;
            }
        }
        ~ClassName(){};
};
#endif

Next, wrap the class in the API method definitions.


// ClassName_API.c
#ifndef ClassName_API_C_Include
#define ClassName_API_C_Include

#include "ClassName_API.h"
#include "ClassName.hpp"

void* ClassName_ctor(){
    return new ClassName();
}
void ClassName_Dispose(void* ptr){
    if (ptr== NULL){return;}
    delete ((ClassName*)ptr);
    ptr = NULL;
}

void ClassName_CreateArray(void* ptr, unsigned char** arr){
    *arr = ((ClassName*)ptr)->CreateArray();
}
void ClassName_WriteArray(void* ptr, unsigned char* arr){
    ((ClassName*)ptr)->WriteArray(arr);
}
#endif

Finally, we can write a main program to demonstrate the functionality.


// main.cpp

#include <iostream>
#include "ClassName_API.h"

int main()
{
    void* ptr = ClassName_ctor();
    unsigned char* arr = NULL;
    ClassName_CreateArray(ptr, &arr);
    ClassName_WriteArray(ptr, arr);
    ClassName_Dispose(ptr);
    free(arr);
    return 0;
}

Let's see the output...

arr[0] = A
arr[1] = B
arr[2] = C
    ...
arr[23] = X
arr[24] = Y
arr[25] = Z

Okay, the array indexing demonstration is complete. You can see the full results if you run this online.

While a string is one of the most common examples, its elements are not very complicated. Take a RGB pixel, for example. It has three components.


struct RBG {
    unsigned char R;
    unsigned char G;
    unsigned char B;
};

I have seen this type of code written:


void set_buffer_grey(unsigned char* buffer, int nPixels){
    int p = 0;
    unsigned char* position = buffer;
    while (p < nPixels){
        *position++ = 64; // set Red
        *position++ = 64; // set Green
        *position++ = 64; // set Blue
        p++;
    }
}

If you are off by just one index, the entire code will produce an incorrect result.

It seems much safer and easier to use a structure, and move through memory based on the structure's size... This seems easier to me:


void set_buffer_grey(unsigned char* buffer, int nPixels){
    int p = 0;
    RBG* position = (RBG*)buffer;
    while (p < nPixels){
        position->R = 64; // set Red
        position->G = 64; // set Green
        position->B = 64; // set Blue
        position++;
        p++;
    }
}

Let's try a non-greyscale image and show it in an entire program, this time displaying results:


#include <stdio.h>

// Define a struct for RGB color
struct RBG {
    unsigned char R;
    unsigned char G;
    unsigned char B;
};

int main()
{
	// unsigned char* arr = new unsigned char[6]{1, 2, 3, 4, 5, 6};
    unsigned char* buffer = new unsigned char[6];
    RBG* rgb = (RBG*)buffer;

	// setting all the values
	for (int i = 1; i <=6; i++){
		// same as *buffer = i; buffer = buffer + 1;
		// same as buffer[0] = i; buffer++;
		*buffer++ = i;
	}

    printf("rgb[0] = {%d, %d, %d}\n", (*rgb).R, (*rgb).G, (*rgb).B);
    rgb++; // same as rgb = rgb + 1;
    printf("rgb[1] = {%d, %d, %d}\n", (*rgb).R, (*rgb).G, (*rgb).B);

    printf("There you have it!");

    return 0;
}

The value of each element in the array displays correctly.


rgb[0] = {1, 2, 3}
rgb[1] = {4, 5, 6}
There you have it!