Можно ли использовать сигнал внутри класса C ++? - PullRequest
31 голосов
/ 05 декабря 2008

Я делаю что-то вроде этого:

#include <signal.h>

class myClass {
public: 
    void myFunction () 
    {
        signal(SIGIO,myHandler);
    }

    void myHandler (int signum)
    {
        /**
        * Handling code
        */
    }

}

Я работаю над Ubuntu, используя gcc.

Но это не скомпилируется. Жалуется с:

ошибка: аргумент с типом void (MyClass::)(int) не соответствует void (*) (int)

Есть какие-нибудь подсказки? Или, может быть, я просто не могу использовать сигнал внутри классов? Разрешены ли сигналы только в C?

Сообщение об ошибке является приблизительным переводом, поскольку мой компилятор не на английском языке.

Ответы [ 6 ]

37 голосов
/ 05 декабря 2008

Второй параметр сигнала должен быть указателем на функцию, принимающую int и возвращающую void. То, что вы передаете сигналу, это указатель на функцию member , принимающую int и возвращающую void (его тип void (myClass::*)(int)). Я вижу три варианта решения этой проблемы:

1 - Ваш метод myHandler может быть статичным: это здорово, сделайте его статичным

class myClass 
{
  public:
    void myFunction () 
    {
        signal(SIGIO, myClass::myHandler);
    }

    static void myHandler (int signum)
    {
        // handling code
    }
};

2 - Ваш метод не должен быть статическим: если вы планируете использовать сигнал только с одним экземпляром, вы можете создать частный статический объект и написать статический метод, который просто вызывает метод для этого объекта. Что-то вроде

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

Но я думаю, что если вы в конечном итоге воспользуетесь последним решением, вам, вероятно, следует подумать об изменении схемы обработки: -)!

9 голосов
/ 05 декабря 2008

Чтобы передать указатель на метод, это должен быть статический метод, и вы должны указать имя класса.

Попробуйте это:

class myClass {
  void myFunction () 
  {
    signal(SIGIO, myClass::myHandler);
  }

  static void myHandler (int signum)
  {
     // blabla
  }
};

И вы также должны прочитать ссылку, предоставленную Baget, пункт 33.2 в C ++ FAQ .

1 голос
/ 24 сентября 2015
#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();
 }
}
1 голос
/ 31 января 2012

На самом деле обработчикам сигналов C ++ не разрешается использовать какие-либо средства, отсутствующие как в C, так и в C ++ (за исключением того, что в C ++ 11 они могут использовать атомарные элементы), и они обязаны использовать связь C. Цитировать C ++ 11 черновик n3242 раздел 18.10 «Другая поддержка времени выполнения» [support.runtime] (параграф 8),

Общее подмножество языков C и C ++ состоит из всех объявлений, определения и выражения, которые могут появиться в правильно сформированной программе C ++ а также в соответствующей C-программе. POF («простая старая функция») - это функция, которая использует только функции из этого общего подмножества, и это не прямо или косвенно использовать любую функцию, которая не является POF, за исключением того, что она может использовать функции, определенные в разделе 29, которые не являются функциями-членами. Все обработчики сигналов должны иметь связь C. ФОМ, который можно использовать в качестве сигнала Обработчик в соответствующей C-программе не дает неопределенного поведения, когда используется в качестве обработчика сигнала в программе на C ++. Поведение любой другой функции используется в качестве обработчика сигнала в программе на C ++ и определяется реализацией.

(пункт 29 посвящен атомному оружию).

1 голос
/ 05 декабря 2008

Прочитайте следующий раздел (33.2):

C ++ FAQ - указатели на участников

0 голосов
/ 04 апреля 2018

Кажется сумасшедшим, что вы можете публиковать новые ответы с меньшей репутацией, чем нужно, чтобы комментировать существующие, но мы идем.

Ответ от gekomad от 24 сентября 2015 года был тем, который я использовал для решения своей проблемы. Стоит отметить, что это будет работать совершенно очевидно, только когда будет создан только один экземпляр myClass. в противном случае указатель статического объекта будет указывать на один из экземпляров (самый последний созданный), который не может быть желательным.

И, в случае, если это кому-то пригодится, действительный URL-адрес 2018 для вопроса часто задаваемых вопросов, связанный в нескольких ответах:

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...