如何将不同的成员函数指针赋值给不同的注册实例类?
How to assign different member function pointers to different instances of registering classes?
编辑:我在这个话题上仅限于 C++03。
在下面的代码中,class Impl
派生自 Intf
并包含 class Caller
.
的实例
Caller
的ctor接受一个Intf::
实例和成员函数指针;它在 Caller::func()
.
中对前者调用后者
Impl
的构造函数将自身及其成员函数 func()
注册到其包含的 Caller
实例。
我希望 Impl
包含多个 Caller
实例并为每个实例注册不同的成员函数指针,以便调用每个包含的 Caller
实例的 ::func()
结果正在调用一个不同的 Impl
成员函数 - 这可以做到吗?
我能想到的唯一方法是在 Intf
中定义多个纯虚函数,在 Impl
中实现它们并注册那些覆盖函数。但这对我来说不是一个理想的解决方案:我想知道是否有一种方法可以在注册 class 的不同实例中注册不同的成员函数指针,而无需在接口 class 1:1 在实现中具有覆盖功能 class.
我需要排除 Caller
采用 Impl
引用和成员函数的可能性; Caller
只能知道 Intf
s 而不能知道 Impl
s。
// 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;
}
另一个问题:有人可以解释为什么在 Impl
的 ctor 中,有必要用 Intf::
限定指向成员函数 func()
的指针吗? IE。为什么这是正确的...
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
您可以使用旧的回调方式:
typedef void (*callback_t)(void*);
辅助函数:
template <typename C, void (C::*M)()>
void member_func(void* instance)
{
C* c = static_cast<C*>(instance); // Not typesafe :-/
((*c).*M)();
}
然后
class Caller
{
public:
Caller(Intf& f, callback_t func) : instance(f), func_(func) {}
void func() const { func_(&instance); }
private:
Intf& instance;
callback_t func_;
};
class Impl : public Intf
{
public:
Impl()
: c_ ( *this, &member_func<Intf, &Intf::func> )
, c2_ ( *this, &member_func<Impl, &Impl::func2> )
{
}
// ...
};
自 C++11 起,您可以将 Caller
替换为 std::function<void(void)>
并通过 c2_([=](){ this->func2();})
对其进行初始化。并称之为 c2_();
编辑:我在这个话题上仅限于 C++03。
在下面的代码中,class Impl
派生自 Intf
并包含 class Caller
.
Caller
的ctor接受一个Intf::
实例和成员函数指针;它在 Caller::func()
.
Impl
的构造函数将自身及其成员函数 func()
注册到其包含的 Caller
实例。
我希望 Impl
包含多个 Caller
实例并为每个实例注册不同的成员函数指针,以便调用每个包含的 Caller
实例的 ::func()
结果正在调用一个不同的 Impl
成员函数 - 这可以做到吗?
我能想到的唯一方法是在 Intf
中定义多个纯虚函数,在 Impl
中实现它们并注册那些覆盖函数。但这对我来说不是一个理想的解决方案:我想知道是否有一种方法可以在注册 class 的不同实例中注册不同的成员函数指针,而无需在接口 class 1:1 在实现中具有覆盖功能 class.
我需要排除 Caller
采用 Impl
引用和成员函数的可能性; Caller
只能知道 Intf
s 而不能知道 Impl
s。
// 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;
}
另一个问题:有人可以解释为什么在 Impl
的 ctor 中,有必要用 Intf::
限定指向成员函数 func()
的指针吗? IE。为什么这是正确的...
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
您可以使用旧的回调方式:
typedef void (*callback_t)(void*);
辅助函数:
template <typename C, void (C::*M)()>
void member_func(void* instance)
{
C* c = static_cast<C*>(instance); // Not typesafe :-/
((*c).*M)();
}
然后
class Caller
{
public:
Caller(Intf& f, callback_t func) : instance(f), func_(func) {}
void func() const { func_(&instance); }
private:
Intf& instance;
callback_t func_;
};
class Impl : public Intf
{
public:
Impl()
: c_ ( *this, &member_func<Intf, &Intf::func> )
, c2_ ( *this, &member_func<Impl, &Impl::func2> )
{
}
// ...
};
自 C++11 起,您可以将 Caller
替换为 std::function<void(void)>
并通过 c2_([=](){ this->func2();})
对其进行初始化。并称之为 c2_();