Thursday, September 11, 2014

C++ Interface Example

#include <iostream>
#include <vector>

using namespace std;

// Animal attribute/property is common between Cow and Dog, hence this is the interface
// that contains pure virtual functions of the property that is common to Cow and Dog
// Since this is pure abstract class (since it has a pure virtual function), this class 
// cannot be instantiated.
class Animal
{
public:
    virtual void Speak() const = 0;
};

// Note:
// You can have an implementation of a pure virtual function.
// A derived class can explicitly call the base class implementation (if access permissions are allow it) 
// by using a fully-scoped name (by calling Animal::Speak(), if Animal::Speak() is public or protected (i.e. not private).

// The use case can be when there's a more-or-less reasonable default behavior, but the class 
// designed wants that sort-of-default behavior to be invoked only explicitly. 
// It can also be the case what you want derived classes to always perform their own work but also be able to call a common set of functionality.

// The other use could be for the case when you want to create a pure abstract class, but it does not have a pure virtual function.
// In that case you can make the destructor a pure abstract method and create the implementation for the destructor.

// Note that even though it's permitted by the language, it's not something that I see commonly used 
// (and the fact that it can be done seems to surprise most C++ programmers, even experienced ones).

void Animal::Speak() const
{
    cout << "Make some noise" << endl; 
}

class Cow : public Animal
{
public:
    void Speak() const;
};

void Cow::Speak() const
{
    cout << "Moo" << endl;
}

class Dog : public Animal
{
public:
    void Speak() const;
};

void Dog::Speak() const
{
    cout << "Woof" << endl;
}

void Speak(const Animal& animal)    // 1. Since we are passing a const reference, this can only call a const member function.
{                                   //    So we will have to make Animal::Speak() const and in turn Cow::Speak() and Dog::Speak() const
    animal.Speak();                 // 2. Passing a non const reference will let you modify Animal
}                                   // 3. Passing by value will lead to object slicing

int main(int argc, char *argv[])
{
    Cow myCow;
    Dog myDog;

    vector<Animal*> animalVec;      // You can't instantiate abstract classes, thus a vector of abstract classes can't work.
                                    // You can however use a vector of pointers to abstract classes.
                                    // Also storing by value i.e. vector<Animal> animalVec; will lead to object slicing
    animalVec.push_back(&myCow);
    animalVec.push_back(&myDog);

    for(vector<Animal*>::iterator iter = animalVec.begin(); iter != animalVec.end(); ++iter)
    {
        Speak(**iter);
    }

    system("PAUSE");
    return EXIT_SUCCESS;
}
Output:
Moo
Woof
Press any key to continue . . .

No comments:

Post a Comment