The plugin systems I know of all use dynamic libraries. Basically, you need to define a small, effective handshake between the system kernel and the plugins. Since there is no C++ ABI, plugins must either only use a C API or use the very same compiler (and probably compiler version) as the system's kernel.
The simplest thinkable protocol would be a function, that all plugin developers would have to provide, which returns an instance of a class derived from your base class, returned as a base class pointer. (The extern "C"
makes sure that function won't have a mangled name, and is thus easier to find by its name.) Something like:
extern "C" {
plugin_base* get_plugin();
}
The kernel would then try to load binaries found in designated places as dynamic libraries and attempt to find the get_plugin()
function. If it succeeds, it calls this function and ends up with a loaded plugin instance.
Of course, it would be nice to also have functions to check the version of the API the plugin was compiled against vs. the version of the kernel. (You might change that base class, after all.) And you might have other functions, which return information about the plugin (or you have this as virtuals in the base class). That depends a lot on the nature of your system.