РЕДАКТИРОВАТЬ: я ограничен С++ 03 по этой теме.
В следующем коде класс Impl
является производным от Intf
и содержит экземпляр класса Caller
.
ctor Caller
принимает экземпляр Intf::
и указатель на функцию-член; он вызывает последний на первом в Caller::func()
.
ctor Impl
регистрирует себя и свою функцию-член func()
с содержащимся в ней экземпляром Caller
.
Я хотел бы, чтобы Impl
содержал несколько экземпляров Caller
и регистрировал разные указатели функций-членов для каждого экземпляра, чтобы вызов каждого содержащегося Caller
экземпляра ::func()
приводил к вызову другой функции-члена Impl
- можно ли это сделать?
Единственный способ, которым я мог это сделать, — это определить несколько чистых виртуальных функций в Intf
, реализовать их в Impl
и зарегистрировать эти переопределяющие функции. Но это не идеальное решение для меня: я хотел бы знать, есть ли способ зарегистрировать разные указатели функций-членов с разными экземплярами класса регистрации без создания виртуальных функций в классе интерфейса 1: 1 с переопределением функций в реализующем классе .
Мне нужно исключить возможность Caller
использования ссылки и функции-члена Impl
; Caller
может знать только о Intf
с, а не о Impl
с.
// main.cpp
#include <iostream>
class Intf
{
public:
virtual void func() = 0;
typedef void (Intf::*funcPtr)();
};
class Caller
{
public:
Caller( Intf& f, Intf::funcPtr func ) : f_( f ), func_( func ) {}
void func() { f_.func(); }
private:
Intf& f_;
Intf::funcPtr func_;
};
class Impl : public Intf
{
public:
Impl()
: c_ ( *this, &Intf::func )
// , c2_( *this, static_cast<Intf::funcPtr>(func2) )
{
}
void callCaller() { c_.func(); };
// void callCaller2() { c2_.func(); };
private:
void func()
{
std::cout << __FUNCTION__ << std::endl;
}
void func2()
{
std::cout << __FUNCTION__ << std::endl;
}
Caller c_;
// Caller c2_;
};
int main( int argc, char* argv[] )
{
Impl i;
i.callCaller();
return 0;
}
Дополнительный вопрос: может ли кто-нибудь объяснить, почему в ctor Impl
необходимо уточнять указатель на функцию-член func()
с помощью Intf::
? т.е. почему это правильно...
Impl() : c_ ( *this, &Intf::func ) {}
...и почему они неверны...
Impl() : c_ ( *this, &Impl::func ) {}
Impl() : c_ ( *this, &func ) {}
?
Ошибка компилятора в случае версии '&Impl::func':
g++ -g main.cpp && ./a.out
main.cpp: In constructor 'Impl::Impl()':
main.cpp:31:31: error: no matching function for call to 'Caller::Caller(Impl&, void (Impl::*)())'
: c_ ( *this, &Impl::func )
^
main.cpp:31:31: note: candidates are:
main.cpp:16:3: note: Caller::Caller(Intf&, Intf::funcPtr)
Caller( Intf& f, Intf::funcPtr func ) : f_( f ), func_( func ) {}
^
main.cpp:16:3: note: no known conversion for argument 2 from 'void (Impl::*)()' to 'Intf::funcPtr {aka void (Intf::*)()}'
main.cpp:12:7: note: Caller::Caller(const Caller&)
class Caller
^
main.cpp:12:7: note: candidate expects 1 argument, 2 provided
Ошибка компилятора в случае версии '&func':
>g++ -g main.cpp && ./a.out
main.cpp: In constructor 'Impl::Impl()':
main.cpp:31:20: error: ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function. Say '&Impl::func' [-fpermissive]
: c_ ( *this, &func )
^
main.cpp:31:25: error: no matching function for call to 'Caller::Caller(Impl&, void (Impl::*)())'
: c_ ( *this, &func )
^
main.cpp:31:25: note: candidates are:
main.cpp:16:3: note: Caller::Caller(Intf&, Intf::funcPtr)
Caller( Intf& f, Intf::funcPtr func ) : f_( f ), func_( func ) {}
^
main.cpp:16:3: note: no known conversion for argument 2 from 'void (Impl::*)()' to 'Intf::funcPtr {aka void (Intf::*)()}'
main.cpp:12:7: note: Caller::Caller(const Caller&)
class Caller
^
main.cpp:12:7: note: candidate expects 1 argument, 2 provided
std::function
. . - person Some programmer dude   schedule 23.05.2018void (Intf::*)()
иvoid (Impl::*)()
- это 2 разных типа. Не всеIntf
будутImpl
, поэтому обычно вы не можете вызывать более поздний экземпляр сIntf
. - person Jarod42   schedule 23.05.2018