确定 C++ 中成员的类实例

Determine class instance of a member in C++

本文关键字:实例 成员 C++ 确定      更新时间:2023-10-16

我从未在任何语言中看到过这个,但我想知道这是否可以使用一些我不知道的技巧。

假设我有一个类似

struct A {
  // some members and methods ...
  some_t t;
  // more members ...
};   

void test(some_t& x) { // a reference to avoid copying a new some_t
    // obtain the A instance if x is the t member of an A 
    // or throw an error if x is not the t member of an A
    ...
    // do something
}

是否有可能获得其成员t xA实例?

不,不幸的是,这是不可能的。

如果你知道你对某个A实例的t成员有引用,你可以使用 container_of 来获取实例,例如 A* pa = container_of(&x, A, t); .

验证生成的指针是否确实是A在技术上是可能的,当且仅当A具有虚拟成员时,不幸的是,没有可移植的方法可以检查。

但是,您可以使用多重继承和dynamic_cast来实现类似的东西,这允许子对象之间的交叉转换。

您可以在some_t内部添加指向A的指针(当然,如果some_tstructclass

喜欢这个:

struct some_t
{
  A *a;
  ...
};
void test(some_t& x) 
{
  if( x.a )
  {
    // do some
  }
  else
    throw ...
}

如果你可以修改结构 A 及其构造函数,并且如果你能确保结构打包,你可以直接在 t 后面添加一个值,它包含一些魔术键。

struct A {
  ...
  some_t t
  struct magic_t
  { 
    uint32 code
    some_t* pt;
  } magic;
}
#define MAGICCODE 0xC0DEC0DE //or something else unique 

在 A 的构造函数中,执行以下操作:
this->magic.code = MAGICCODE; this->magic.pt = &(this->t);然后你可以写

bool test(some_t *t)  //note `*` not `&`
{
    struct magic_t* pm = (struct magic_t*)(t+1);
    return (pm->pt == t && pm->code == MAGICCODE);
}

这个答案不符合原始问题的所有要求,我已经删除了它,但 OP 要求我发布它。它显示了如何在非常特定的条件下计算从指向成员变量的指针的实例指针。

不应该这样做,但您可以:

#include <iostream>
#include <cstddef>
using namespace std;
struct A
{
    int x;
    int y;
};
struct A* find_A_ptr_from_y(int* y)
{
    int o = offsetof(struct A, y);
    return (struct A*)((char *)y - o);
}
int main(int argc, const char* argv[])
{
    struct A a1;
    struct A* a2 = new struct A;
    cout << "Address of a1 is " << &a1 << endl;
    cout << "Address of a2 is " << a2 << endl;
    struct A *pa1 = find_A_ptr_from_y(&a1.y);
    struct A *pa2 = find_A_ptr_from_y(&(a2->y));
    cout << "Address of a1 (recovered) is " << pa1 << endl;
    cout << "Address of a2 (recovered) is " << pa2 << endl;
}

输出

Address of a1 is 0x7fff5fbff9d0
Address of a2 is 0x100100080
Address of a1 (recovered) is 0x7fff5fbff9d0
Address of a2 (recovered) is 0x100100080

警告:如果你传递给find_A_ptr_from_y的不是指向(结构A).y的指针,那么你很可能会得到垃圾。

你不应该(几乎)永远不要这样做。请参阅下面的DasBoot评论。

我不太清楚你想做什么,但是如果你想在知道指向 A 成员的指针时找到指向结构 A 实例的指针,你可以这样做。

例如,请参阅 linux 内核中的container_of宏。

函数

test()的参数x不必是任何类的成员,只要test()是融合的。

如果在语义上在特定应用程序中x必须始终是类的成员,那么可以通过传递额外的参数或让some_t本身包含此类信息来提供该信息。 然而,这样做是非常不必要的,因为如果test()真的需要访问包含x的对象,那么为什么不简单地传递父对象本身呢? 或者只是test()成为同一类的成员函数,不传递任何参数? 如果原因是x可能属于不同的类,则可以采用多态性来解决此问题。

基本上,我建议在任何情况下,您都不需要以更简单,更安全和更面向对象的方式解决这种功能。