层次结构中的成员函数指针

Jes*_*der 4 c++ casting member-function-pointers

我正在使用定义接口的库:

template<class desttype>
void connect(desttype* pclass, void (desttype::*pmemfun)());
Run Code Online (Sandbox Code Playgroud)

我有一个小的层次结构

class base {
   void foo();
};

class derived: public base { ... };
Run Code Online (Sandbox Code Playgroud)

在一个成员函数中derived,我想打电话

connect(this, &derived::foo);
Run Code Online (Sandbox Code Playgroud)

但它似乎&derived::foo实际上是一个成员函数指针base; gcc吐了出来

error: no matching function for call to ‘connect(derived* const&, void (base::* const&)())’
Run Code Online (Sandbox Code Playgroud)

我可以通过明确地this转向来解决这个问题base *.但为什么编译器不能匹配调用desttype = base(因为derived *可以隐式转换为base *)?

另外,为什么 &derived::foo不是一个成员函数指针derived

AnT*_*AnT 7

首先,当你这样做&class::member时,结果的类型总是基于成员实际声明的类.这就是一元&在C++中的运作方式.

其次,代码无法编译,因为模板参数推断失败.从第一个参数得出的结果是desttype = derived,从第二个参数得出它desttype = base.这就是编译失败的原因.C++中的模板参数推导规则不考虑this可以转换为base *类型的事实.此外,人们可以争辩说,不是转换thisbase *类型,而是正确的方法是&derived::foo从指针到基础成员转换为指向派生成员类型.两种方法都同样可行(见下文).

第三,C++中的成员指针遵循反方差规则,这意味着指向基类成员的指针可以隐式转换为指向派生类成员的指针.在您的情况下,您需要做的就是通过显式指定参数来帮助编译器完成模板参数推导,并且代码应该编译

 connect<derived>(this, &derived::foo);
Run Code Online (Sandbox Code Playgroud)

上述应编译由于禁忌方差&derived::foo指针,即使它是一个指向base部件.或者你可以做

 connect<base>(this, &derived::foo);
Run Code Online (Sandbox Code Playgroud)

由于指针的协方差,这也应该编译this.

您还可以对实际参数使用显式强制转换(正如您在问题中提到的那样)来解决演绎模糊性,但在我看来,显式指定的模板参数看起来更好.