访问main函数内的私有数据

时间:2012-11-27 13:50:56

标签: c++

在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。

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

6 个答案:

答案 0 :(得分:2)

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

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

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

Uses and Abuses of Access Rights 必须读取。

另请注意,该标准明确注释了由访问说明符分隔的成员的顺序。从another发送回答:

  

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

答案 1 :(得分:1)

在班级vivek

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

并在您的代码中调用它:

std::cout << (p -> getD()) << std::endl;

答案 2 :(得分:1)

如果您想要/需要访问它们,请将它们设为public。这就是public的要点,这意味着允许该类的用户查看和更改public的内容。

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

答案 3 :(得分:1)

虽然它非常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点(标准布局结构的布局兼容性)。

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

答案 4 :(得分: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;
}

但请注意,上述内容最有可能不适用于成员函数。这些编译器的智能和功能名称根据其访问级别而有所不同。

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

答案 5 :(得分:0)

虽然当然可以将对象视为一个字节序列并直接对这些字节进行调整,但这是一个非常糟糕的主意。拥有类和对象的重点是为您省去必须考虑数据如何在内存中实际布局的麻烦。