Вызовите указатель на функцию вне структуры - PullRequest
0 голосов
/ 14 октября 2018

У меня есть структура, внутри нее указатель на функцию из той же структуры.И теперь мне нужно вызвать указатель на функцию вне структуры.Я приведу пример кода ниже:

#include <iostream>

struct test {
    void (test::*tp)(); // I need to call this pointer-to-function
    void t() {
        std::cout << "test\n";
    }
    void init() {
        tp = &test::t;
    }
    void print() {
        (this->*tp)();
    }
};
void (test::*tp)();

int main() {
    test t;
    t.init();
    t.print();
    (t.*tp)(); // segfault, I need to call it
    return 0;
}

Ответы [ 2 ]

0 голосов
/ 14 октября 2018

@ songyuanyao ответ действителен.Тем не менее, вы уверены, что хотите использовать свою структуру таким образом?Почему бы просто не использовать наследование и виртуальные методы?:

class base_test {
public:
    virtual void t() { std::cout << "test\n"; }
    void print() { t(); }
};

и затем вы можете создать его подкласс:

class my_test : base_test {
public:
    virtual void t() { std::cout << "my test\n"; }
};

В вашей функции main() (или где угодно) у вас могут быть функции, возвращающие указатели или ссылки на базовый класс, которыена самом деле экземпляры подклассов.И таким образом, вам не нужно беспокоиться об указателях.

Недостатком является то, что вы должны знать о различных тестах во время компиляции (а затем даже в месте использования, как я только что объяснил).Если вы это сделаете, я бы пошел с общей идиомой.

0 голосов
/ 14 октября 2018

(t.*tp)(); пытается вызвать указатель на функцию-член tp, который определен в глобальном пространстве имен как void (test::*tp)();, обратите внимание, что он фактически инициализируется как нулевой указатель (через инициализация нуля 1 ), вызов его приводит к UB , все возможно.

Если вы хотите вызвать элемент данных tp из t (т.е. t.tp)на объекте t вы должны изменить его на

(t.*(t.tp))();
     ^
     |
     ---- object on which the member function pointed by tp is called

Если вы хотите вызвать глобальный tp, вы должны инициализировать его соответствующим образом, например,

void (test::*tp)() = &test::t;

затем вы можете

(t.*tp)(); // invoke global tp on the object t

1 Об инициализации нуля

Инициализация нуля выполняется в следующих ситуациях:

1) Для каждой именованной переменной со статическим или локальным потоком хранилищем that is not subject to constant initialization (since C++14) перед любой другой инициализацией.

...