指向成员函数的错误

时间:2016-06-25 21:56:06

标签: c++ visual-c++

我正在尝试在我的代码中使用指向成员函数的指针,以便我可以轻松地替换要使用的函数,而无需更改代码中的任何位置。编译时我得到一个错误,我不明白如何解决。以下是最低工作示例:

OrderBook.h

#include <list>
#include <string>

class Order
{

};

class OrderBook
{
    typedef void(OrderBook::* MatchingAlgorithm)(Order&, std::list<Order>&);
public:
    OrderBook(const std::string name);    
    void ExecuteFunction(Order&, std::list<Order>);
private:
    void FunctionToUse(Order&, std::list<Order>&);        
    const std::string m_OrderBookName;
    MatchingAlgorithm m_matchingAlgorithm;
};

OrderBook.cpp

#include "OrderBook.h"

OrderBook::OrderBook(
    const std::string name
    )
    : m_OrderBookName(name)
{
    m_matchingAlgorithm = &OrderBook::FunctionToUse;
}

void OrderBook::ExecuteFunction(Order & order, std::list<Order> listOfOrders)
{
    (*m_matchingAlgorithm)(order, listOfOrders);
}

void OrderBook::FunctionToUse(Order &, std::list<Order>&)
{
    // do nothing
}

Source.cpp

#include "OrderBook.h"

int main() 
{
    std::list<Order> mylist;
    Order o1, o2;    
    mylist.push_back(o1);
    mylist.push_back(o2);

    OrderBook ob("my book");

    ob.ExecuteFunction(o1, mylist);

    return 0;
}

编译错误

error C2171: '*': illegal on operands of type 'OrderBook::MatchingAlgorithm'
error C2064: term does not evaluate to a function taking 2 arguments

如果我将(*m_matchingAlgorithm)替换为FunctionToUse ExecuteFunction,则代码编译时没有错误。

2 个答案:

答案 0 :(得分:2)

将函数调用更改为:

(this->*m_matchingAlgorithm)(order, listOfOrders);

答案 1 :(得分:2)

简短回答

您可以使用指向成员运算符(.*->*)的指针调用您的函数:

void OrderBook::ExecuteFunction(Order & order, std::list<Order> listOfOrders)
{
    (this->*m_matchingAlgorithm)(order, listOfOrders);
}

更多信息here

长解释

我们都习惯于省略this->来访问当前对象的成员。允许这种情况的机制是名称解析原则。但这些不适用于指针解除引用运算符。

指向数据成员的指针的简单情况

让我们用更简单的情况加注星形:指向整数成员的指针。

class OrederBook {
    ...
    int x,y; 
    int OrderBook::* px; 
};

在构造函数中,您无法使用px初始化&x,因为&x是整数的绝对地址,px是一个(相对)地址OrderBook中的整数。然后我们会初始化它:

OrderBook::OrderBook(..)
    : m_OrderBookName(name), px(&OrderBook::x) {...}

但在这种情况下,px的普通解除引用运算符也不起作用:

 *px =2;    // error because of unary operator *

实际上,对于解除引用这样的指针,您不仅需要知道指针,还需要知道应该使用此指针的对象:

 this->*px =2;    // yes ! take relative px address and apply it to this object.  

一元与二元反对

该标准定义了两个不同的解除引用运算符:

  

5.3.1 / 1: 一元 *运算符执行间接:表达式   应用应该是指向对象类型的指针,或指向a的指针   函数类型,结果是引用对象或的左值   表达式指向的函数。如果是表达式的类型   是“指向T的指针”,结果的类型是“T”。

     

5.5 / 3: 二进制运算符 - &gt; *将其第二个操作数绑定到第一个操作数,该操作数应为“指向T成员的指针”,哪一个   应为“指向T的指针”或“指向T所属的类的指针”   一个明确的,可访问的基类。“表达式E1-&gt; E2是   转换为等效形式((E1))。* E2。

取消引用指向成员函数的指针

对于上面的数据示例,您可以选择武器。您可以非常轻松地构建实现相同结果的代码,但将px定义为int *px而不是int OrderBook::*px并像往常一样使用一元*

不幸的是,对于非静态成员函数的poitners,你不能使用这样的快捷方式。你真的需要一个指向成员函数的指针而不是指向函数的指针:当你调用一个成员函数时,除了你必须传递的参数之外,你总是要知道你调用它的对象。告诉他们的唯一方法是使用(->*)(.*)

<强>结论

忽略this->*并假设编译器足够聪明,可以推断它对于当前对象来说对我们来说似乎很自然。但这并不是标准所定义的。这是不幸的,更多here