GDExtensions will also use GDVIRTUAL etc macros; they aren’t C++ virtual methods though, so trying to override or replace a function in C++ with one written in GDScript will require extra steps.
For an example in my game players can place objects and furniture I create dictionaries for each object, I want to save some data from the C++ and I also want to extend these objects in GDScript, so I must have both C++ virtual functions and GDScript.
// Appliance.hpp
Dictionary on_save() const;
virtual Dictionary _on_save() const; // internal virutal
GDVIRTUAL0RC(Dictionary, _on_save); // GD virtual (0 args, R returns a value, C constant)
The GDVirtual _on_save can share the same name as the C++ virtual _on_save because the macro expands to a number of much larger function signatures, but you can have either one without the other, I only happen to make use of a internal virtual.
The non-virtual on_save calls my other two virtual functions. Exampling using a C++ virtual (very standard) and the GDVIRTUAL macros to check and call a GDScript virutal if overriden. GDVIRTUAL_CALL does also check GDVIRTUAL_IS_OVERIDDEN and I believe it will return false if the function is not overridden, so my use of GDVIRTUAL_IS_OVERIDDEN may be superfluous.
// Appliance.cpp
Dictionary Appliance::on_save() const {
// internal C++ virtual call
Dictionary data = _on_save();
// GD virtual macros
if (GDVIRTUAL_IS_OVERRIDDEN(_on_save)) {
Dictionary extra;
if (GDVIRTUAL_CALL(_on_save, extra)) {
data.merge(extra, true);
}
}
return data;
}
My _bind_methods only binds the main non-virutal on_save to kick things off, and the GDVIRTUAL_BIND, my internal virtual _on_save is only for C++.
// Appliance.cpp :: _bind_methods()
ClassDB::bind_method(D_METHOD("on_save"), &Appliance::on_save);
GDVIRTUAL_BIND(_on_save);
It was really hard to find this information; godot-cpp is still rapidly changing too.