Передача функции-члена класса параметру вне класса
Как передать функцию-член класса в качестве параметра другой функции-члену другого класса?
class theSecondClass
{
public:
void theFunctionReceiver(void (theFirstClass::*Function)(void));
{
// This part is wrong. "Operand of * must be a pointer"
(*Function)();
}
}
class theFirstClass
{
public:
theSecondClass * SecondClassInstance;
void theFunctiontoPass(void)
{
printf("It worked \n");
return;
}
void theFunctiontoCall(void)
{
SecondClassInstance->theFunctionReceiver(theFunctiontoPass);
}
};
Примите предположение, что theSecondClass
а также theFirstClass
оба уже сделаны. Я зову theFirstClass->theFunctiontoCall()
откуда-то
Я не понимаю Когда я передаю это, разве это не передается как указатель?
Я посмотрел на несколько похожих тем вокруг, но я не понимаю их полностью. Я использую VS 2013, базовый компилятор.
1 ответ
Когда вы пишете это заявление:
SecondClassInstance->theFunctionReceiver(theFunctiontoPass);
Вероятно, вы имели в виду:
SecondClassInstance->theFunctionReceiver(&theFunctiontoPass);
Что должно дать вам предупреждение компилятора о том, что это неквалифицированная ссылка на член, что указывает на то, что вы на самом деле пишете:
SecondClassInstance->theFunctionReceiver(&theFirstClass::theFunctiontoPass);
Вы получаете указатель на функцию-член в определении класса. "Это" не подразумевается и не входит в пакет. Единственный способ вызвать его без экземпляра класса - это если он статический. (В этом случае он не будет проверять тип как функцию-член... это будет просто указатель на обычную функцию.)
Если я собираюсь передать ссылку на мой класс, зачем мне вообще передавать эту функцию? Не могу ли я просто вызвать его, в случае ссылки, ButtonObj->Buttonfunc();
Единственная причина, по которой вы будете использовать указатели на функции-члены, состоит в том, чтобы получить некоторую абстракцию, где один фрагмент кода может вызывать функцию-член, которой не нужно явно называть имя. Если ты в порядке с theSecondClass::theFunctionReceiver
зная имя theFirstClass::theFunctionToPass
и личность theFirstClass
... тогда обязательно просто передайте ссылку на экземпляр theFirstClass и явно вызовите метод.
Вы можете захотеть ситуацию, когда theSecondClass
собирается вызвать любую из нескольких функций-членов на theFirstClass
с соответствующими сигнатурами... он просто не хочет жестко кодировать какую. В этом случае можно передать пару ссылок на класс и функцию-член. Вы, кажется, подозреваете, что это не слишком часто бывает полезным, и вы были бы правы. Каждый год мне приходится возвращаться и искать синтаксис для вызова указателей на члены в классе, потому что он почти никогда не появляется, за исключением вопросов Stackru:
Как позвонить через указатель на функцию-член?
Скорее всего, что вы хотите (и что на самом деле хотят люди, задающие эти вопросы), так это разделить проблемы так, чтобы theSecondClass
имеет крюк для выполнения чего-либо, но не должен знать о theFirstClass
совсем. Посмотрите на lambdas, std:: function и std::bind, чтобы найти обобщенные решения, с которыми вы, возможно, сможете поэкспериментировать.
Вот пример, чтобы показать вам, как это выглядит для удобной абстрактной упаковки вызова в std::function. Это делает функциональный объект на месте, который захватывает окружающую this
указатель, чтобы при вызове вызывать метод объекта:
#include <iostream>
#include <functional>
class theSecondClass {
public:
void theFunctionReceiver(std::function<void()> const & Function) {
Function();
}
};
class theFirstClass {
private:
theSecondClass * SecondClassInstance;
public:
void theFunctiontoPass() {
std::cout << "It worked\n";
}
void theFirstClass::theFunctiontoCall() {
SecondClassInstance->theFunctionReceiver(
[this]() {theFunctiontoPass();}
);
}
};
int main() {
theFirstClass tfc;
tfc.theFunctiontoCall();
}
Обратите внимание, что это C++11, который я предлагаю использовать, если вы еще этого не сделали. Однако в C++98 существуют менее удобные обозначения и механизмы.
Это исправляет проблемы с вашим кодом, которые выходят за рамки упомянутой вами проблемы. Пожалуйста, просмотрите написание минимального, полного, проверяемого примера. Должна быть возможность вставить предоставленный код в компилятор и увидеть только ту ошибку, которую вы хотите обсудить.
- Это добавляет точки с запятой после окончания определений классов
- Это удаляет точку с запятой после объявления метода, когда вы предоставляете тела в классе
- Вы нуждались в различных предварительных определениях, чтобы заставить его работать так, как оно было у вас, это не требует их
- Когда функция не принимает параметров, ее обычно определяют как
void foo()
неvoid foo(void)
,return;
последняя строка функции, не возвращающей значения, также является излишней. - Избегайте написания нового кода на C++ с использованием printf, изучайте iostreams
- Переменные члены смещены на частную или защищенную.
- В образцах кода Stackru старайтесь, чтобы они были короткими и не нуждались в полосах прокрутки; лучше не давать открывающим скобкам собственную линию (большую часть времени)
Хотя именование субъективно, я бы посоветовал дать начальные заглавные буквы именам ваших классов, лучше, чем начальные заглавные буквы для переменных.