16

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

void* getThis() {return this;}

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

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

4

5 回答 5

17

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

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

现在,为什么首先要更改地址?在示例base中是两个派生类的虚拟基类,但可能还有更多。其类实际上继承自的所有子对象将在进一步派生类的对象中base共享一个共同的主题(在下面的示例中)。根据不同类的排序方式,该子对象的位置可能相对于相应的派生子对象不同。结果,指向对象的指针通常不同于指向虚拟继承的类的子对象的指针baseconcretebasebasebase. 如果可能,相关偏移量将在编译时计算,或者在运行时来自诸如 vtable 之类的东西。沿继承层次结构转换指针时会调整偏移量。

#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';
}
于 2013-08-21T22:39:08.387 回答
2

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

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

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

于 2013-08-21T22:33:47.193 回答
1

您的班级可以有自定义operator&(因此&a可能不会返回thisa。这就是std::addressof存在的原因。

于 2013-08-21T23:44:22.717 回答
0

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

于 2013-08-21T22:42:44.460 回答
0

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

这样,您无需覆盖 new 关键字,而是覆盖“this”,访问池。这也可能意味着对象可能定义在不同的内存空间上,比如说在 SRAM 上、在引导模式下,然后在 SDRAM 上。

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

于 2013-08-21T22:47:01.030 回答