Skip to content

Instantly share code, notes, and snippets.

@stungeye
Created October 8, 2025 19:18
Show Gist options
  • Select an option

  • Save stungeye/68daf18d623b0bf6a05304464e131a24 to your computer and use it in GitHub Desktop.

Select an option

Save stungeye/68daf18d623b0bf6a05304464e131a24 to your computer and use it in GitHub Desktop.
Polymorphic Objects in C++ with Virtual Abstract Classes
#include "raylib.h"
#include <memory> // Smart Pointers
#include <vector> // std::vector
#include <iostream>
// ABSTRACT BASE CLASS (Shape)
class Shape {
protected:
Vector2 position;
Color color;
public:
Shape(Vector2 position, Color color) : position{position}, color{color} {}
// We need a virtual descructor here to allow for derived class destructors:
virtual ~Shape() = default;
// We need a virtual method here to allow for polymorphic derived versions of draw.
// Marking the virtual method as "= 0" without giving it an implementation makes
// the method a "pure virtual" method. A class with more or more pure virtual
// methods is an "abstract class". Abstract classes cannot be instantiated.
virtual void draw() const = 0;
};
// DERIVED CLASS (Circle)
class Circle : public Shape {
float radius;
public:
Circle(Vector2 position, Color color, float radius) : Shape(position, color), radius{ radius } {}
~Circle() { std::cout << "Circle Destructor\n"; }
virtual void draw() const override {
DrawCircleV(position, radius, color);
}
};
// DERIVED CLASS (Square)
class Square : public Shape {
float sideLength;
public:
Square(Vector2 position, Color color, float sideLength) : Shape(position, color), sideLength{ sideLength } {}
~Square() { std::cout << "Square Destructor\n"; }
virtual void draw() const override {
DrawRectangleV(position, {sideLength, sideLength}, color);
}
};
// A highly contrived example of polymorphism via a reference:
void drawShape(Shape& s) {
s.draw(); // Will call the most derived version of draw.
}
int main() {
const int screenWidth = 800;
const int screenHeight = 450;
InitWindow(screenWidth, screenHeight, "raylib [core] example - basic window");
SetTargetFPS(60); // Set our game to run at 60 frames-per-second
std::vector<std::unique_ptr<Shape>> shapes;
shapes.emplace_back(std::make_unique<Circle>(Vector2{ screenWidth / 4, screenHeight / 2 }, BLUE, 30));
shapes.emplace_back(std::make_unique<Square>(Vector2{ screenWidth / 4, screenHeight / 2 }, GREEN, 50));
while (!WindowShouldClose()) {
BeginDrawing();
ClearBackground(RAYWHITE);
// This will properly call the derived version of draw()
// on Circle and Square objects in the shapes vector:
for (const auto& s : shapes) {
s->draw();
}
EndDrawing();
}
CloseWindow();
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment