'this'指针可以与对象的指针不同吗?

时间:2013-08-21 22:13:46

标签: c++

我最近在某个课程中遇到过这个奇怪的功能:

void* getThis() {return this;}

稍后在代码中有时会使用它:bla->getThis()(其中 bla 是指向定义此函数的类的对象的指针。) 我似乎无法意识到这可能有什么好处。是否存在指向对象的指针与对象this(其中bla != bla->getThis())不同的情况?

这似乎是一个愚蠢的问题,但我想知道我在这里错过了什么......

5 个答案:

答案 0 :(得分:17)

当然,指针值可能不同!下面是一个演示此问题的示例(您可能需要在系统上使用derived1而不是derived2才能获得差异)。关键是当涉及虚拟,多重继承时,this指针通常会被调整。这可能是一种罕见的情况,但它确实发生了。

这个习惯用法的一个潜在用例是能够在将它们存储为void const*(或void*之后恢复已知类型的对象; const正确性在这里无关紧要):如果你有一个复杂的继承层次结构,你不能只是将任何奇怪的指针转换为void*,并希望能够将它恢复到原始类型!也就是说,为了轻松获得例如指向base的指针(来自下面的示例)并将其转换为void*,您可以调用p->getThis() static_cast<base*>(p)void*更容易base* static_cast<base*>(v) 1}}并获得一个static_cast<base*>(static_cast<void*>(d)),可以使用d安全地转换为base:您可以撤消隐式转换,但前提是您转换回原始版本的确切类型指针来自。也就是说,static_cast<base*>(d->getThis())其中base是指向从base派生的类型的对象的指针是非法的,但base是合法的。

现在,为什么地址会改变?在示例中,concrete是两个派生类的虚拟基类,但可能还有更多。其类实际上从base继承的所有子对象将在另一个派生类的对象中共享一个公共base主题(在下面的示例中为base)。根据不同类的排序方式,此#include <iostream> struct base { void const* getThis() const { return this; } }; struct derived1 : virtual base { int a; }; struct derived2 : virtual base { int b; }; struct concrete : derived1 , derived2 { }; int main() { concrete c; derived2* d2 = &c; void const* dptr = d2; void const* gptr = d2->getThis(); std::cout << "dptr=" << dptr << " gptr=" << gptr << '\n'; } 子对象的位置可能与相应的派生子对象不同。因此,指向{{1}}对象的指针通常不同于指向虚拟继承自{{1}}的类的子对象的指针。相关的偏移量将在编译时计算,如果可能,或者来自运行时的vtable。在沿继承层次结构转换指针时调整偏移量。

{{1}}

答案 1 :(得分:2)

No。是的,在有限的情况下。

这看起来像是受Smalltalk启发的东西,其中所有对象都有yourself方法。可能存在一些使代码更清晰的情况。正如评论所指出的,这看起来像是在c ++中实现这个习惯用法的奇怪方式。

在您的具体情况下,我会仔细查看该方法的实际用法,以了解它是如何使用的。

答案 2 :(得分:1)

您的班级可以拥有自定义operator&(因此&a可能无法返回this a}。这就是std::addressof存在的原因。

答案 3 :(得分:0)

我在很多年前(多年前)碰到过这样的事情。如果我没记错的话,当一个类操作同一个类的其他实例时需要它。一个例子可能是一个容器类,它可以包含自己的类型/(class?)。

答案 4 :(得分:0)

这可能是一种覆盖this关键字的方法。 假设您有一个内存池,在程序开始时已完全初始化,例如,您知道在任何时候您最多可以处理50条消息,CMessage。 您可以创建一个大小为50 * sizeof(CMessage)的池(这个类可能是什么),并且CMessage实现了getThis函数。

通过这种方式而不是覆盖新关键字,您只需覆盖“this”,即可访问池。 它也可能意味着对象可能在不同的存储空间中定义,比如在SRAM上,在引导模式下,然后在SDRAM上。

在这种情况下,当然,当覆盖时,同一个实例可能会通过程序为getThis返回不同的值。