Использование класса C ++ в D - PullRequest
10 голосов
/ 30 ноября 2010

Я пытаюсь найти способ использовать классы C ++ в D.

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

D не может вызывать специальные функции-члены C ++, и наоборот.К ним относятся конструкторы, деструкторы, операторы преобразования, перегрузка операторов и распределители.

Итак, я пытаюсь свести эти функции C ++ к вызовам функций в стиле C.Вот подтверждение, с которым я работаю.

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();
}

И вот как я это выполнил.

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++

И я получаю ошибку сегментации, как только вызывается метод.

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 ()

Ответы [ 3 ]

7 голосов
/ 30 ноября 2010

Ваша версия C ++ возвращается по значению.

Ваша версия D ожидает, что она вернется по ссылке.

По сути, ваша версия C ++ помещает копию someClass в стек.D думает, что C ++ поместит указатель на стек.Он пытается интерпретировать копию someClass как указатель, и происходят плохие вещи.

Проблема в том, что в D классы и интерфейсы всегда возвращаются по ссылке.C ++ возвращает все по значению, если только вы не указываете, что это либо ссылка, либо указатель.

Таким образом, вам нужно это:

someClass * hearMeOut() { return new someClass; }

Не забудьте удалить его позже.

3 голосов
/ 30 ноября 2010

Вы не выставили интерфейс C.У вас все еще есть функция, возвращающая класс C ++, а не что-то распознаваемое C. Вместо этого вы можете указать свой класс как void * s.Например:

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);
    }
}

Это сделает ваш класс пригодным для использования как D, так и C (и любым другим языком, связанным с C).

0 голосов
/ 01 декабря 2010

D может вызывать только виртуальные методы C ++ с помощью трюка интерфейса.

Кроме того, вы говорите, что D hearMeOut () использовал соглашение о вызовах C ++, а C ++ имеет C, вызывающий conv.Поправьте меня, если я ошибаюсь, но это также должно привести к проблемам.

Imo-интерфейс с C ++ таким образом практически ограничен вызовом простых функций, поскольку в большинстве библиотек C ++ всегда есть не виртуальные методы, операторы и все,еще в классах, не говоря уже о пространствах имен, с которыми D также не справляется.

D SFML делает это так, как описал Билли.Работать с оберткой C и оберткой D довольно утомительно.Следует использовать некоторый (полу) автоматический подход, такой как SWIG, тогда вы также получите хороший межъязыковой полиморфизм.

...