9

通过将其转换为 void 指针然后转换为结构来访问类的私有成员是否合适?

我认为我没有权限修改包含我需要访问的数据成员的类。如果不道德,我不想冒险以间接方式访问数据成员。

编辑:必须进一步编辑这个......我很确定这个类不会被修改,所以在那个程度上没关系......我唯一担心的是,如果编写该类的人知道这一点,它可能不会和他相处得很好:(。

4

12 回答 12

28

让我们暂时不要考虑道德。让我们考虑一下标准。

你提议做的是非标准的。见标准第 9.2 节第 12 条。“由访问说明符分隔的非静态成员的分配顺序未指定。” 因此,如果您有一个具有私有成员的类和一个没有私有成员的结构,则标准不保证成员的顺序相同。

因此,如果你的 hack 有效,它只是偶然的,编译器作者碰巧这样做了。不能保证它可以在另一个编译器、同一编译器的更高版本或不同的类布局上工作。

更不用说,如果您无权修改类(例如,提供简单的访问器函数),那么如果类中的任何实现细节发生更改,您可能无权反对。(public 和 private 背后的想法之一是区分承诺的内容和可自由更改的内容。)因此,布局可能会发生变化,或者成员可能意味着不同的东西,或者被完全删除。

Herb Sutter 就这个问题写了一篇“本周大师”专栏。

哦,就道德而言?如果你真的,真的必须做这样的事情,而且你无法摆脱它,请非常仔细地记录它。如果您的编码标准有某种程序来标记非标准行为,请使用它们。如果没有,请非常小心地记下它,以便在出现问题时不会被忽视。

于 2009-04-07T15:20:12.093 回答
25

我不确定“道德”是否真的参与其中。不过,它破坏了封装。

编辑:如果我正在执行代码审查,我几乎永远不会接受这一点。你必须非常努力地说服我没有办法围绕这个需求进行设计。有可能你会成功,但必须到处都有重大警告,并进行严格的单元测试,以确保如果有任何改变来破坏它,你会很快知道。

于 2009-04-07T14:44:58.527 回答
18

我刚刚在我的博客中添加了一个条目,展示了如何以完全一致的方式完成它。这是有关如何将其用于以下课程的示例

struct A {
private:
  int member;
};

只需声明一个标签名称并实例化一个 robber,如下例所示(我的帖子显示了 robber 的实现)。然后,您可以使用成员指针访问该成员

struct Amem { typedef int type; };
template class rob<Amem, &A::member>;

int main() {
  A a;
  a.*result<Amem>::ptr = 42; // Doh!
}

但实际上,这并不能说明 c++ 的访问规则不可靠。语言规则旨在防止意外错误 - 如果您试图窃取对象的数据,语言设计不会花很长时间来阻止您。


以上是一种以一致的方式访问私有和受保护成员的方法。这是另一种以符合标准的方式访问受保护成员的方法。基本思想是使用成员指针

std::deque<int> &getAdapted(std::stack<int> &s) {
    struct voyeur : stack<int> 
    { using stack<int>::c; };
    return s.*(&voyeur::c);
}

int main() {
    std::stack<int> s;
    std::deque<int> &adapted = getAdapted(s);
    output(adapted); // print the stack...
}

不涉及铸造或类型双关语。它通过从它派生的类获取一个指向受保护成员的指针,std::stack<int>其中该成员名称是公共的,因此编译器允许这样做。然后它在一个std::stack<int>对象上使用它,这也是允许的。

于 2009-06-25T14:59:46.423 回答
8

我遇到过这种情况,因为有一个非常糟糕的源代码控制系统,对于旧版本的应用程序来说,对头文件进行更改几乎是不可能的。

如果在某些情况下你只需要做一个黑客。

在您需要访问私有数据成员的源文件中,您可以将其作为第一行放入:

#define private public
#define protected public

并访问您想要的任何内容。

于 2009-04-07T15:32:24.247 回答
7

不,你正在做的是纯粹的邪恶。

于 2009-04-07T14:46:34.903 回答
5

“永不说永不”。我敢肯定,在宇宙的某个地方,有一种情况会迫使你不得不这样做……

但如果我不得不这样做,我肯定会畏缩。在扣动扳机之前,您确实需要就您的情况获得很多意见。您能否描述一下您的具体情况,也许我们可以看看它是否有意义或可能存在哪些更好的选择?

回应评论/问题——定义“权限”——机构许可?这听起来不像是一个编程问题,而是可以与主张所述许可的人交谈。也许这更像是一个政治问题而不是技术问题?同样,我认为我们需要更多细节——即使它在某种程度上是关于局势的政治。但是,这可能会或可能不会被视为超出网站的范围。

于 2009-04-07T14:47:21.220 回答
4

如果您有这样做的冲动,请忘记强制转换 - 只需修改头文件中的类声明:

class A {
  private:
    int x;
};

将其更改为:

class A {
  public:
    int x;
};

你很高兴。好吧,也许“好”这个词不太合适。

于 2009-04-07T14:47:35.760 回答
3

这是合乎道德的,但通常有很多脏代码与未定义的行为和不可移植性相邻。只有在绝对必要时才这样做。

于 2009-04-07T14:46:18.947 回答
2

啊,抽象——没有它你就活不下去,但有时处理起来很痛苦:)

无论如何,抛开道德问题不谈,如果类的“所有者”决定更改内部实现,或者只是颠倒私有数据成员的顺序怎么办?

于 2009-04-07T14:51:29.167 回答
1

唯一的“道德”问题是你对可怜的混蛋所做的事情,他将不得不弄清楚并维护你的代码。

私人会员就是这样。他可能,而且很可能有一天会改变那个成员。发生这种情况时,您甚至可能不会注意到,因为那里很可能仍然存在内存,而不是您期望的成员。当你的代码运行时,任何你能想象到的几乎不可能发生的事情都可能开始发生。怎么会有人能够调试它?

于 2009-04-07T17:59:47.107 回答
0

简单的回答:没有。

这是不道德的,并且在某些时候会变成维护的噩梦。库的内部私有成员可以更改和破坏您的代码。库的开发人员不需要知道(也不想知道)您违反了封装。

类通常在其方法上具有不变量,有时不会记录在案,但从外部访问和更改值可能会破坏这些不变量。例如,如果您将向量中的保留空间更改为更高的值,则向量将不会分配新空间,直到它填满现有空间,并且在遇到未分配的内存之前不会发生这种情况:您的应用程序将崩溃。

如果该属性是私有的,则不能供你使用,只供类本身或知道成员、如何使用、如何不破坏它的类朋友使用。如果程序员希望您更改字段,它将是公开的。

于 2009-04-07T14:51:47.137 回答
-1

我假设这门课是你正在从事的项目的一部分。

这里有一个道德问题:如果在您的公司中,您将代码的所有权视为骶骨。或者最糟糕的是,您不允许修改不属于您的代码。是的,您可能会伤害维持该课程的人的感觉。如果他的薪水与他的代码有关,或者激怒他。所以最好只是向他寻求任何帮助,并提供一些建议,例如。添加 getter 函数或将私有更改为公共 - 所有这些都基于您使用该新代码的直觉。

你提到的黑客真的是床上练习。如果不能修改该代码并且维护者不会改变任何东西。考虑使用适配器设计模式。

于 2009-11-28T17:32:38.363 回答