代码之家  ›  专栏  ›  技术社区  ›  Pablo Herrero

可以在C++类中使用信号吗?

  •  37
  • Pablo Herrero  · 技术社区  · 17 年前

    我正在做这样的事情:

    #include <signal.h>
    
    class myClass {
    public: 
        void myFunction () 
        {
            signal(SIGIO,myHandler);
        }
    
        void myHandler (int signum)
        {
            /**
            * Handling code
            */
        }
    
    }
    

    我正在使用gcc开发Ubuntu。

    但它不会编译。它抱怨:

    错误:类型为的参数 void (MyClass::)(int) 不同意 void (*) (int)

    有什么线索吗?或者,也许只是我不能在课堂上使用信号?信号只允许用C吗?

    错误消息是近似翻译,因为我的编译器不是英文的。

    6 回复  |  直到 7 年前
        1
  •  44
  •   Luc Touraille    17 年前

    信号的第二个参数应该是一个指针,指向一个接受int并返回void的函数。你传递给信号的是一个指向 成员 函数接受int并返回void(其类型为 void (myClass::*)(int) ).我可以看到克服这个问题的三种可能性:

    1-你的方法 myHandler 可以是静态的:这很棒,让它保持静态

    class myClass 
    {
      public:
        void myFunction () 
        {
            signal(SIGIO, myClass::myHandler);
        }
    
        static void myHandler (int signum)
        {
            // handling code
        }
    };
    

    2-你的方法不应该是静态的:如果你打算只使用一个实例的signal,你可以创建一个私有静态对象,并编写一个静态方法,简单地调用这个对象上的方法。有些东西沿着线

    class myClass 
    {
      public:
        void myFunction () 
        {
            signal(SIGIO, myClass::static_myHandler);
        }
    
        void myHandler (int signum)
        {
            // handling code
        }
    
        static void static_myHandler(int signum)
        {
            instance.myHandler(signum);
        }
    
      private:
        static myClass instance;
    };
    

    3-但是,如果你打算在多个实例中使用信号,事情会变得更加复杂。也许一个解决方案是将每个要操作的实例存储在一个静态向量中,并在每个实例上调用该方法:

    class myClass
    {
      public:
        void myFunction () // registers a handler
        {
            instances.push_back(this);
        }
    
        void myHandler (int signum)
        {
            // handling code
        }
    
        static void callHandlers (int signum) // calls the handlers
        {
            std::for_each(instances.begin(), 
                          instances.end(), 
                          std::bind2nd(std::mem_fun(&myClass::myHandler), signum));
        }
      private:
        static std::vector<myClass *> instances;
    };
    

    在某个地方,打一个电话

    signal(SIGIO, myClass::callHandlers);
    

    但我认为,如果你最终使用最后一种解决方案,你可能应该考虑改变你的处理设计:-)!

        2
  •  10
  •   Jørn Jensen    17 年前

    要传递指向方法的指针,它必须是静态方法,并且必须指定类名。

    试试这个:

    class myClass {
      void myFunction () 
      {
        signal(SIGIO, myClass::myHandler);
      }
    
      static void myHandler (int signum)
      {
         // blabla
      }
    };
    

    你也应该阅读Baget提供的链接 paragraph 33.2 in the C++ FAQ .

        3
  •  3
  •   SamB som-snytt    14 年前

    实际上,C++信号处理程序不允许使用任何在C和C++中都不存在的工具(除了在C++11中它们可能使用原子),并且需要使用C链接。报价 C++11 draft n3242 第18.10节“其他运行时支持”[support.runtime](第8段),

    C和C++语言的公共子集由所有声明组成, 在格式良好的C++程序中可能出现的代码、定义和表达式 并且也在符合C标准的程序中。POF(普通旧函数)是 仅使用此公共子集中的特征的函数,而不使用 直接或间接使用任何不是POF的函数,除了 可以使用第29条中定义的非成员函数。所有 信号处理器应具有C联动。可以用作信号的POF 当满足以下条件时,符合C程序的处理程序不会产生未定义的行为 在C++程序中用作信号处理程序。任何其他函数的行为 在C++程序中用作信号处理程序是实现定义的。

    (第29条是关于原子论的。)

        4
  •  3
  •   gekomad    10 年前
    #include <signal.h>
    
    class myClass {
    
     private:
      static myClass* me;
    
     public:
      myClass(){ me=this; }
    
      void myFunction (){
        signal(SIGIO,myClass::myHandler);
      }
    
      void my_method(){ }
    
      static void myHandler (int signum){
        me->my_method();
     }
    }
    
        5
  •  1
  •   Michael Firth    8 年前

    你发布的新答案的声誉比评论现有答案的声誉低,这确实看起来很疯狂,但我们做到了。

    gekomad在2015年9月24日的回答是我用来解决问题的答案。值得指出的是,只有当只有一个实例时,这才会完全有效 myClass 创建。否则,静态对象指针将指向其中一个可能不是所需的实例(最近创建的)。

    而且,如果它对其他人有用,在几个答案中链接的常见问题解答的有效2018 URL是:

    http://www.cs.technion.ac.il/users/yechiel/c++-faq/memfnptr-vs-fnptr.html

        6
  •  0
  •   Abolfazl Abbasi    5 年前

    您可以使用单例模式

        static MyClass &getInstance() {
        static MyClass instance;
        return instance;