私人会员黑客行为是定义行为吗?

发布于 2024-09-01 17:05:02 字数 805 浏览 7 评论 0原文

我有以下课程:

class BritneySpears
{
  public:

    int getValue() { return m_value; };

  private:

    int m_value;
};

这是一个外部库(我无法更改)。我显然无法更改m_value的值,只能读取它。即使从 BritneySpears 派生也行不通。

如果我定义以下类会怎样:

class AshtonKutcher
{
  public:

    int getValue() { return m_value; };

  public:

    int m_value;
};

然后执行:

BritneySpears b;

// Here comes the ugly hack
AshtonKutcher* a = reinterpret_cast<AshtonKutcher*>(&b);
a->m_value = 17;

// Print out the value
std::cout << b.getValue() << std::endl;

我知道这是不好的做法。但只是出于好奇:这保证有效吗?它是定义的行为吗?

额外问题:你曾经不得不使用如此丑陋的黑客吗?

编辑:只是为了吓唬更少的人:我不打算在真实代码中实际执行此操作。我只是想知道;)

I have the following class:

class BritneySpears
{
  public:

    int getValue() { return m_value; };

  private:

    int m_value;
};

Which is an external library (that I can't change). I obviously can't change the value of m_value, only read it. Even deriving from BritneySpears won't work.

What if I define the following class:

class AshtonKutcher
{
  public:

    int getValue() { return m_value; };

  public:

    int m_value;
};

And then do:

BritneySpears b;

// Here comes the ugly hack
AshtonKutcher* a = reinterpret_cast<AshtonKutcher*>(&b);
a->m_value = 17;

// Print out the value
std::cout << b.getValue() << std::endl;

I know this is bad practice. But just out of curiosity: is this guaranteed to work? Is it defined behaviour?

Bonus question: Have you ever had to use such an ugly hack?

Edit: Just to scare fewer people: I don't intend to actually do this in real code. I'm just wondering ;)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

勿挽旧人 2024-09-08 17:05:03

您可能无法修改 BritneySpears 的库,但您应该能够修改 .h 头文件。如果是这样,您可以让 AshtonKutcher 成为 BritneySpears 的朋友:

class BritneySpears 
{
    friend class AshtonKutcher;
  public: 

    int getValue() { return m_value; }; 

  private: 

    int m_value; 
}; 

class AshtonKutcher 
{ 
  public: 

    int getValue(const BritneySpears & ref) { return ref.m_value; }; 
}; 

我真的不能容忍这种伎俩,而且我想我自己也没有尝试过,但是它应该是合法的、定义明确的 C++。

You might not be able to modify the library for BritneySpears, but you should be able to modify the .h header file. If so, you can make AshtonKutcher a friend of BritneySpears:

class BritneySpears 
{
    friend class AshtonKutcher;
  public: 

    int getValue() { return m_value; }; 

  private: 

    int m_value; 
}; 

class AshtonKutcher 
{ 
  public: 

    int getValue(const BritneySpears & ref) { return ref.m_value; }; 
}; 

I can't really condone this trick, and I don't think I've ever tried it myself, but it should be legal well-defined C++.

陌上青苔 2024-09-08 17:05:03

@Marcelo 说得对:成员的顺序在不同的访问级别上是未定义的。

但请考虑以下代码;这里,AshtonKutcher 的布局与 BritneySpears 完全相同:

class AshtonKutcher
{
  public:
    int getValue() { return m_value; };
    friend void setValue(AshtonKutcher&, int);

  private:
    int m_value;
};

void setValue(AshtonKutcher& ac, int value) {
    ac.m_Value = value;
}

我相信这实际上可能是有效的 C++。

@Marcelo has it right: the order of members is undefined across different access levels.

But consider the following code; here, AshtonKutcher has exactly the same layout as BritneySpears:

class AshtonKutcher
{
  public:
    int getValue() { return m_value; };
    friend void setValue(AshtonKutcher&, int);

