Тип аргумента обратного вызова не совпадает в унаследованном классе - PullRequest
0 голосов
/ 14 декабря 2011

Я пытаюсь реализовать менеджер событий на основе связанного кода в верхнем ответе здесь: Игровые объекты говорят друг с другом

Однако, когда я получаю сообщение об ошибке,попробуйте зарегистрировать обратные вызовы.Я уверен, что это связано с typedef, и я признаю, что я не уверен, как он работает точно, но он находится в точно такой же форме в связанном коде.Класс B должен наследоваться от интерфейса, так почему тип отличается?Я сжал код в наименьшем примере ниже.

#include <iostream>

class Interface;
typedef void (Interface::*Callback)(void *data);

class Interface
{
    public:
        void Register    (Callback func);

};

void Interface::Register(Callback func)
{
    std::cout << "Register" << std::endl;
}


class B : public Interface
{
    public:
        B();
        void Echo(void *data);
};

B::B()
{
    Register( (Callback)Echo );
}

void B::Echo(void *data)
{
    std::cout << "Echo" << std::endl;
}


int main()
{
    B b;
    return 0;
}

Вот ошибка, которую я получаю под g ++ 4.6.1:

test.cpp: In constructor ‘B::B()’:
test.cpp:31:22: error: argument of type ‘void (B::)(void*)’ does not match ‘Callback {aka void (Interface::*)(void*)}’

Может кто-нибудь объяснить, что я делаюнеправильно?Спасибо

Ответы [ 2 ]

1 голос
/ 14 декабря 2011

Как правильно указал @ Kerrek , Echo не является членом Interface, поэтому B::Echo не квалифицируется как Interface::*Callback.Но вы можете использовать шаблон для этого, например:

template <class T> class Interface {
public:
    typedef void (T::*Callback)(void *data);
    void Register(Callback func) {
        std::cout << "Register" << std::endl;
    }
    // ...
};

class B : public Interface<B> {
public:
    B() {
        Register(&B::Echo);
    }
    void Echo(void *data) {
        // Do something
    }
};
0 голосов
/ 14 декабря 2011

Думаю, вам лучше использовать std :: function (c ++ 11) или boost :: function (c ++ 03 + boost)

#include <iostream>

class Interface;
typedef void (Interface::*Callback)(void *data);

class Interface
{
    public:
        std::function<void(void*)> register;

            Interface(std::function<void(void*)> register_)
            :    register(register_)   //intializer list
            {}
            virtual ~Interface(){} //put me in
};

void Interface::Register(Callback func)
{
    std::cout << "Register" << std::endl;
}


class B : public Interface
{
    public:
        B();
        void Echo(void *data);
};

B::B()
:   Interface( std::bind(B::Echo, this) )
{}

void B::Echo(void *data)
{
    std::cout << "Echo" << std::endl;
}

Хотя почему вы не используетечистые виртуалы вне меня

class Interface
{
    public:
        virtual void Echo(void*)=0;

};

void B::Echo(void *data) //implements Echo
{
    std::cout << "Echo" << std::endl;
}

интерфейс вызова-> эхо вызовет ребенка

, если вам нужна производительность, тогда используйте

http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern

И будьте очень осторожны с void * они обычно считаются плохими.

РЕДАКТИРОВАТЬ АДРЕСОВУЮ ТОЧКУ В КОММЕНТАРИЯХ: не чистые виртуалы

class Interface
{
public:
    virtual ~Interface(){} //put me in
    virtual void echo(void*){}  //if implementation is not extended it will do nothing.
    //others 
};

Это не Java, интерфейсы не вещьопределяется языком.Таким образом, вы можете иметь интерфейс, который вы можете выбрать, который может выбрать, какую часть реализовать, если обратный вызов не касается вашего класса, тогда просто не реализуйте его.

void * плохо для всего хостапричин.из C ++ FAQ

избегать пустот * (держите их внутри низкоуровневых функций и структур данных, если они вам действительно нужны, и предоставляйте пользователям безопасные интерфейсы типов, обычно шаблоны) *

http://www2.research.att.com/~bs/bs_faq.html

поиск по "void *"

, но в основном void * обходить все типы безопасности, добавленные C ++.Это взлом в C, чтобы восполнить тот факт, что у него нет полиморфизма или общего кода.

...