对象方法的真实地址
True address of object's method
我知道我可以创建方法指针,并且我知道它们通常与函数指针不同。不允许在它们之间进行转换。方法指针可以包含有关如何调整指针等this
大量数据。
我想知道如何获取正在执行给定方法的代码的实际地址。此地址不会以任何方式被尊重,但将用作给定方法所属类型的标识符 - 有点像 RTTI,具有对库边界不敏感的优点,因为此代码通常仅在一个单元中可用。
编辑:
为什么我不添加一些返回对象类型的getType()
方法?
因为我希望能够以这种方式不仅使用我创建的类。我正在尝试做的基本上是我对variant
类的实现,它基本上可以接受所有内容,前提是存在给定类型的 void* getVariantId(( 的专用化。
所以我可以写:
template <typename T>
class getTypeId{
};
class foo{
public:
void bar();
};
// getTypeId declared but not defined for generic type T earlier...
template <>
class getTypeId<foo>{
static void* get<foo>(){
return &foo::bar;
}
};
void doSomething(myVariant var);
int main(int argc, char* argv[]){
foo f;
myVariant var = myVariant::fromType<foo*>(&f);
doSomething(f);
}
void doSomething(myVariant var){
foo* f = var.toType<foo*>(); // Returns foo object from main
int* i = var.toType<int*>(); // returns null, as var is not int* in my example.
}
这个想法是fromType
使用getTypeId
来获取类型的表示值,并将其与投射到void*
的对象指针一起进行缩放。 另一方面,toType
比较从'getTypeId::get获得的值和一个存储在对象中的值 - 如果它匹配,那么内部保留的对象指针将被重新解释回原始类型并返回。
这个解决方案的优点是,即使有一些共享库 X,定义了类型 x,那么单独使用库 X 的库 Y 和 Z 也会同意类型 x 是相同的(例如,如果 Y 中的变量创建被传递给 Z(,因为 X::method 上的地址保持不变。作为 Y 或 Z 库(但不是 X!!(的创建者,我不需要确保 X lib 启用了 RTTI,甚至不知道 myVariant 的存在,但 x 类型仍然完全兼容 myVariant 。
编辑2:
我现在看到没有独立于实现的方法来完成这项工作。但是,我认为这是不寻常需要的怪癖,因此不存在的功能,而不是无法创建的功能。我想我还没有明确我想要实现的目标以及我是如何计划的。所以:
我所说的库是指这里的共享库(.dll,.so等(。
每个非纯虚拟方法(意味着定义的每个方法(都必须具有实现。此实现的行为类似于接受一个附加参数
this
的函数 - 虚拟函数仅在调用方端不同。让我们以类 X 及其方法X::foo
为例。此方法仅绑定到 X 类型,即使类型 Y 继承了它,此方法也保持X::foo
,因此足以识别类型X
。覆盖子类Xchild
中的虚拟方法或覆盖方法实际上是使用新地址定义新方法 Xchild::foo。然后你可以用Xchild::foo
来表示Xchild
,但不能用X
。
如果类型 X(所有准确的方法(都是在库 libX 中定义的,并且 libY 和 libZ 都使用 libX(但彼此不知道(,并且为了自己的目的定义 getTypeId 使用 X 中的第一个方法来表示它(请注意,这不会对 libX 开发人员施加任何影响(,那么他们对 X 类型是一致的。如果应用程序开发人员使用 libY 获取变体并将其传递给 libZ,则两者都将正确识别提到的类型。
我不是在尝试开发类型转换变体 - 保存为 X 的变体只能读取为 X,即使传递给 myVariant 的实际指针是 Xchild。我对获取给定实例的最顶层类的类型不感兴趣 - 只是用于创建变体的类。
C++ FAQ Lite 用一整节专门介绍指向成员函数的指针。
有两个答案特别说明了为什么您尝试做的事情无法完成(至少不是以便携式方式(:
- 指针到成员函数是一种不同的动物:
C++引入了一种新型指针,称为指向成员的指针, 只能通过提供对象来调用。不要尝试 将指向成员的指针"转换为指向函数的指针;这 结果是不确定的,可能是灾难性的。例如,一个 指针到成员函数不需要包含计算机 相应函数的地址。
- 指针到成员函数可以指向虚函数:
指向成员函数的指针可能是数据结构,而不是 单指针。想一想:如果它指向一个虚拟的 函数,它实际上可能并不指向静态可解析的 一堆代码,所以它甚至可能不是一个普通的地址。
我想知道如何获取正在执行给定方法的代码的实际地址。此地址不会以任何方式被尊重,但将用作给定方法所属类型的标识符 - 有点像 RTTI,具有对库边界不敏感的优点,因为此代码通常仅在一个单元中可用。
RTTI不受翻译单位的限制。RTTI 围绕库的唯一限制是 DLL 边界,其中一个 DLL 将公开返回派生类的函数。而且我不是 100% 确定,但只要 DLL 和可执行文件都是使用相同的编译器构建的(并共享静态库(,我认为它仍然可以工作。
无论如何,你所要求的事情是无法做到的。成员指针不是指针,并且没有可移植的方法来获取指向成员函数的实际函数指针。
即使可以,它也不会为您提供类型的唯一标识符。毕竟,如果一个类不重写函数,或者如果函数不是虚拟的,那么该成员函数的地址对于使用它的每个类都是相同的。仅当函数是虚拟的并且类覆盖它时,它才会更改。
没有办法从中制作一个唯一的类型标识符。
在我看来,你想要的是 Boost.Any,它在内部使用 RTTI 来防止你投射到错误的类型。
您的计划崩溃的地方
您正在提出一个getTypeId
函数,该函数将像这样实现:
template<typename T>
SomeIdentifierTypedef getTypeId(const T &x)
{
void *ptr = GetMemberFuncPtr<T>(x, &x::foo);
return FindIdFromPtr(ptr);
}
这需要存在 GetMemberFuncPtr
,它接受一个成员指针和一个对象,并获取该成员的实际函数指针。此函数旨在为它收到的每个类型返回一个唯一值。
好的,现在考虑一下你说的话:
让我们以类 X 和它的方法 X::foo 为例。此方法仅绑定到 X 类型,即使类型 Y 继承了它,此方法仍保留为 X::foo,因此足以标识类型 X。
如果Y::foo
和X::foo
是相同的成员函数,那么它们自然具有相同的函数指针。因此,getTypeId(Y()) == getTypeId(X())
.这违反了getTypeId
的既定目标。如果类型为 Y,则希望它返回的值与类型 X 时的值不同。
如果类型 X(所有准确的方法(都是在库 libX 中定义的,并且libY 和 libZ 都使用 libX(但彼此不知道(,并且为了自己的目的定义 getTypeId 使用 X 中的第一个方法来表示它(请注意,这不会对 libX 开发人员施加任何影响(,那么他们对 X 类型是一致的。如果应用程序开发人员使用 libY 获取变体并将其传递给 libZ,则两者都将正确识别提到的类型。
这行不通,原因有二。首先,请注意,我对getTypeId
的实现::foo
其中。那是因为没有办法谈论类的任意方法。你必须使用一个名称(如果你想确定的话,可能是一个完整的签名(来谈论一个特定的功能。你不能只是说"从这个类型中给我一些功能"。你必须选择一个。
这意味着您必须为所有可能的模板类型选择相同的getTypeId
。因此,使用 getTypeId
的所有类都必须实现相同的函数。
哦,您可以尝试将其专门用于某些类型。但这直接涉及第二个问题。
共享库不共享函数,除非它们被显式共享。您不能共享X::foo
。libX
传递libY
libY
没有完整和单独定义的类的唯一方法是该类以某种方式隐藏。所以要么它是一个不透明的指针(void*
(,在这种情况下,你甚至无法获得它的成员函数。或者它是从libX
和libY
都有的定义派生的类。
也就是说,有一些(可能是抽象的(类base
,libX
和libY
都是针对它们编译的。 libX
创建从base
派生的X
,并且libX
公开了一些函数,该函数返回X
作为base *
。
在这种情况下,专业化无济于事,因为只有libX
才能访问专业化getTypeId<X>
。它工作的唯一方法是如果专业化是针对getTypeId<base>
的。但是,我们又遇到了一个问题,如果用户不覆盖虚拟函数怎么办?然后我们认为它仍然是一个base
.
即使测试函数是纯虚函数,也无济于事。这是因为libX
可以有一个派生自X
派生自base
的Y
。 X
可能已经实现了该功能,但Y
没有覆盖它。因此再次getTypeId(x) == getTypeId(y)
。
你的想法行不通。
如果你只想从彼此推断类型(所以基本上创建自定义RTTI(,你可以创建一个返回某种类型标识符的方法。
class MyFirst
{
public:
inline virtual string GetType() { return "Myfirst"; }
};
然后为您创建的每个类重载 GetType(( 函数。
这通常是最简单的方法(当然,除了dynamic_cast(。如果你真的想从虚拟调用中获取对象的类型,你可以设置一个静态标志来表示最后使用的类型,或者从该对象具有的每个函数中返回它。
如果你能写出你真正想要的"获取正在执行给定方法的代码的实际地址",你的问题肯定会更清楚。
- 将数组的地址分配给变量并删除
- 激励'inline'说明符的真实世界示例?
- 空基优化子对象的地址
- C++ 指针的内存地址和指向数组的内存地址如何相同?
- 在C++中打印指向不同基元数据类型的指针的内存地址
- 如何在c++程序中找到函数的地址
- 向量元素的引用地址与它所指向的向量元素的地址不同.为什么
- 被解释为低级别const的const对象的地址
- 将地址分配给本地指针后,公共对象的变量将消失
- 为什么我在leetcode上收到AddressSanitizer:地址0x602000000058上的堆缓冲区溢出错误
- 内联程序集printf将整数解释为地址
- 为什么指针不写入类的地址?
- 如何在C++中获取该对象的类声明中对象的地址?
- 如何在Windows上绕过主机文件获取真实的IP地址
- 如何从"const int i"获取i的真实地址
- 如何使用IOCP获取客户端的真实ip地址和端口
- 指针具有良好的地址,但不显示真实信息
- 对象方法的真实地址
- 获取虚成员函数的真实地址(或vTable中的索引)
- 为什么字符串形参与实参共享相同的地址