Implementing Java-like Abstract Functions in C++

Viplove Mittal
4 min readNov 8, 2024

In languages like Java, the concept of abstract functions is elegantly supported through interfaces. Interfaces are user-defined types where all methods are purely declarative; they contain only function signatures and no implementations. Any class that implements an interface must provide concrete implementations for all methods, thereby adhering to a contract. However, C++ lacks a dedicated interface keyword, but we can still create similar structures using pure virtual functions to enforce contract-based programming. Let’s look at how C++ developers can implement Java-style abstract functions and even provide default implementations within an abstract base class.

Understanding Pure Virtual Functions in C++

In Java, the interface keyword provides a way to create contracts for classes by defining methods without implementations. In C++, we achieve similar behavior using abstract classes with pure virtual functions. Let’s dive into how to model this with a transportation system, where different types of vehicles inherit from a shared interface.

Step 1: Define an Abstract Base Class with Pure Virtual Functions

#include <iostream>
#include <string>

class Vehicle {
public:
// Pure virtual functions to enforce that each vehicle implements its own start and stop functions
virtual std::string start() const = 0;
virtual std::string stop() const = 0;

// Virtual destructor for proper cleanup of derived objects
virtual ~Vehicle() = default;
};

In this code:

  • Vehicle is an abstract class with two pure virtual functions: start() and stop().
  • Each derived class will have to provide its own implementation of start() and stop(), just as Java classes implement methods defined in an interface.

Step 2: Implement Concrete Vehicle Classes

Now we’ll define specific types of vehicles: Car and Bicycle. Both classes will inherit from Vehicle and provide unique implementations for start() and stop().

class Car : public Vehicle {
public:
std::string start() const override {
return "Car starts with the turn of a key or push of a button.";
}

std::string stop() const override {
return "Car stops by pressing the brake pedal.";
}
};

class Bicycle : public Vehicle {
public:
std::string start() const override {
return "Bicycle starts by pedaling.";
}

std::string stop() const override {
return "Bicycle stops by pressing the hand brakes.";
}
};

In this example:

  • Car and Bicycle each implement start() and stop() in ways unique to their operation.
  • This setup ensures every derived class adheres to the Vehicle contract, just like a Java interface would require.

Step 3: Adding a Default Implementation for a Pure Virtual Function

In some cases, we might want a default implementation for a function to provide shared behavior across derived classes. C++ allows us to define a default implementation for a pure virtual function outside the class definition, which derived classes can choose to call.

Let’s add a new method, move(), that will have a default implementation in Vehicle but still be declared as pure virtual:

class Vehicle {
public:
virtual std::string start() const = 0;
virtual std::string stop() const = 0;
virtual std::string move() const = 0; // Pure virtual with default implementation

virtual ~Vehicle() = default;
};

// Default implementation of the move() function
std::string Vehicle::move() const {
return "The vehicle is moving forward.";
}

class Car : public Vehicle {
public:
std::string start() const override {
return "Car starts with the turn of a key or push of a button.";
}

std::string stop() const override {
return "Car stops by pressing the brake pedal.";
}

std::string move() const override {
return Vehicle::move() + " Car accelerates down the road.";
}
};

class Bicycle : public Vehicle {
public:
std::string start() const override {
return "Bicycle starts by pedaling.";
}

std::string stop() const override {
return "Bicycle stops by pressing the hand brakes.";
}

std::string move() const override {
return Vehicle::move() + " Bicycle coasts along the path.";
}
};

In this code:

  • Vehicle::move() provides a default implementation, allowing all vehicles to use a common "moving forward" description.
  • Both Car and Bicycle override move() but incorporate the base class functionality by calling Vehicle::move() within their own implementations.

Step 4: Using the Classes

We can now create instances of Car and Bicycle, demonstrating how each implements the abstract functions in its unique way.

int main() {
Car car;
Bicycle bicycle;

std::cout << car.start() << std::endl;
std::cout << car.move() << std::endl;
std::cout << car.stop() << std::endl;

std::cout << bicycle.start() << std::endl;
std::cout << bicycle.move() << std::endl;
std::cout << bicycle.stop() << std::endl;

return 0;
}

Output:

Car starts with the turn of a key or push of a button.
The vehicle is moving forward. Car accelerates down the road.
Car stops by pressing the brake pedal.
Bicycle starts by pedaling.
The vehicle is moving forward. Bicycle coasts along the path.
Bicycle stops by pressing the hand brakes.

Summary

Using abstract classes with pure virtual functions in C++, you can achieve a Java-like interface pattern. Here’s a recap of the key points:

  • Pure Virtual Functions enforce that derived classes implement required methods.
  • Default Implementations allow the abstract base class to provide common behavior that derived classes can use or extend.
  • Polymorphic Design through abstract classes enables a flexible and extensible structure in object-oriented programming.

This example illustrates how C++ offers a robust way to design interfaces and shared behavior, even without a dedicated interface keyword. By understanding pure virtual functions and default implementations, you can design versatile and reusable code in C++.

Sign up to discover human stories that deepen your understanding of the world.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

No responses yet

Write a response