在C ++模块中传递指向成员函数的指针

时间:2016-12-22 15:55:26

标签: c++ visual-studio-2015 function-pointers member-function-pointers

给出两个类:XYX包含Y *类型的成员,并将指向其成员函数的指针传递给Y的实例。所以在C ++中它看起来像这样:

x.h

#pragma once

class Y;

class X
{
public:
    X();
private:
    Y *y;
    void myfunc(int);
};

x.cpp

#include "x.h"
#include "y.h"

X::X()
{
    this->y = new Y(*this, &X::myfunc);
}

void X::myfunc(int dummy)
{
    dummy = dummy;
}

y.h

#pragma once

//#include "x.h"    // this would fix the issue!

class X;

class Y
{
public:
    Y(X &x, void (X::*pMyCallback)(int));
    ~Y();

private:
    X &x;
    void (X::*pMyCallback)(int) = nullptr;
};

y.cpp的

#include "y.h"
#include "x.h"

Y::Y(X &x, void (X::*pMyCallback)(int))
    : x(x), pMyCallback(pMyCallback)
{
    (x.*pMyCallback)(3);
}

Y::~Y()
{
}

当我运行此代码时,Visual Studio 2015引发了异常:" MYPROGRAM.exe触发了断点"。有时它会因访问冲突异常而崩溃。

int main(int argc, char *argv[])
{
    X x;
    return 0;
}

我注意到这个问题与编译单元有某种关系,因为如果我在同一个文件中定义XY,它就不会崩溃。此外,如果我将X(即" x.h")的声明包含在" y.h"中,它也不会崩溃。

这种行为是否存在理由?

1 个答案:

答案 0 :(得分:1)

问题似乎是,在声明类之后定义指向成员的指针,但在定义之前,MSVC必须猜测类#39;继承模型。有四种方法可以解决这个问题:

  • 在" y.h"中的声明__single_inheritance中使用特定于MS的关键字__multiple_inheritance__virtual_inheritanceclass X;,强迫它使用特定的模型。其中,__single_inheritance是最有效的,但只有在类没有多个或虚拟继承时才可用;由于X没有基类,这很好。

    // y.h
    
    #pragma once
    
    //#include "x.h"    // this would fix the issue!
    
    class __single_inheritance X;
    
    class Y
    {
    public:
        Y(X &x, void (X::*pMyCallback)(int));
        ~Y();
    
    private:
        X &x;
        void (X::*pMyCallback)(int) = nullptr;
    };
    
  • 出于同样的原因,请使用特定于MS的编译指示pointers_to_members。同样,我们可以使用"单继承",这是最有效的选择。

    // y.h
    
    #pragma once
    
    #pragma pointers_to_members(full_generality, single_inheritance)
    
    //#include "x.h"    // this would fix the issue!
    
    class X;
    
    class Y
    {
    public:
        Y(X &x, void (X::*pMyCallback)(int));
        ~Y();
    
    private:
        X &x;
        void (X::*pMyCallback)(int) = nullptr;
    };
    
  • 更改IDE中的指针到成员的表示选项;不幸的是,我不确定如何做到这一点,因为我无法找到这个选项。

  • 指定命令行选项/vmg