  private:
    int m_value;
};

void setValue(AshtonKutcher& ac, int value) {
    ac.m_Value = value;
}

I believe that this may actually be valid C++.

断肠人 2024-09-08 17:05:03

您的代码存在问题,答案已用下划线突出显示。问题来自于对值进行排序。

然而,您几乎已经完成了:

class AshtonKutcher
{
public:

  int getValue() const { return m_value; }
  int& getValue() { return m_value; }

private:
  int m_value;
};

现在,您拥有完全相同的布局,因为您具有相同的属性,以相同的顺序声明,并且具有相同的访问权限......并且两个对象都没有虚拟表。

因此,诀窍不是改变访问级别,而是添加一个方法:)

当然,除非我错过了一些东西。

我准确地说这是一场维护噩梦吗?

There is an issue with your code, underlined by the answers. The problem comes from ordering the values.

However you were almost there:

class AshtonKutcher
{
public:

  int getValue() const { return m_value; }
  int& getValue() { return m_value; }

private:
  int m_value;
};

Now, you have the exact same layout because you have the same attributes, declared in the same order, and with the same access rights... and neither object has a virtual table.

The trick is thus not to change the access level, but to add a method :)

Unless, of course, I missed something.

Did I precise it was a maintenance nightmare ?

乄_柒ぐ汐 2024-09-08 17:05:03

通常应避免使用reinterpret_cast,并且不能保证给出便携式结果

另外,为什么要更改私人成员?您可以将原始类包装在一个新类中(首选组合而不是继承)并根据需要处理 getValue 方法。

Use of reinterpret_cast should usually be avoided and it's not guaranteed to give portable results.

Also, why do you want to change the private member? You could just wrap the original class in a new one (prefer composition over inheritance) and handle the getValue method as you wish.

胡大本事 2024-09-08 17:05:02

这是未定义的行为。每个访问限定符部分中的成员都保证按照它们出现的顺序排列,但访问限定符之间没有这样的保证。例如,如果编译器选择将所有私有成员放在所有公共成员之前,则上述两个类将具有不同的布局。

编辑:重新审视这个旧答案,我意识到我错过了一个相当明显的点:结构定义每个都只有一个数据成员。成员函数的顺序无关紧要,因为它们不影响类的布局。您可能会发现两个数据成员都保证位于同一个位置,尽管我不太了解该标准,无法确定。

但!您无法在不相关的类型之间取消引用reinterpret_cast结果。依然是UB。至少,这是我对 http://en.cppreference.com/w/cpp 的阅读/language/reinterpret_cast,这确实读起来很粗糙。

This is undefined behaviour. The members within each access-qualifier section are guaranteed to be laid out in the order they appear, but there is no such guarantee between acccess qualifiers. For instance, if the compiler chooses to place all private members before all public members, the above two classes will have a different layout.

Edit: Revisiting this old answer, I realized that I missed a rather obvious point: the struct definitions have exactly one data member each. The order of member functions is irrelevant, since they don't contribute to the class's layout. You might well find that both data members are guaranteed to be in the same place, though I don't know the standard well enough to say for sure.

But! You cannot dereference the result of reinterpret_casting between unrelated types. It's still UB. At least, that's my reading of http://en.cppreference.com/w/cpp/language/reinterpret_cast, which is a gnarly read indeed.

横笛休吹塞上声 2024-09-08 17:05:02

这是未定义的行为,原因是 Marcelo 指出出去。但有时在集成无法修改的外部代码时,您需要诉诸这些东西。一种更简单的方法(以及同样未定义的行为)是:

#define private public
#include "BritneySpears.h"

This is undefined behavior, for the reasons Marcelo pointed out. But sometimes you need to resort to such things when integrating external code you can't modify. A simpler way to do it (and equally undefined behavior) is:

#define private public
#include "BritneySpears.h"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文