Tuesday, May 22, 2012

My C++ Interface

In my young days (not too long ago mind you), I started out with C++. I have always had a fondness for the language, despite the simplicity and support for Java. I wanted to write a simple post, so I decided to make a cute little interface and implement it in C++. C++ does not have actual interfaces like Java; however, a careful programmer can create pure virtual classes that can behave like interfaces. Implementing classes have the responsibility of overriding those virtual functions so that they are meaningful.
To implement the interface, the sub class would have to be an extension. In the land of Java, multiple inheritance is so frowned upon that the language prevents the developer from even doing it; C++ doesn't have such a restriction. Therefore, one can follow the same design patterns in Java (if they are careful).

A Brief Demonstration

In C++, virtual functions can allow late binding. This means that I can create classes that are implementations of the interface and later assign those instances to function arguments or pointers of type IMyInterface. The following code set will demonstrate that:
#ifndef IMYINTERFACE_H
#define IMYINTERFACE_H
using namespace std;

class IMyInterface{
public:
    virtual char * returnContent(){
        return "";
    }

};

#endif
The above class is a standard C++ class called IMyInterface. Clearly, it is labeled as an interface. There is only one function defined in the class, using the keyword virtual. It returns a type of char *, which is kind of like a String (for this example, I wanted to avoid as much of the STL as possible, despite the fact that I declare it as my default namespace at the top of the page).

The following code samples are implementations of that interface (in reality, extensions of a class):
#ifndef IMPLEMENTOR_H
#define IMPLEMENTOR_H
#include "IMyInterface.h"
using namespace std;

class Implementor: public IMyInterface{
private:
    int a;
public:
    Implementor(){
        a = 0;
    }

    char * returnContent(){
        return "This is [Implementor]";
    }

    static Implementor * getInstance(){
        return new Implementor();
    }

    void setA(int a){
        this->a = a;
    }
};

#endif

#ifndef ANOTHERDEMONSTRATION_H
#define ANOTHERDEMONSTRATION_H
#include "IMyInterface.h"
using namespace std;

class AnotherDemonstration : public IMyInterface{
public:
    char * returnContent() {
        return "This is [AnotherDemonstration]";
    }
};

#endif
The first code snippet has some useless traffic, but notice that it does override the virtual function. The latter class has no excessive traffic, and overrides the virtual function. The following is the run-time snippet that I am going to execute:
#include <iostream>
#include "Implementor.h"
#include "IMyInterface.h"
#include "AnotherDemonstration.h"
using namespace std;

    void displayable(IMyInterface * );

    int main(){
        AnotherDemonstration myThirdClass;
        Implementor * anotherImpl = Implementor::getInstance();
        displayable(anotherImpl);
        displayable(&myThirdClass);

    }

    void displayable(IMyInterface * object){
        cout << object->returnContent() << endl;
    }
The above snippet does the following:
  1. The first two lines create our instances of the implementations of IMyInterface; both are separate instances of their respective types, but are sub classes of their common parent type.
  2. The third line calls a function that accepts a point to an IMyInterface instance. This function calls the interface method IMyInterface::returnContent(). At execution time, late binding will occur calling the instance's implementations version of the function.
  3. The third line passes anotherImpl into the function.
  4. myThirdClass is not a type of IMyInterface *. Therefore, I pass in an address reference using the ampersand operator. This address reference will serve as the pointer to the instance myThirdClass.
I added a statement to hold up execution of the code so that I can get a print-screen of the execution:

When developing C++, keeping little tricks like the above in mind can save quite a bit of code. Don't fear the pointer, embrace the pointer (since all Java developers do, implicitly).

No comments:

Post a Comment