Understanding Abstraction
Abstraction is the process of hiding the complex implementation details of a system while exposing only the necessary functionalities or interfaces to the outside world. It allows developers to focus on what an object does rather than how it does it.
Achieving Abstraction
Abstract Classes
In C++, abstraction is often achieved using abstract classes. An abstract class is a class that cannot be instantiated and may contain one or more pure virtual functions.
Pure Virtual Function
A pure virtual function is a virtual function with no implementation provided in the base class. It serves as a placeholder for functions that must be implemented by derived classes.
Pure virtual functions are functions declared with the virtual keyword and assigned a = 0 specifier in the abstract class.
Interfaces
Interfaces in C++ are abstract classes with only pure virtual functions. They define a contract that concrete classes must adhere to by implementing all the functions declared in the interface.
Difference between Abstract Class and Interface
Definition:
- Abstract Class: An abstract class is a class that cannot be instantiated on its own and may contain both concrete and abstract (pure virtual) member functions. Abstract classes can have member variables and constructors.
- Interface: An interface in C++ is represented by an abstract class containing only pure virtual functions. It provides a contract that classes implementing the interface must adhere to, but it does not contain any member variables or concrete function implementations.
Usage:
- Abstract Class: Abstract classes are used when you want to provide a common base implementation for a group of related classes, while allowing specific subclasses to provide their own implementations for certain methods. Abstract classes can have some common behavior that is shared among subclasses.
- Interface: Interfaces are used when you want to define a contract or set of behaviors that multiple unrelated classes must implement. Interfaces define what a class can do without specifying how it does it, promoting loose coupling between classes.
Inheritance:
- Abstract Class: Classes can inherit from abstract classes and provide concrete implementations for the pure virtual functions. Subclasses may also inherit member variables and concrete member functions from the abstract class.
- Interface: Classes implement interfaces by providing concrete implementations for all the pure virtual functions declared in the interface. A class can implement multiple interfaces, but it cannot inherit from more than one class.
Flexibility:
- Abstract Class: Abstract classes provide more flexibility than interfaces because they can contain both concrete and abstract member functions, as well as member variables. Subclasses can choose which methods to override and which to inherit from the abstract class.
- Interface: Interfaces promote a higher level of abstraction and decoupling by enforcing a strict contract without allowing any concrete implementations. Classes implementing an interface must adhere to the contract defined by the interface, providing a more uniform and predictable behavior.
Example:
Abstract Class
// Abstract class representing an animal
class Animal {
public:
// Pure virtual function to make this class abstract
virtual void makeSound() const = 0;
// Concrete function shared among all animals
void move() const {
std::cout << "The animal moves.\n";
}
// Virtual destructor
virtual ~Animal() {}
};
// Concrete subclass representing a dog
class Dog : public Animal {
public:
// Implementation of makeSound specific to dogs
void makeSound() const override {
std::cout << "Woof!\n";
}
};
// Concrete subclass representing a cat
class Cat : public Animal {
public:
// Implementation of makeSound specific to cats
void makeSound() const override {
std::cout << "Meow!\n";
}
};
Interface Class
// Interface representing an electronic device
class Device {
public:
// Pure virtual function to make this class an interface
virtual void turnOn() const = 0;
virtual void turnOff() const = 0;
// Virtual destructor
virtual ~Device() {}
};
// Concrete class representing a smartphone
class Smartphone : public Device {
public:
// Implementation of turnOn specific to smartphones
void turnOn() const override {
std::cout << "Smartphone turned on.\n";
}
// Implementation of turnOff specific to smartphones
void turnOff() const override {
std::cout << "Smartphone turned off.\n";
}
};
// Concrete class representing a laptop
class Laptop : public Device {
public:
// Implementation of turnOn specific to laptops
void turnOn() const override {
std::cout << "Laptop turned on.\n";
}
// Implementation of turnOff specific to laptops
void turnOff() const override {
std::cout << "Laptop turned off.\n";
}
};