C ++: указатель на функцию-член - PullRequest
0 голосов
/ 21 мая 2019

В следующей программе, Как мне ввести строку ввода для foo?

#include <iostream>
namespace NA {
    class A {
    public:
        int (*foo)(int);
    };
}

namespace NB {
    class B : public NA::A {
    public:
        int bar(int i) {
            std::cout << i << std::endl;
            return i*2;
        }
        B() {

            this->foo = bar;  // how to type cast this fn pointer?
        }
    };
}


int main() {
    NA::A *a = new NB::B(); 
    std::cout << a->foo(2) << std::endl;
}

Я попытался выполнить приведение типа следующим образом, но что-то идет не так, когда я запускаю программу:

B() {
    typedef int (*TypeFoo)(int);
    this->foo = reinterpret_cast<TypeFoo> (&bar);
}

Вот результат, когда я запускаю:

$ ./a.out 
31947824
63895648

Я ожидал 2 и 4. Как можно типизировать указатели на функции-члены выше?

Обновление : После просмотраОтветы, указывающие, что вышеупомянутая проблема не решена, я обновляю этот вопрос, добавив в него конкретную проблему, которую я пытался решить.

Пожалуйста, см. https://boringssl.googlesource.com/boringssl/+/HEAD/include/openssl/ssl.h#1173 - Я пытаюсь иметь разные экземплярыstruct ssl_private_key_method_st работает с различными закрытыми ключами.Я пытался получить другую структуру, наследуемую от ssl_private_key_method_st , и чтобы методы sign / decrypt / complete работали с переменными экземпляра унаследованной структуры.

Мне известно об использовании SSL_ [sg] et_ex_data для косвенной передачи данных в эти функции, но я искал более простой / прямой способ передачи данных экземпляра в эти функции, если это возможно.

Ответы [ 5 ]

2 голосов
/ 21 мая 2019

Краткий ответ: нет.

Нестатические указатели на функции-члены странные.Вызов одного включает секретный параметр this, и они могут быть или не быть virtual.Это делает невозможным их смешивание с обычными указателями функций.

Вам следует рассмотреть возможность использования std::function<int(int)> вместо int (*)(int).Это позволит вам сохранить что-то вроде следующей лямбды:

B(){
    std::function<int(int)> myfn = [this](int x){
        return bar(x);
    };
}

Эта лямбда захватывает текущий объект по ссылке, и эта ссылка хранится внутри самого объекта std::function.Но вы также можете назначить любую другую функцию для std::function, напрямую или через лямбда-выражение или выражение связывания.

С другой стороны, если ваш метод bar на самом деле не зависитНапример, просто сделайте это static.Это позволит ему смешиваться с обычными указателями на функции, так как ему больше не нужен секрет this и он не может быть virtual.

static int bar(int i) {
    std::cout << i << std::endl;
    return i*2;
}

Написано так, &B::bar можно назначить обычномуint (*)(int) указатель на функцию.

2 голосов
/ 21 мая 2019

Вы столкнулись с неопределенным поведением.

TypeFoo и bar - это различные типы указателей функций (int (*)(int) и int (NB::B::*)(int) соответственно). В то время как можно привести одно к другому, использование результата для вызова функции приведет к неопределенному поведению.

8.2.10 Переинтерпретация приведения [expr.reinterpret.cast]
...
6 . Указатель на функцию может быть явно преобразован в указатель на функцию другого типа. [Примечание: Эффект вызова функции через указатель на тип функции (11.3.5), который отличается от типа, используемого в определении функции, не определен. - конец примечания] За исключением что преобразование значения типа «указатель на T1» в тип «указатель на T2» (где T1 и T2 являются типами функций) и обратно в его исходный тип дает исходное значение указателя, результат такого указателя конверсия не указана. [Примечание: см. Также 7.11 для более детали преобразования указателя. —Конечная записка]

1 голос
/ 21 мая 2019

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

Поэтому вы должны решить, что вам нужно: обычная функция (в этом случае сделать bar статической) или метод, в данном случаеВы должны напечатать определение следующим образом:

typedef int (B::*TypeFoo)(int);

reinterpret_cast является склонной к ошибкам практикой.Если вы не можете разыграть без него - высока вероятность, что ваш код неверен.

0 голосов
/ 21 мая 2019

Вызов указателя на функцию-член - это настоящая боль.Я предлагаю вам пойти по этому пути следующим образом, упрощая большую часть обработки контекста:

#include <iostream>
namespace NA {
    class A {
    public:
        int (A::*foo)(int);
    };
}

namespace NB {
    class B : public NA::A {
    public:
        int bar(int i) {
            std::cout << i << std::endl;
            return i*2;
        }
        int callFoo(int x) {
            return (this->*foo)(x);
        }
        B() {
            this->foo = (int(A::*)(int)) (&B::bar);
        }
    };
}


int main() {
    NA::A *a = new NB::B(); 
    std::cout << ((NB::B*)a)->callFoo(2) << std::endl;
}
0 голосов
/ 21 мая 2019

Функция указателя на член не работает, как обычный указатель. Он содержит «относительный адрес» того, где функция находится в макете класса. Так что объявляйте функцию со статическим. Нравится:

static int bar(int i) 
{
// code here
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...