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
EasyLet'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 calledNotifyFuncthat takes aconst char*message and returns nothing. Then define anINotifierstruct containing only anotifyfunction pointer of this type. Also declare two constructor functions:create_email_notifierandcreate_sms_notifier, each returning anINotifierby value.notifier.c: Implement the concrete notification functions and constructors here. Create:email_notify— prints the message in the format:[EMAIL] messagesms_notify— prints the message in the format:[SMS] messagecreate_email_notifier— returns anINotifierwired toemail_notifycreate_sms_notifier— returns anINotifierwired tosms_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 3pmExample output when type is 2 and message is Your code shipped:
[SMS] Your code shippedThe 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;
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Modular Programming Basics
Header FilesInclude GuardsSource FilesStatic FunctionsRecap: Modular Calculator4Encapsulation
Opaque Pointers ConceptDefining Opaque StructsGetters and SettersValidation in SettersRecap: Secret Box2Objects and Methods
Structs as ObjectsThe 'Self' PointerConst CorrectnessPointer vs ValueHelper MethodsRecap: Point Manager5Project: Simple Bank Account
Project SetupImplementation of Account8Polymorphism
Function Pointers in StructsSimulating MethodsThe Interface ConceptImplementing InterfacesPolymorphic IterationRecap: Greeter3Object Lifecycle
Constructor PatternDestructor PatternStack InitializationDeep CopyRecap: String Wrapper6Inheritance via Composition
Struct EmbeddingThe First Member RuleAccessing Parent MembersUpcastingRecap: Shape Hierarchy