/** * @file CppWidgetApi.h * @brief A C++ (not extern "C") surface living alongside * PluginApi.h's plain C one, in the SAME plugin build. Every member * function below keeps its real, compiler-mangled name; nothing here * needs special handling by source/HotReload, which classifies * symbols by their type and section, never by what their name looks * like -- see the "Requirements on a hot-reloadable module" section of * hot_reload.h and the "Hot reloading C++ symbols" section of * source/HotReload/README.md for the full picture. * * The two methods below are reached two different ways from * Host/Main.cpp, deliberately: see that file's comments for why. */ #pragma once /** * @brief A small C++ class whose members are defined in the plugin, not the host. * * Each member below keeps its real, compiler-mangled name and is reached a different way from * Host/Main.cpp -- through the vtable, through a manually resolved mangled name, and (for the * operator) not at all -- to show that all of them patch like any plain C function. */ class CppWidget { public: /** * @brief Virtual, so that destroying a widget through a base pointer works across the * boundary. */ virtual ~CppWidget() = default; /** * @brief Scales its input, through a virtual call. * * Virtual: Host/Main.cpp calls this through ordinary C++ * polymorphic dispatch (widget->virtualTick(x)) and needs no * manual symbol lookup at all -- the call compiles down to an * indirect call through the object's vtable slot, not a direct * reference to this specific symbol, so it needs no link-time * dependency on whichever plugin build actually defines it. * * @param input The value to scale. * @return V1: `input * 2`. V2: `input * 3`. */ virtual int virtualTick(int input); /** * @brief Scales its input, through an ordinary out-of-line method. * * Calling this as widget->tick(x) * would compile to a direct call to CppWidget::tick's own mangled * symbol, which would need the Host to link against a plugin * build at build time -- exactly what hot-reloading a plugin * means avoiding. So Host/Main.cpp instead resolves it manually * by its mangled name via hot_reload_get_symbol(), the same way * it resolves PluginApi.h's plain C functions. * * @param input The value to scale. * @return V1: `input * 2`. V2: `input * 3`. */ int tick(int input); /** * @brief An overloaded operator. * * Mechanically just a function with an * unusual mangled name, reached the same manual way as tick() * above. * * @param other Ignored; the operator only prints which build it is. * @return A new, empty widget. */ CppWidget operator+(const CppWidget& other) const; }; /** * @brief Creates a widget. * * The one entry point Host/Main.cpp looks up by a plain, human-typed * name -- extern "C" here for exactly the reason hot_reload.h * recommends it: something to hand a human-readable name to, without * needing to know or hardcode a mangled string. * * @return A new widget. The caller owns it and must `delete` it (safe across the plugin * boundary here because host and plugin share one C++ runtime and allocator). */ extern "C" CppWidget* make_cpp_widget();