指向类方法调用的指针

Pointer to a class method call

本文关键字:指针 调用 类方法      更新时间:2023-10-16

我正在尝试定义一个名为RationalNumber的类。在构造函数中,我想使用另一个函数(名为simplification(的回调函数来简化RationalNumber表示的分数,但我收到一些错误,我无法弄清楚我错过了什么。

第一个错误是cannot convert from 'void (__cdecl *)(RationalNumber &)' to 'RationalNumber::pointer_to_f' Prob2 ...sourcereposProb2Prob2NumarRational.h 21

#pragma once
#include <iostream>
using namespace std;
class RationalNumber {
typedef void (RationalNumber::*pointer_to_f)(RationalNumber&);
private:
int a;
int b;
void callback(pointer_to_f);
static int gcd(int, int);
public:
RationalNumber(int = 0, int = 0);
static void simplification(RationalNumber&);
};
RationalNumber::RationalNumber(int x, int y) {
this->a = x;
this->b = y;
pointer_to_f p = &simplification;    // <-- line 21, location of the first error
callback((p)(this));
}
int RationalNumber::gcd(int a, int b)
{
if (b == 0)
return a;
return gcd(b, a % b);
}
void RationalNumber::simplification(RationalNumber& x) {
int d = gcd(x.a, x.b);
if (d != 1) {
x.a /= d;
x.b /= d;
}
}
void RationalNumber::callback(pointer_to_f *p(RationalNumber& x) ) {
(*p)(x);
}

完整的错误日志:

Error   C2440   'initializing': cannot convert from 'void (__cdecl *)(RationalNumber &)' to 'RationalNumber::pointer_to_f'  Prob2   ...sourcereposProb2Prob2NumarRational.h    21
Error   C2511   'void RationalNumber::callback(RationalNumber::pointer_to_f *(__cdecl *)(RationalNumber &))': overloaded member function not found in 'RationalNumber'  Prob2   ...sourcereposProb2Prob2NumarRational.h    39
Error   C2065   'x': undeclared identifier  Prob2   ...sourcereposProb2Prob2NumarRational.h    40  
Error (active)  E0144   a value of type "void (*)(RationalNumber &x)" cannot be used to initialize an entity of type "RationalNumber::pointer_to_f" Prob2   ...sourcereposProb2Prob2NumarRational.h    21  
Error (active)  E0147   declaration is incompatible with "void RationalNumber::callback(RationalNumber::pointer_to_f)" (declared at line 11 of "...sourcereposProb2Prob2NumarRational.h")  Prob2   ...sourcereposProb2Prob2NumarRational.h    39  
Error (active)  E0109   expression preceding parentheses of apparent call must have (pointer-to-) function type Prob2   ...sourcereposProb2Prob2NumarRational.h    22
Error (active)  E0020   identifier "x" is undefined Prob2   ...sourcereposProb2Prob2NumarRational.h    40  
Error   C2064   term does not evaluate to a function taking 1 arguments Prob2   ....sourcereposProb2Prob2NumarRational.h    22  

谢谢!

cannot convert from 'void (__cdecl *)(RationalNumber &)' to 'RationalNumber::pointer_to_f'

在线

pointer_to_f p = &simplification;

让我们看看我们这里有什么。这条线初始化一个类型为RationalNumber::pointer_to_f的变量(p(,它对应于尝试的转换。=的右侧是RationalNumber::simplification的地址,这是一个从RationalNumber&void的静态成员函数。检查,是否与错误消息匹配。

因此,第一个错误归结为指向成员函数的指针必须指向非静态成员函数。静态成员函数的地址是一个普通的函数指针(主要是因为它缺少隐藏的this参数(。

鉴于您的设置,从simplification中删除static关键字以及删除其参数似乎是有意义的。让它在*this上运行,一旦成员函数不再static,它就会可用。

或者,如果出于某种原因需要static,您可以将指向成员函数的指针更改为指向函数的常规指针simplification。(鉴于该函数在任何一种情况下都需要一个RationalNumber对象,我不明白为什么static是可取的。


其余的错误在技术上是独立的,但我会抛出一些与无效使用指向成员函数的指针有关的错误。

callback((p)(this));

这将调用p指向的函数,并将指针this作为参数提供。返回值 (void( 成为callback的参数。如果要将p作为参数传递给callback,则传递p

callback(p);

void RationalNumber::callback(pointer_to_f *p(RationalNumber& x) )

这与声明不符。您将callback声明为参数为pointer_to_f的函数。这个定义有一个参数,其类型是一个接受RationalNumber&参数并返回pointer_to_f的函数(x在这里毫无意义(。保持一致!

void RationalNumber::callback(pointer_to_f p)

如果要传入某些内容以在调用p时用作参数,则需要第二个参数。另请参阅指向成员函数的函数指针,了解如何修复用于调用p的语法。


最后说明:在这里使用回调看起来像是严重的过度工程,但我想它的需求可能存在于删除的细节中,以使示例代码简单。

下面修改的代码编译并展示了如何使用静态方法作为"回调",但如上所述,不清楚为什么你不想直接从构造函数中使用simplification方法(而不是使用此方法的指针(

#include <functional>
class RationalNumber {
private:
int a;
int b;

static int gcd(int, int);
public:
RationalNumber(int = 0, int = 0);
static void simplification(RationalNumber&);

};
RationalNumber::RationalNumber(int x, int y) {
this->a = x;
this->b = y;
std::function<void(RationalNumber&)> p= &RationalNumber::simplification;
p(*this) ;
}
int RationalNumber::gcd(int a, int b)
{
if (b == 0)
return a;
return gcd(b, a % b);
}
void RationalNumber::simplification(RationalNumber& x) {
int d = gcd(x.a, x.b);
if (d != 1) {
x.a /= d;
x.b /= d;
}
}

函数指针必须是静态的(不能是对象方法(。 因此,在上面的示例中,您可以将gcdsimplification声明为标准函数(而不是对象方法(。