С++, вызывающий функцию из вектора указателей функций внутри класса, где определение функции в основном

Хорошо, в моем основном я:

void somefunction();
int main()
{
    //bla bla bla
    SomeClass myclass = SomeClass();
    void(*pointerfunc)() = somefunction;
    myclass.addThingy(pointerfunc);

    //then later i do
    myclass.actionWithDiffrentOutcomes();
}

void somefunction()
{
    //some code
}

и в классе:

class SomeClass()
{
    public:
        void addThingy(void (*function)());
        void actionWithDiffrentOutcomes();
    private:
        std::vector<void (**)()> vectoroffunctions;
}
SomeClass::addThingy(void (*function)())
{
    vectoroffunctions.push_back(&function);
}
SomeClass::actionWithDiffrentOutcomes()
{
    (*vectoroffunctions[0])();;
}

Я вроде как новичок в указателях, но я читаю свои книги на С++, googled, ext. и это кажется правильным, компилируется, запускается, но когда я называю "actionWithDiffrentOutcomes()", я получаю нарушение доступа. Я не уверен, что делать. это кажется правильным, но что-то явно неправильно. Итак, как я могу вызвать функцию из класса, когда определение находится в другом?

Я делаю это так, потому что я не могу жестко закодировать каждый параметр в инструкции switch.

Ответ 1

Ваш код почти правильный. Ваш вектор ошибочно держит указатели на указатели на функции, а не просто на указатели на функции. addThingy добавляет адрес указателя function к vector, но этот указатель выходит из области видимости в следующей строке.

Измените свой код следующим образом:

//Store pointers to functions, rather than
//pointers to pointers to functions
std::vector<void (*)()> vectoroffunctions;

SomeClass::addThingy(void (*function)())
{
    //Don't take the address of the address:
    vectoroffunctions.push_back(function);
}

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

Ответ 2

Проблема здесь:

vectoroffunctions.push_back(&function);

Вы добавляете адрес переменной local. Локальная переменная будет уничтожена после возврата из функции. Адрес, который вектор сохраняет, указывает на уничтоженный объект, поэтому вы получаете ошибку "нарушение прав доступа" во время выполнения.

Чтобы исправить это, сделайте следующее:

Сначала измените это

std::vector<void (**)()> vectoroffunctions;

:

std::vector<void (*)()> _functions; //vector of function-pointer-type
                                    //I changed the name also!

который практически такой же, как:

std::vector<void()> _functions; //vector of function-type

Теперь сделайте следующее:

_functions.push_back(function); //add copy! 

Чтобы сделать его более гибким, вы можете использовать шаблон вместе с std::function как:

class A
{
    public:
        template<typename Function>
        void add(Function && fn) 
        {  
            _functions.push_back(std::forward<Function>(fn)); 
        }
        void invoke_all()
        {
           for(auto && fn : _functions)
                fn();
        }
    private:
        std::vector<std::function<void()>> _functions;
};

Теперь вы можете использовать его для хранения функций, а также функторов:

void myfunction() { std::cout << "myfunction" << std::endl ; }

struct myfunctor
{
       void operator()() { std::cout << "myfunctor" << std::endl ; }
};

A a;
a.add(myfunction);   //add function
a.add(myfunctor());  //add functor!
a.invoke_all();

Выход (Онлайн-демонстрация):

myfunction
myfunctor

Надеюсь, что это поможет.

Ответ 3

Указатели функций гораздо более разборчивы с помощью typedefs:

typedef void (*RequiredFunction)();

Затем вы можете объявить addThingy() следующим образом:

    void addThingy(RequiredFunction function);

И vectoroffunctions вот так:

    std::vector<RequiredFunction> vectoroffunctions;

Определение addThingy будет:

void SomeClass::addThingy(RequiredFunction function)
{
    vectoroffunctions.push_back(function);
}

И ваш main() будет больше похож:

int main()
{
    SomeClass sc;
    RequiredFunction pointerfunc = somefunction;
    sc.addThingy(pointerfunc);
    sc.actionWithDiffrentOutcomes();
}

Намного меньше * и &, чтобы совершать ошибки!