Я работал над проектом, в котором мне нужно было работать с указателями функций, а точнее с указателем функции на функции-члены. Я прочитал почти все связанные вопросы, однако ни один из них не описывает мою конкретную проблему. Итак, попробую описать свою проблему на простом примере.
Предположим, что у меня есть три разных файла заголовков с разными классами, как показано ниже:
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
для построения. Таким образом, это создает тупик.
Это причина проблемы? Если да, то как я могу это решить?
Поскольку и 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} {}
};