1. Basic concepts
1.1. Concrete class
Concrete class is a class that can be used to specify any specific entity. For example, class Car:
class Car{ string color; string model; public: string getColor(){ return this->color; } void setColor(string color){ this->color = color; } string getModel(){ return this->model; } void setModel(string model){ this->model = model; } }
The class Car has two attributes color and model, so any object instantiated by class Car will be determistic with these attributes.
1.2. Abstract class
Suppose that we add a new method called getTax() to class Car. But this class does not know how to implement this because tax may be depended on car type (assuming car has two types: RegularCar and SupperCar). So we mark virtual keyword for the getTax() function. The class Car now is considered to be abstract.class Car{ string color; string model; public: string getColor(){ return this->color; } void setColor(string color){ this->color = color; } string getModel(){ return this->model; } void setModel(string model){ this->model = model; } virtual float getTax(); }We cannot use abstract class directly and the classes inheriting from this class have to provide implementation of the virtual methods.
class SportCar : public Car{ public: float getTax(){ return 2000f; } }
1.3. Interface
In C++ we may consider an interface as a pure abstract class (with no implementation code). For example:
class Shape{ public: virtual float getArea(); virtual float getPerimeter(); }
class Square : public Shape{ int sideLength; public: float getArea(){ return sideLength*sideLength; } float getPerimeter(){ return 4*sideLength; } }
1.4. Why do we need Interfaces and Abstract Classes
We use interfaces and abstract class when:
- We need multiple class to behave in a polymorphic way
- We need some kind off contract to enforce on the classes.
- We need multiple class to behave in a polymorphic way
- We need some kind off contract to enforce on the classes.
2. Program to an interface, not an implementation
This principle means uses interfaces from other part of the application rather than the concrete implementation. When we work on a software, we often spend much time maintaining than developing. If we programming to an implementation, when the requirement change, we need much more efforts in modifying code. For example:
class Dog{ public: void run(){ cout <<"A dog is running"; } } Class Collection{ public: void performAnimalAction(){ Dog *dog = new Dog; dog -> run(); } }This example, use concrete implementation (Dog), it work fine if we has only Dog in Collection. Imagine that we add a new class called Cat to the class Collection later, the performAnimalAction() function will be messed up.
To handle this problem, we create a interface Animal, and use interface instead of concrete implementation in performAnimalAction() function.
class Animal{ public: virtual void run(); } class Dog : public Animal{ public: void run(){ cout <<"A dog is running"; } } class Cat : public Animal{ public: void run(){ cout <<"A cat is running"; } } class Collection{ public: void performAnimalAction(Animal *_animal){ Animal *animal = _animal; animal->run(); } } int main(){ Collection *collection = new Collection; collection->performAnimalAction(new Dog); collection->performAnimalAction(new Cat); }