Exploring the intricacies of computing often involves understanding not just how something works, but also why and how it could be built from scratch. This article delves into the concept of interfaces in object-oriented programming (OOP), using Java as a reference point, and then demonstrates a rudimentary C implementation.
Our example focuses on calculating vehicle prices: cars priced by speed, motorcycles by engine displacement (cc). We begin with a Java interface defining the core vehicle behavior:
<code class="language-java">public interface Vehicle { Integer price(); }</code>
This interface is then implemented by Car
and Motorcycle
classes:
<code class="language-java">public class Car implements Vehicle { private final Integer speed; public Car(Integer speed) { this.speed = speed; } @Override public Integer price() { return speed * 60; } } public class Motorcycle implements Vehicle { private final Integer cc; public Motorcycle(Integer cc) { this.cc = cc; } @Override public Integer price() { return cc * 10; } }</code>
A helper function prints the price:
<code class="language-java">public static void printVehiclePrice(Vehicle vehicle) { System.out.println("$" + vehicle.price() + ".00"); }</code>
The main method demonstrates usage:
<code class="language-java">public static void main(String[] args) { Car car = new Car(120); Motorcycle motorcycle = new Motorcycle(1000); printVehiclePrice(car); // Output: 00.00 printVehiclePrice(motorcycle); // Output: 000.00 }</code>
Replicating this in C requires a different approach.
In C, we lack the built-in interface mechanism of Java. We'll simulate it using structs for data and functions for methods. The compiler doesn't handle interface resolution; we must do it manually.
Our "interface" skeleton:
<code class="language-c">#include <stdio.h> #include <stdlib.h> typedef enum { VEHICLE_CAR, VEHICLE_MOTORCYCLE } VehicleType; typedef struct { VehicleType type; } Vehicle; void vehicle_free(Vehicle *vehicle); int vehicle_price(Vehicle *vehicle);</code>
The Car
implementation:
<code class="language-c">typedef struct { VehicleType type; int speed; } Car; Car *car_init(int speed) { Car *car = malloc(sizeof(Car)); car->type = VEHICLE_CAR; car->speed = speed; return car; } void car_free(Car *car) { free(car); } int car_price(Car *car) { return car->speed * 60; }</code>
The Motorcycle
implementation (similar to Car
):
<code class="language-c">typedef struct { VehicleType type; int cc; } Motorcycle; Motorcycle *motorcycle_init(int cc) { Motorcycle *motorcycle = malloc(sizeof(Motorcycle)); motorcycle->type = VEHICLE_MOTORCYCLE; motorcycle->cc = cc; return motorcycle; } void motorcycle_free(Motorcycle *motorcycle) { free(motorcycle); } int motorcycle_price(Motorcycle *motorcycle) { return motorcycle->cc * 10; }</code>
The price printing function:
<code class="language-c">void print_vehicle_price(Vehicle *vehicle) { printf("$%d.00\n", vehicle_price(vehicle)); }</code>
Crucially, we implement vehicle_free
and vehicle_price
using switch
statements to handle different vehicle types:
<code class="language-c">void vehicle_free(Vehicle *vehicle) { switch (vehicle->type) { case VEHICLE_CAR: car_free((Car *)vehicle); break; case VEHICLE_MOTORCYCLE: motorcycle_free((Motorcycle *)vehicle); break; } } int vehicle_price(Vehicle *vehicle) { switch (vehicle->type) { case VEHICLE_CAR: return car_price((Car *)vehicle); case VEHICLE_MOTORCYCLE: return motorcycle_price((Motorcycle *)vehicle); } }</code>
The main function demonstrates usage:
<code class="language-c">int main(void) { Car *car = car_init(120); Motorcycle *motorcycle = motorcycle_init(1000); print_vehicle_price((Vehicle *)car); // Output: 00.00 print_vehicle_price((Vehicle *)motorcycle); // Output: 000.00 vehicle_free((Vehicle *)car); vehicle_free((Vehicle *)motorcycle); return 0; }</code>
This manual interface approach is particularly useful in scenarios like parsing, where an Abstract Syntax Tree (AST) might benefit from a similar structure. Different node types in the AST can be represented as separate structs, all conforming to a common "interface" defined by a set of functions.
While C lacks built-in interfaces, simulating them with careful struct and function design provides a powerful mechanism for achieving similar OOP principles. This manual approach offers flexibility and control, particularly beneficial in complex projects like parsers and interpreters.
The above is the detailed content of Object-Oriented Programming in C? Implementing an Interface from Scratch. For more information, please follow other related articles on the PHP Chinese website!