Using custom classes (types) as arguments in another class member function (or a constructor)

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By curious_orange
:warning: Old Version Published before Godot 3 was released.

Hi, I’m new to C++ module development. Following the documentation and some examples, I tried a simple test module where there are two classes. Here a “class 2” member function (mul) is to have “class 1” type arguments. Declared in header file as below:

class class_1 : public Reference {

OBJ_TYPE(class_1, Reference);
...

and then

class class_2 : public Reference {
        
            OBJ_TYPE(class_2, Reference);
        
            public:
                class_2();
                virtual ~class_2();
        
                float mul(class_1, class_1);
...

But I get “no known conversion for argument 1 from ‘class_1’…” errors during compilation, at variant.h. The below is the initial part of error message, as it is repeated for all variant types.

core/method_bind.inc:1296:87:   required from 'Variant::Type MethodBind2R<R, P1,
 P2>::_gen_argument_type(int) const [with R = class_1; P1 = class_1; P2 = class_
1]'
modules\SimpleTest\mtest.cpp:52:1:   required from here
core/variant.h:177:19: error: no matching function for call to 'Variant::Variant
(class_1&)'
   Variant v(t.type);
                   ^
In file included from core/object.h:33:0,
                 from core/reference.h:32,
                 from modules\SimpleTest\mtest.h:4,
                 from modules\SimpleTest\mtest.cpp:1:
core/variant.h:439:17: note: candidate: Variant::Variant()
  _FORCE_INLINE_ Variant() { type=NIL; }
                 ^
core/variant.h:439:17: note:   candidate expects 0 arguments, 1 provided
core/variant.h:438:2: note: candidate: Variant::Variant(const Variant&)
  Variant(const Variant& p_variant);
  ^
core/variant.h:438:2: note:   no known conversion for argument 1 from 'class_1'
to 'const Variant&'
In file included from core/object.h:33:0,
                 from core/reference.h:32,
                 from modules\SimpleTest\mtest.h:4,
                 from modules\SimpleTest\mtest.cpp:1:
core/variant.h:325:2: note: candidate: Variant::Variant(const IP_Address&)
  Variant(const IP_Address& p_address);
  ^
core/variant.h:325:2: note:   no known conversion for argument 1 from 'class_1'
to 'const IP_Address&'

As I understand, function arguments are only compared against existing variant types. How can one have custom types in a module, be recognized as valid arguments? Is this a binding or a compilation order issue? I tried various arrangements of source files (common/separate headers etc.) assuming the latter, with same outcome. Help would be appreciated.

Note: Using minGW for compilation (compiles Godot fine without this test module).

:bust_in_silhouette: Reply From: Zylann

I think the error occurs because you wrote your function as expecting two class_1 by value (so the function will receive copies). Doing that mostly works with built-in variant types, while everything else (inheriting Object or Reference) must be passed by reference.

Assuming class_1 also inherits Reference, you should change your method prototype to be:

float mul(Ref<class_1>, Ref<class_2>)

Also, a good practice is to name the arguments, so you (and others) can tell what they are:

float mul(Ref<class_1> first, Ref<class_2> second)

If class_1 actually inherits Object, you can write it this way instead (but you loose automatic reference counting and will need to free the object manually):

float mul(class_1 &first, class_1 &second)

Finally, if what you wanted is really to send the parameters by value (like vectors, rect, matrix, color and other primitives), then Variant has to be changed, but I never did that, I have no idea if there is a more “modular” way.

Thanks for your help, finally compiled it!

Had a few more questions meanwhile. The thing is, I have some useful utility code in C++, trying to adapt them as Godot modules. I try to understand essentials with simple test codes, to gain some time. Hence, any info on below could also greatly help:

I don’t fully grasp Ref<> functionality (got rusty in C++ after a long break too). In above case, does Ref<> copy the object, or act like a GDscript wrapper of C++ referencing method, like func(type &arg)?

In the utility code, I use several overloaded constructors with arguments. Can one bind a class with constructor arguments to GDscript? The new() method doesn’t have arguments, hence not sure how. For instance, I tested overloading class_2 constructor, adding one with argument:

class_2(Ref<class_1>)
{
...
};

When compiled as above, there are no errors. But a GDscript declaration like var c2 = class_2(c1) doesn’t work of course. The script expects a function. Any example of such a module implementation perhaps, couldn’t find one so far.

Thanks again.

curious_orange | 2016-12-07 15:31