Search code examples
c++classsegmentation-faultd

Using C++ class in D


I am trying to find a way to use C++ classes in D.

http://www.digitalmars.com/d/2.0/cpp_interface.html

D cannot call C++ special member functions, and vice versa. These include constructors, destructors, conversion operators, operator overloading, and allocators.

So, I am attempting to dumb down these C++ functions to C style function calls. Here is the proof I am working with.

helper.h

class someClass {
    public:
        someClass();
        char *whatSayYou();
};

extern "C"
{
    someClass *hearMeOut();
}

helper.cpp

#include "helper.h"

someClass::someClass()
{

}

char *someClass::whatSayYou()
{
    return "Everything is gravy";
}


someClass *hearMeOut()
{
    return new someClass;
}

main.d

import std.stdio;

int main(string[] args)
{
    someClass *awesomeExample = hearMeOut();
    char *shoutoutToTheWorld = awesomeExample.whatSayYou();
    writefln(std.string.toString(shoutoutToTheWorld));
    return 0;
}


extern (C++)
{
    interface someClass
    {
        char *whatSayYou();
    }

    someClass *hearMeOut();
}

And here is how I complied it.

g++-4.3 -c -I code/dg3d_helper -I /usr/local/include/ -o code/dg3d_helper/helper.o code/dg3d_helper/helper.cpp
code/dg3d_helper/helper.cpp: In member function ‘char* someClass::whatSayYou()’:
code/dg3d_helper/helper.cpp:19: warning: deprecated conversion from string constant to ‘char*’
gdc-4.3 -g -c -I code/ -o code/main.o code/main.d
gdc-4.3 -g -I code/ -o main code/dg3d_helper/helper.o code/main.o -lstdc++

And I get a segmentation fault as soon as the method is called.

Program received signal SIGSEGV, Segmentation fault.
0x0000000000402fa0 in _Dmain (args=...) at code/main.d:7
7       char *shoutoutToTheWorld = awesomeExample.whatSayYou();
(gdb) bt
#0  0x0000000000402fa0 in _Dmain (args=...) at code/main.d:7
#1  0x000000000041b1aa in _D9dgccmain211_d_run_mainUiPPaPUAAaZiZi2goMFZv ()
#2  0x000000000041b235 in _d_run_main ()
#3  0x00002aaaab8cfc4d in __libc_start_main () from /lib/libc.so.6
#4  0x0000000000402d59 in _start ()

Solution

  • You've not exposed a C interface. You still have your function returning a C++ class rather than something recognizable by C. Expose your class as void *s instead. For example:

    class MyClass
    {
    //private members
    public:
    //public members
        int MyMethod(int argument) const;
        virtual float MyVirtualMethod();
        virtual ~MyClass() {}
    };
    
    class MySecondClass : public MyClass
    {
    public:
        virtual float MyVirtualMethod();
        int MyMethod2(int argument) const;
    };
    
    extern "C" {
        void * CreateMyClass()
        {
            return static_cast<void *>(new(std::nothrow) MyClass);
        }
    
        void * CreateMySecondClass()
        {
            //Note the cast to the base class first (This is needed
            //because it might actually change the position of the pointer,
            //which would not be automatically adjusted later)
            return static_cast<void *>(static_cast<MyClass *>(new(std::nothrow) MySecondClass));
        }
    
        int CallMyClassMethod(void * thisMember, int argument)
        {
            return static_cast<MyClass *>(thisMember)->MyMethod(argument);
        }
    
        float CallMyVirtualMethod(void * thisMember)
        {
            return static_cast<MyClass *>(thisMember)->MyVirtualMethod();
        }
    
        int CallMyMethod2(void thisMember, int argument)
        {
            MyClass * convertedToMyClass = static_cast<MyClass *>(thisMember);
            MySecondClass * asSecondClass = dynamic_cast<MySecondClass *>(convertedToMyClass);
            if (!asSecondClass)
            {
                //Return error (thisMember not an instance of MySecondClass)
            }
            else
            {
                return asSecondClass->MyMethod2(argument);
            }
        }
    
        void DestroyMyClass(void * classMember)
        {
            delete static_cast<MyClass *>(classMember);
        }
    }
    

    This will make your class usable by D, but also by C (and every other language that binds to C) as well.