看起来std::cout
无法打印成员函数的地址,例如:
#include <iostream>
using std::cout;
using std::endl;
class TestClass
{
void MyFunc(void);
public:
void PrintMyFuncAddress(void);
};
void TestClass::MyFunc(void)
{
return;
}
void TestClass::PrintMyFuncAddress(void)
{
printf("%p\n", &TestClass::MyFunc);
cout << &TestClass::MyFunc << endl;
}
int main(void)
{
TestClass a;
a.PrintMyFuncAddress();
return EXIT_SUCCESS;
}
结果是这样的:
003111DB
1
如何使用MyFunc
打印std::cout
的地址?
答案 0 :(得分:16)
我不相信这种语言提供了任何设施。 operator <<
的重载有流打印出正常的void*
指针,但成员函数指针不能转换为void*
s。这是特定于实现的,但通常成员函数指针实现为一对值 - 指示成员函数是否为虚拟的标志,以及一些额外数据。如果该函数是非虚函数,则该额外信息通常是实际成员函数的地址。如果函数是虚函数,那么额外的信息可能包含有关如何索引到虚函数表以查找给定接收器对象的函数的数据。
一般来说,我认为这意味着在不调用未定义行为的情况下打印成员函数的地址是不可能的。你可能不得不使用一些特定于编译器的技巧来实现这种效果。
希望这有帮助!
答案 1 :(得分:13)
我想补充其他答案,你打印'1'而不是地址的原因是,由于某种原因,编译器将你的函数指针强制转换为布尔值,这样你真的打电话给ostream& operator<< (bool val);
这似乎与作为成员函数的函数无关。
您可以使用clang ++ -cc1 -ast-dump:
来发现此类信息(ImplicitCastExpr 0x3861dc0 <col:13, col:25> '_Bool' <MemberPointerToBoolean>
(UnaryOperator 0x3861940 <col:13, col:25> 'void (class TestClass::*)(void)' prefix '&'
(DeclRefExpr 0x38618d0 <col:14, col:25> 'void (void)' CXXMethod 0x3861500 'MyFunc' 'void (void)')))))
答案 2 :(得分:5)
这样做的一种方法是(我不确定它是否可移植):
void TestClass::PrintMyFuncAddress(void)
{
void (TestClass::* ptrtofn)() = &TestClass::MyFunc;
cout << (void*&)ptrtofn<< endl;
}
答案 3 :(得分:2)
指向成员函数的指针也需要内存。他们也有一个大小。那么如何打印出指针的内存:
template<typename R, typename T, typename... Args>
std::string to_string(R (T::*func)(Args...))
{
union PtrUnion
{
R(T::*f)(Args...);
std::array<unsigned char, sizeof(func)> buf;
};
PtrUnion u;
u.f = func;
std::ostringstream os;
os << std::hex << std::setfill('0');
for (auto c : u.buf)
os << std::setw(2) << (unsigned)c;
return os.str();
}
你可以这样使用它:
class TestClass
{
void foo();
};
...
std::cout << to_string(&TestClass::foo) << std::endl;