2

以下は *nix プラットフォーム全体でサポートされていますか?

    #include <cstdio>
    #include <sys/types.h>
    #include <signal.h>
    #include <unistd.h>

    class SignalProcessor
    {
     public:
      static void OnMySignal(int sig_num)
      {
          printf("Caught %d signal\n", sig_num);
          fflush(stdout);

          return;
      } 
    }; 
    using namespace std;

   int main()
   {

          signal(SIGINT,SingalProcessor::OnMySignal);
          printf("Ouch\n");

          pause();

          return 0;
   }
4

3 に答える 3

5

技術的にはできません。

コンパイラが「C」関数に使用するのと同じ呼び出し規約を使用していることは、たまたま幸運なことです。C++ ABI は定義されていないため、コンパイラの次のバージョンでは、まったく異なる呼び出し規約を自由に使用できます。これにより、コンパイラからの警告なしにコードが混乱します。

参照: http://www.parashift.com/c++-faq-lite/pointers-to-members.html#faq-33.2
このセクションの最後にある注を参照してください。

注: 静的メンバー関数は、実際のオブジェクトを呼び出す必要がないため、通常、静的メンバー関数へのポインターは、通常の関数へのポインターと型互換性があります。ただし、おそらくほとんどのコンパイラで機能しますが、「C リンケージ」は名前マングリングなどのことだけでなく、呼び出し規約もカバーするため、実際には extern "C" 非メンバー関数である必要があります。 C と C++ では異なる場合があります。

編集:
サーシャのコメントに答えるには:

例としてスレッドを使用します。

#include <iostream>
class Thread
{    public:   virtual void run()  = 0; };

extern "C" void* startThrerad(void* data)
{
    Thread*  thread = reinterpret_cast<Thread*>(data);
    try
    {
        thread->run();
    }
    catch(...)
    {    /* Log if required. Don't let thread exit with exception. */ }
    return NULL;
}
class MyJob: public Thread
{
    public: virtual void run() {std::cout << "HI\n";}
};
int main()
{
    MyJob     job; // MyJob inherits from Thread
    pthread_t th;

    // In most situation you do not need to dynamic cast.
    // But if you use multiple inheritance then things may get
    // interesting, as such best to always use it.
    pthread_create(&th,NULL,startThrerad,dynamic_cast<Thread*>(&job));

    void*     result;
    pthread_join(th,&result);
}
于 2009-06-09T22:55:57.240 に答える
-1

私は、Windows のスレッド プロシージャやその他のさまざまなコールバック、および RTX 割り込みを常に使用して同等の処理を行っています。唯一の本当の落とし穴は、メンバーが静的でなければならないこと (これは既に理解済みです) と、ルーチンが標準の C/システム コール呼び出し規則を使用するように設定されていることを確認する必要があることです。残念ながら、それを行う方法はプラットフォームに依存します。Win32 では、"__stdcall" 修飾子を使用しています。

passback-in ポインター パラメータを使用して、そのような呼び出しを通常のクラス メソッド呼び出しに「変換」できることに注意してください。そのように(「self_calling_callback」は静的メソッドです):

unsigned long __stdcall basic_thread::self_calling_callback (void *parameter) {
   if (parameter) {
      basic_thread * thread = reinterpret_cast<basic_thread *>(parameter);
      thread->action_callback();
   }
   return 0; 
   // The value returned only matters if someone starts calling GetExitCodeThread
   // to retrieve it.
}

basic_thread::basic_thread () {
   // Start thread.
   m_Handle = CreateThread(NULL,
                           0,
                           self_calling_callback,
                           (PVOID)this,
                           0,
                           &m_ThreadId );
   if( !IsHandleValid() )
      throw StartException("CreateThread() failed", GetLastError());
}
于 2009-06-09T18:34:10.247 に答える
-1

それはうまくいくはずです。実際、その関数を拡張して、キャッチされたシグナルに応じてそのクラスの特定のインスタンスを呼び出すことができます。たとえば、非静的メソッド Process をクラスに追加すると、次のようなことができます。

SignalProcessor* sp[MAX_SIGNALS];

static void SignalProcessor::OnMySignal(int sig_num)
{
      printf("Caught %d signal\n", sig_num);

      if (0 < sp[sig_num])
            sp[sig_num]->Process();

      fflush(stdout);

      return;

}
于 2009-06-09T18:40:30.763 に答える