Menu
Coddy logo textTech

Implementing Interfaces

Part of the Object Oriented Programming section of Coddy's C journey — lesson 41 of 61.

Now that you understand what an interface is — a struct containing only function pointers — it's time to create concrete implementations that fulfill that contract.

Recall our ILogger interface from the previous lesson:

typedef void (*LogFunc)(const char* message);

typedef struct {
    LogFunc log;
} ILogger;

To implement this interface, we write actual functions that match the LogFunc signature, then create ILogger instances with those functions assigned:

void console_log(const char* message) {
    printf("[CONSOLE] %s\n", message);
}

void file_log(const char* message) {
    printf("[FILE] %s\n", message);  // Simulating file output
}

ILogger create_console_logger() {
    ILogger logger = { console_log };
    return logger;
}

ILogger create_file_logger() {
    ILogger logger = { file_log };
    return logger;
}

Each "constructor" function returns an ILogger with a different function wired in. Code that uses these loggers doesn't need to know which implementation it received:

void do_work(ILogger* logger) {
    logger->log("Starting work...");
    logger->log("Work complete!");
}

int main() {
    ILogger console = create_console_logger();
    ILogger file = create_file_logger();
    
    do_work(&console);  // Uses console_log
    do_work(&file);     // Uses file_log
    return 0;
}

The do_work function is completely decoupled from the logging implementation. You can swap loggers freely without changing any of the core logic — that's the power of programming to an interface.

challenge icon

Challenge

Easy

Let's build a INotifier system that demonstrates how different implementations can fulfill the same interface contract. You'll create concrete notifiers — an EmailNotifier and an SMSNotifier — that both conform to a common interface but produce different outputs.

You'll organize your code across three files:

  • notifier.h: Define the interface here. Create a function pointer type called NotifyFunc that takes a const char* message and returns nothing. Then define an INotifier struct containing only a notify function pointer of this type. Also declare two constructor functions: create_email_notifier and create_sms_notifier, each returning an INotifier by value.
  • notifier.c: Implement the concrete notification functions and constructors here. Create:
    • email_notify — prints the message in the format: [EMAIL] message
    • sms_notify — prints the message in the format: [SMS] message
    • create_email_notifier — returns an INotifier wired to email_notify
    • create_sms_notifier — returns an INotifier wired to sms_notify
  • main.c: Bring everything together here. Read a notification type and a message, create the appropriate notifier using the constructor functions, and send the notification through the interface.

Your program will receive two inputs: a notification type (1 for email, 2 for SMS) and a message to send.

Use the constructor functions to create the appropriate notifier, then call notify through the interface to display the message.

Example output when type is 1 and message is Meeting at 3pm:

[EMAIL] Meeting at 3pm

Example output when type is 2 and message is Your code shipped:

[SMS] Your code shipped

The power of this pattern is that main.c doesn't need to know how each notifier works internally — it simply calls the interface's notify function, and the correct implementation executes. Remember to use include guards in your header file.

Try it yourself

#include <stdio.h>
#include "notifier.h"

int main() {
    int type;
    char message[256];
    
    // Read the notification type (1 for email, 2 for SMS)
    scanf("%d", &type);
    getchar(); // consume newline
    
    // Read the message
    fgets(message, sizeof(message), stdin);
    // Remove trailing newline if present
    int len = 0;
    while (message[len] != '\0') len++;
    if (len > 0 && message[len-1] == '\n') message[len-1] = '\0';
    
    // TODO: Create the appropriate notifier based on type
    // Use create_email_notifier() for type 1
    // Use create_sms_notifier() for type 2
    
    // TODO: Call the notify function through the interface
    // notifier.notify(message);
    
    return 0;
}
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Object Oriented Programming