Simulating Methods
Part of the Object Oriented Programming section of Coddy's C journey — lesson 39 of 61.
You've seen how to place a function pointer inside a struct. The real power comes when you assign different functions to different instances of the same struct type — this is how we simulate methods with varying behavior.
Consider a struct that represents an action with customizable logic:
typedef void (*ActionFunc)(void);
typedef struct {
const char* name;
ActionFunc execute;
} Action;When creating instances, you wire up different functions to each one:
void say_hello(void) {
printf("Hello!\n");
}
void say_goodbye(void) {
printf("Goodbye!\n");
}
int main() {
Action greet = { "Greet", say_hello };
Action farewell = { "Farewell", say_goodbye };
greet.execute(); // Output: Hello!
farewell.execute(); // Output: Goodbye!
return 0;
}Both greet and farewell are the same type (Action), yet calling execute on each produces completely different results. The struct doesn't just hold data — it holds behavior that varies per instance.
This pattern mirrors how objects work in other languages: each object can have its own implementation of a method, even though they share the same interface.
Challenge
EasyLet's build a Speaker system that demonstrates how different instances of the same struct type can exhibit completely different behaviors based on which function is wired into them.
You'll create two files to organize your code:
speaker.h: Define a function pointer type calledSpeakFuncthat takes no parameters and returns nothing. Then define aSpeakerstruct containing aname(aconst char*) and aspeakfunction pointer of typeSpeakFunc.main.c: Include your header and implement three different speaking functions:bark— printsWoof!meow— printsMeow!chirp— printsChirp!
Speakerinstances, each wired to a different function based on input, and call theirspeakmethods to see polymorphic behavior in action.
Your program will receive two inputs: the first speaker type (1 for bark, 2 for meow, 3 for chirp) and the second speaker type (also 1, 2, or 3).
Create two Speaker instances — you can name them anything you like (such as "Dog", "Cat", "Bird", or simply "Speaker1", "Speaker2"). Wire each one to the appropriate function based on its input code, then call speak on each instance in order.
Example output when the first type is 1 and the second type is 2:
Woof!
Meow!Example output when the first type is 3 and the second type is 3:
Chirp!
Chirp!The key insight here is that both speakers are the same Speaker type, yet they produce different outputs because each has a different function assigned to its speak member. Remember to use include guards in your header file.
Cheat sheet
Different instances of the same struct type can hold different function pointers, enabling polymorphic behavior.
Define a function pointer type and a struct that uses it:
typedef void (*ActionFunc)(void);
typedef struct {
const char* name;
ActionFunc execute;
} Action;Create instances with different functions assigned:
void say_hello(void) {
printf("Hello!\n");
}
void say_goodbye(void) {
printf("Goodbye!\n");
}
int main() {
Action greet = { "Greet", say_hello };
Action farewell = { "Farewell", say_goodbye };
greet.execute(); // Output: Hello!
farewell.execute(); // Output: Goodbye!
return 0;
}Both instances share the same type but exhibit different behavior when their function pointers are called.
Try it yourself
#include <stdio.h>
#include "speaker.h"
// TODO: Implement the bark function that prints "Woof!"
// TODO: Implement the meow function that prints "Meow!"
// TODO: Implement the chirp function that prints "Chirp!"
int main() {
int type1, type2;
scanf("%d", &type1);
scanf("%d", &type2);
// TODO: Create two Speaker instances
// TODO: Wire the first speaker's speak function based on type1
// (1 = bark, 2 = meow, 3 = chirp)
// TODO: Wire the second speaker's speak function based on type2
// (1 = bark, 2 = meow, 3 = chirp)
// TODO: Call speak on each speaker in order
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