Как получить указатель функции на функцию-член

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

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

foo1.h

struct Foo1{
    int a1;
    double b1;
    
    void (Foo2::*fp)(const double);
}

foo2.h

#include "foo1.h"

class Foo2{
public:
    void print_foo2(const double p){
        cout << "From Foo2: " << p << endl;
    }
    
    Foo1 foo1;
}

foo3.h

class Foo3 : public Foo2{
    Foo1 foo1;
    
    foo1.fp = &Foo2::print_foo2; // cannot do that
}

Итак, одна из переменных-членов структуры Foo1 является указателем на функцию-член Foo2, а именно print_foo2. По этой причине я создаю экземпляр объекта foo1 и присваиваю ему указатель на print_foo2. Класс Foo3 наследуется от класса Foo2.

Я отметил, что, как я и думал, может быть это полезная информация для решения проблемы. Однако я не могу получить этот указатель на функцию, так как Foo2 не распознается внутри структуры Foo1. Даже включение foo2.h в foo1.h не помогает. Если я не ошибаюсь, это потому, что Foo1 требует Foo2 для своей переменной-члена во время построения, но точно так же Foo2 требует Foo1 для построения. Таким образом, это создает тупик.

Это причина проблемы? Если да, то как я могу это решить?

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
67
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Поскольку и Foo2, и Foo3 нуждаются в определении Foo1, они оба должны #include "foo1.h". Без определения Foo1 компилятор не сможет вычислить размер ни Foo2, ни Foo3.

Foo1, с другой стороны, не нуждается в определении Foo2 и, следовательно, может предварительно объявить Foo2 для разрешения взаимоблокировки. Указатель (fp), который он хранит, будет иметь одинаковый размер независимо от того, как определен Foo2, поэтому достаточно предварительного объявления.

Встроенные комментарии:

// foo1.h
#pragma once

class Foo2;       // forward declaration

struct Foo1{
    int a1;
    double b1;
    
    void (Foo2::*fp)(const double);
};
// foo3.h
#pragma once

#include "foo2.h"
#include "foo1.h" // not strictly needed since `foo2.h` includes it

class Foo3 : public Foo2{

    // proper initalization:

    Foo1 foo1{1, 3.141, &Foo2::print_foo2};
};

Примечание. В вашем коде и Foo2, и Foo3 имеют переменную-член Foo1. Это означает, что у Foo3 всего 2. Если у вас только один Foo1 в Foo3 и вместо этого вы хотите, чтобы Foo3 инициализировал Foo1 в унаследованном Foo2, вы можете удалить элемент Foo1 из Foo3 и инициализировать базовый класс (Foo2) следующим образом:

class Foo3 : public Foo2{
public:
    Foo3() : Foo2{1, 3.141, &Foo2::print_foo2} {}
};

Другие вопросы по теме