Interfacing with basic C++ class

Ogi ogion.art at gmail.com
Fri Sep 30 22:56:06 UTC 2022


On Thursday, 29 September 2022 at 12:49:06 UTC, Riccardo M wrote:
> On Thursday, 29 September 2022 at 11:13:15 UTC, Ogi wrote:
> So it turns out that D's structs are a much better match for 
> C++'s classes in this case. But why is this? Can you elaborate? 
> It must have to do with the fact that D structs are passed by 
> value?
>

In C++, class and struct are basically the same thing (AFAIK the 
only difference is that struct members are public by default). In 
D, they are two very different things: classes are reference 
types — structs are value types, classes support inheritance — 
structs only support `alias this`, and so on.

When interfacing to C++, disregard the keyword and look at the 
implementation instead. If all its member functions are 
non-virtual, map it to struct. Otherwise map it to class. If it 
defines at least one pure virtual member function, map it to 
abstract class. If all its member functions are either pure 
virtual or non-virtual and it contains no fields, map it to 
interface. Sounds complicated? Well, that’s because C++ is 
complicated.

> However the 'add' function only links correctly if C++ has the 
> function body defined outside of its class.
> ```
> // C++
> int MyClass::add(int asd) {
>     return field + asd;
> }
> ```
> If the function is defined inside its class, it is an undefined 
> reference at link time. Once again I ask for clarifications and 
> workarounds, if possible.

In C++, member functions defined inside its class are called 
*inline* member functions. In contrast to normal functions which 
must be defined once and only once in your program, inline 
functions must be defined in every translation unit that uses 
them. Let’s replicate your linking error in C++:

```C++
//c.h
class C {
public:
     int foo() {
         return 42;
     }
     void bar();
};
```

```C++
//c.cpp
#include "c.h"

void C::bar() { /* ... */ }
```

```C++
//main.cpp
#include <stdio.h>

//Let’s see what happens if we forget `C::foo` definition:
class C {
public:
     int foo();
     void bar();
};

int main() {
     auto c = new C();
     printf("%d\n", c->foo());
     c->bar();
     return 0;
}
```

```
$ clang++ -c c.cpp
$ clang++ -c main.cpp
$ clang++ main.o c.o
main.o : error LNK2019: unresolved external symbol "public: int 
__cdecl C::foo(void)" (?foo at C@@QEAAHXZ) referenced in function 
main
a.exe : fatal error LNK1120: 1 unresolved externals
clang++: error: linker command failed with exit code 1120 (use -v 
to see invocation)
```

Copying `C::foo` definition to `main.cpp` will fix this. Of 
course, we could just include `c.h`.

Same goes for D. `MyClass.add` must be defined in your D module.


More information about the Digitalmars-d-learn mailing list