How to create virtual methods available in GDScript?

Godot Version

4.7.dev3

godot-cpp API version

4.5

Question

In the Godot source code, virtual methods for overriding in scripts are created using the macros GDVIRTUAL0, GDVIRTUAL1, and so on. I searched for a long time for a way to do the same in GDExtension, but I couldn’t find anything. Simply creating a virtual method and binding it doesn’t work, and BIND_VIRTUAL_METHOD doesn’t seem to be designed for the client side at all. Am I missing something? There’s no documentation for GDExtension anyway (those two and a half articles don’t even count).

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.

3 Likes

Which header defines GDVIRTUAL macros?

#include <godot_cpp/core/gdvirtual.gen.inc>

might be the wrong one but that’s what I’m using

3 Likes

Thanks! This was useful information, although not for me… I’m very familiar with the source code, so I know how to create virtual functions for ClassDB and use them in scripts (the source code and GDExtension are very similar in use). The problem was that I didn’t have the files with the necessary macros (godot_cpp/core/gdvirtual.gen.inc). I tried various configuration options and even dumped the extension API, but the required file was still missing. I don’t know what exactly I did (basically nothing), but now the file appears. Maybe it’s because of the CMake cache. In any case, the problem is solved. Thanks again for your answer, it’s really very helpful considering how poorly documented C++ is in the Godot documentation.

1 Like

I haven’t seen this header file mentioned anywhere except by an LLM. This can only mean that the place it was actually mentioned was some long buried discord chat :smile:

Now it’s at least mentioned here.

3 Likes