跨 C++ 模块传递指向成员函数的指针
Passing a pointer to a member function across C++ modules
给定两个 类:X
和 Y
。 X
包含类型 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 has triggered a breakpoint"。有时它会因访问冲突异常而崩溃。
int main(int argc, char *argv[])
{
X x;
return 0;
}
我注意到这个问题在某种程度上与编译单元有关,因为如果我在同一个文件中定义 X
和 Y
它不会崩溃。此外,如果我将 X
(即 "x.h")的声明包含在 "y.h" 中,它也不会崩溃。
这种行为有理由吗?
问题似乎是在声明 class 之后定义指向成员的指针时,但在定义之前,MSVC 必须猜测 class' 继承模型。有四种处理方法:
在 "y.h" 中的声明 class X;
中使用 MS 特定关键字 __single_inheritance
、__multiple_inheritance
或 __virtual_inheritance
来强制它使用特定的模型。其中,__single_inheritance
是最有效的,但仅在 class 没有多重或虚拟继承时可用;因为 X
没有基础 classes,所以这很好。
// 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 的 pragma pointers_to_members
。同样,我们可以使用 "single inheritance",这是最有效的选择。
// 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中的Pointer-to-member representation选项;不幸的是,我不确定该怎么做,因为我找不到该选项。
- 指定命令行选项
/vmg
给定两个 类:X
和 Y
。 X
包含类型 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 has triggered a breakpoint"。有时它会因访问冲突异常而崩溃。
int main(int argc, char *argv[])
{
X x;
return 0;
}
我注意到这个问题在某种程度上与编译单元有关,因为如果我在同一个文件中定义 X
和 Y
它不会崩溃。此外,如果我将 X
(即 "x.h")的声明包含在 "y.h" 中,它也不会崩溃。
这种行为有理由吗?
问题似乎是在声明 class 之后定义指向成员的指针时,但在定义之前,MSVC 必须猜测 class' 继承模型。有四种处理方法:
在 "y.h" 中的声明
class X;
中使用 MS 特定关键字__single_inheritance
、__multiple_inheritance
或__virtual_inheritance
来强制它使用特定的模型。其中,__single_inheritance
是最有效的,但仅在 class 没有多重或虚拟继承时可用;因为X
没有基础 classes,所以这很好。// 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 的 pragma
pointers_to_members
。同样,我们可以使用 "single inheritance",这是最有效的选择。// 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中的Pointer-to-member representation选项;不幸的是,我不确定该怎么做,因为我找不到该选项。
- 指定命令行选项
/vmg