9

C++ クラスがあり、いくつかの C ファイルでコンパイルしています。

C++ で定義されている関数を、実際には C++ クラスで呼び出したいのですが、どうすればよいですか?

私が言っていることを示す次の宣言: 構文エラーがある可能性があります:

serial_comm.cpp

class MyClass {
    void sendCommandToSerialDevice(int Command, int Parameters, int DeviceId) {
         //some codes that write to serial port.
    }
}

外部.c

int main(int argc, char ** argv) {
    //what am I going to write here?
}
4

5 に答える 5

20

この問題に対する一般的なアプローチは、CラッパーAPIを提供することです。MyClassオブジェクトへのポインターを受け取るC関数(MyClass有効なCではないため、いくつかのモニカを提供する必要があります。最も単純なものは動き回っvoid*ています)と残りの引数を記述します。次に、C++内で関数呼び出しを実行します。

extern "C" void* MyClass_create() {
   return new MyClass;
}
extern "C" void MyClass_release(void* myclass) {
   delete static_cast<MyClass*>(myclass);
}
extern "C" void MyClass_sendCommandToSerialDevice(void* myclass, int cmd, int params, int id) {
   static_cast<MyClass*>(myclass)->sendCommandToSerialDevice(cmd,params,id);
}

次に、CコードはC apiを使用してオブジェクトを作成し、関数を呼び出してオブジェクトを解放します。

// C
void* myclass = MyClass_create();
MyClass_sendCommandToSerialDevice(myclass,1,2,3);
MyClass_release(myclass);
于 2013-02-11T15:39:35.490 に答える
10

関数を呼び出すオブジェクトのアドレスとともに、追加の引数を渡す必要があります。何かのようなもの:

extern "C" void SendCommandToSerialDevice( void* object,
    int command, int parameters, int deviceId )
{
    static_cast<MyClass*>( object)->sendCommandToSerialDevice(
        command, parameters, deviceId );
}

mainもちろん、何らかの方法でクラスのインスタンスを見つける必要があります。

編集:

他の回答で提起されたいくつかの点について:

  1. あなたの例では、mainC としてコンパイルします。これは未定義の動作であり、実際にはコンストラクターが静的オブジェクトで呼び出されないことを意味する可能性があります。(コードが DLL 内にある場合は問題ありません。標準では DLL について何も述べていませんが、実際には動作します。)

  2. 例外によってエラーを報告している場合は、署名を変更して別の方法で報告し、コードをラップしてすべての例外をキャッチし、それらを C 規則に変換する必要があります。(関数には戻り値がないため、これは戻りコードによって簡単に処理されます。)

于 2013-02-11T15:38:52.720 に答える
2

正確にやりたいなら

serial_comm_wrapper.h

#ifdef __cpluscplus
class MyClass;
extern "C" {
#else
struct MyClass;
typedef struct MyClass MyClass;
#endif

MyClass *MyClass_new();

void MyClass_sendCommandToSerialDevice(MyClass *instance, int Command, int Parameters, int DeviceId);

#ifdef __cpluscplus
}
#endif

serial_comm_wrapper.cc

#include "serial_comm_wrapper.h"
#include "serial_comm.hh"

MyClass *MyClass_new()
{
    return new MyClass();
}

void MyClass_sendCommandToSerialDevice(MyClass *instance, int Command, int Parameters, int DeviceId)
{
    instance->sendCommandToSerialDevice(command, Parameters, DeviceID);
}

外部.c

#include "serial_comm_wrapper.h"

int main(int argc, char ** argv) {
     MyClass *instance = MyClass_new();
     MyClass_sendCommandToSerialDevice(instance, ...);
}
于 2013-02-11T15:37:20.733 に答える
1

CからC++コードを呼び出すだけではいけません。

Cから呼び出すことができるC++インターフェイスを作成する必要があります。

このようなもの

 // interface.h

 #ifdef __cplusplus
 extern "C" {
 #endif

 void createMyclass();

 void callMyclassSendCommandToSerialDevice(int Command, int Parameters, int DeviceId);

 void destroyMyclass();

 #ifdef __cplusplus
 extern }
 #endif

次に、これを行います。

 static MyClass *myclass;

 void createMyclass()
 {
    try
    {
        myclass = new MyClass;
    }
    catch(...)
    {
       fprintf(stderr, "Uhoh, caught an exception, exiting...\n");
       exit(1);
    }
 }


 void callMyclassSendCommandToSerialDevice(int Command, int Parameters, int DeviceId)
 {
     // May need try/catch here. 
     myclass->sendCommandToSerialDevice(Command, Parameters, DeviceId);
 }

 void destroyMyclass()
 {
    delete myclass;
 }

明確な未定義の動作であるため、壁からCコードへの「例外」を許可しないことが重要であることに注意してください。

于 2013-02-11T15:40:30.367 に答える