0

main.cpp 内部

class vivek
{
    int i;
    float d;
public:
    vivek()
    {
        i = 4;
        d = 4.44;
    }
    ~vivek()
    {
        cout << "destructor" << i;
    }
    int get()
    {
        return i;
    }
};

int main()
{
    vivek *viku = new vivek;
    vivek *p;

    p = viku;
    cout << (*(int*) (p));
    getchar();

    return 0;
}

通过上面的代码我可以访问变量 i ,但我想知道如何访问变量 d 。

我知道这个概念是不可取的,因为它违反了封装..但我只想知道我们怎么能做到这一点?

4

6 回答 6

2

虽然它非常hacky,但它可能的,因为它vivek是一个标准布局结构。这意味着您可以这样做:

#include <iostream>

// copied from original
class vivek {
  int i;
  float d;
public:
  vivek() {i = 4; d = 4.44; }
  ~vivek() { cout<<"destructor"<<i; }
  int get() { return i; }
};

struct vivek_sneaky_accessor {
  int i;
  float d;
};

int main() {
  vivek v;
  vivek_sneaky_accessor *acc = reinterpret_cast<vivek_sneaky_accessor*>(&v);
  std::cout << acc->d;
  return 0;
}

这依赖于 [class] 点 7 和 8(标准布局结构的定义)以及 [class.mem] 点 17 和 20(标准布局结构的布局兼容性)。

免责声明我绝不提倡这是合理的做法。我只是说这实际上是可能的。

于 2012-11-27T14:14:30.147 回答
2

我会冒险投反对票,因为我认为您这样做是为了理解指针。

也许,你所期待的是这样的:
int * x=reinterpret_cast<int *>(p);
x++;
cout<<*reinterpret_cast<float *>(x);

哪个有效,并且可能适用于您遇到的大多数编译器。但是,有很多原因可以说明您不能做这样的事情。

访问权限的使用和滥用必读的。

另请注意,该标准清楚地评论了由访问说明符分隔的成员的顺序。从另一个软答案:

分配没有中间访问说明符的(非联合)类的非静态数据成员,以便后面的成员在类对象中具有更高的地址。由访问说明符分隔的非静态数据成员的分配顺序未指定 (11.1)

于 2012-11-27T14:22:23.130 回答
1

在班上vivek

public:
  float getD() {
    return this -> d;
  }

并在您的代码中调用它,如下所示:

std::cout << (p -> getD()) << std::endl;
于 2012-11-27T13:54:06.197 回答
1

如果您想要/需要访问它们,请将它们设为public. 这就是 . 的意义所在public,这意味着该类的用户可以查看和更改public.

有人可能会告诉你,这“破坏了封装”。但是,如果您只需要该类保存一些值,并且您不需要做任何花哨的事情,那么公开数据成员就不是问题。

于 2012-11-27T13:58:23.803 回答
1

冒着被语言律师否决的风险,这里有一些黑客的建议给你,希望它可能会很有趣。私有成员不应该从类和类的朋友之外访问。但是,如果您绝对必须访问该类的那些成员字段,那么像这样的 hack 可能会起作用:

#include <iostream>

class vivek {
    int   i;
    float d;

  public:
    vivek() : i(4), d(4.44) {}
    ~vivek() {}
};

int main()
{
    vivek viku;
    struct badhack {
        int   i;
        float d;
    } *h = (sizeof(badhack) == sizeof viku ? (badhack*)&viku
            : ((badhack*)((char*)&viku + sizeof(void*))));
    std::cout << "i=" << h->i << ", d=" << h->d << std::endl;
}

请注意使用 sizeof 的游戏——这只是确定一个虚拟表的示例,该表采用sizeof(void*)字节并且是类中的第一个隐式字段,是否应该有任何虚拟成员。如果你不这样做并且一个类恰好有一个虚拟表,那么数据偏移量就会被搞砸,这个技巧将不起作用,所以这就是我们按sizeof(void*)字节调整偏移量以避免这个问题的原因。现在,这不是由标准定义的并且是特定于编译器的,但我从未遇到过以不同方式实现虚拟表的编译器,因为这是最有效的方式。

另一种选择就像这样简单:

#include <iostream>

#define class struct
#define private public

class vivek {
    int   i;
    float d;

  public:
    vivek() : i(4), d(4.44) {}
    ~vivek() {}
};

int main()
{
    vivek viku;
    std::cout << "i=" << viku.i << ", d=" << viku.d << std::endl;

    return 0;
}

但是请注意,上述内容很可能不适用于成员函数。如今的编译器很聪明,并且根据访问级别不同地修改函数名称。

并且请不要使用这样的技巧,除非有必要挽救某人的生命并且您愿意牺牲自己的生命作为回报。

于 2012-11-27T14:31:58.573 回答
0

虽然当然可以将您的对象视为字节序列并直接摆弄这些字节,但这是一个非常糟糕的主意。拥有类和对象的全部意义在于让您不必考虑数据在内存中的实际布局方式。

于 2012-11-27T14:32:30.730 回答