通过将类的私有成员转换为void指针然后转换为结构来访问它是否合适?
我认为我没有权限修改包含我需要访问的数据成员的类。如果不符合道德规范,我不想以间接方式冒险访问数据成员。
编辑:不得不进一步编辑...我很确定这个课程不会被修改,所以这样就可以了......我唯一关心的是,如果编写该课程的人知道的话这个,它可能不适合他:(。
答案 0 :(得分:27)
我们暂时不要考虑道德问题。让我们考虑标准。
你建议做的是非标准的。见标准第9.2节第9.2节。 “未指定由访问说明符分隔的非静态成员的分配顺序。”因此,如果您有一个具有私有成员的类,以及一个没有私有成员的结构,则该标准不保证成员的顺序相同。
因此,如果你的黑客工作,它只是偶然的,编译器编写者碰巧这样做。无法保证它可以在另一个编译器,同一编译器的更高版本或不同的类布局上工作。
更不用说,如果您没有权限修改类(例如,提供简单的访问器函数),如果类中的任何实现细节发生更改,您可能无权对象。 (公共和私人背后的一个想法是区分承诺与可自由变更的内容。)因此,布局可能会发生变化,或者成员可能意味着不同的东西,或者被完全删除。
Herb Sutter在这个问题上写了a Guru of the Week专栏。
哦,就道德而言呢?如果你真的,真的必须做这样的事情,而你无法摆脱它,请非常仔细地记录下来。如果您的编码标准有某种程序来标记非标准行为,请使用它们。如果没有,请小心注意,当出现问题时不会忽视它。
答案 1 :(得分:26)
我不确定“道德”真的会进入它。尽管如此,它还是破坏了封装。
编辑:如果我正在执行代码审查,我几乎从不接受这个。你必须努力工作 很难说服我没有办法围绕这个需求进行设计。你可能会成功,但是必须在整个地方发出重大警告,并进行坚硬的单元测试,以确保如果有任何改变可以打破它,你很快就会知道。
答案 2 :(得分:14)
我刚刚添加了一个entry to my blog,展示了如何以完全一致的方式完成它。以下是如何将其用于以下类
的示例struct A {
private:
int member;
};
只需声明标记名称并实例化强盗,如下面的示例所示(我的帖子显示了强盗的实施)。然后,您可以使用成员指针
访问该成员struct Amem { typedef int type; };
template class rob<Amem, &A::member>;
int main() {
A a;
a.*result<Amem>::ptr = 42; // Doh!
}
但实际上,这并没有表明c ++的访问规则不可靠。语言规则旨在防止意外错误 - 如果您尝试抢夺对象的数据,则 by-design 语言不会花费很长时间来阻止您。
以上是一种以符合标准的方式访问私有和受保护成员的方法。这是以标准符合方式访问受保护成员的另一种方法。基本思想是使用成员指针
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>
对象上使用它,这也是允许的。
答案 3 :(得分:9)
没有。你在做什么是Pure Evil。
答案 4 :(得分:6)
“永不言败”。我确信在宇宙的某个地方,有一种情况会迫使你不得不这样做......
但如果我不得不这样做,我当然会畏缩。在扣动扳机之前,你真的需要对你的情况有很多意见。你能描述一下你的具体情况吗?也许我们可以看看它是否有意义或者可能存在哪些更好的选择?
回应评论/问题 - 定义“权限” - 机构许可?这听起来不是一个编程问题,但可以与任何主张上述许可的人交谈。也许这更像是一个政治问题而不是技术问题?同样,我认为我们需要更具体的内容 - 即使它在某种程度上与情况的政治有关。但是,这可能会或可能不会被视为超出网站的范围。
答案 5 :(得分:6)
我遇到过这种情况,因为有一个非常糟糕的源代码控制系统,旧版本的应用程序对头文件进行更改几乎是不可能的。
如果有些情况你只需要做一个黑客攻击。
在您需要访问私有数据成员的源文件中,您可以将其作为第一行放入:
#define private public
#define protected public
并访问您想要的任何内容。
答案 6 :(得分:5)
如果您有这样做的冲动,请忘记转换 - 只需修改头文件中的类声明:
class A {
private:
int x;
};
将其更改为:
class A {
public:
int x;
};
你很高兴。好吧,也许“好”不是一个正确的词。
答案 7 :(得分:3)
这是道德的,但通常有很多脏代码与未定义的行为和不可移植性相邻。只有你绝对必须这样做才能做到。
答案 8 :(得分:2)
啊,抽象 - 你不能没有它,但有时候处理它是如此痛苦:)
无论如何,除了道德规范之外,如果班级的“所有者”决定改变内部实施,或者只是颠倒私人数据成员的顺序怎么办?
答案 9 :(得分:1)
简单回答:不。
这不符合道德规范,在某些时候会变成维护噩梦。库的内部私有成员可以更改和破坏您的代码。库的开发人员不需要知道(也不想)您违反了封装。
类通常在其方法上具有不变量,有时无法记录,但从外部访问和更改值可能会破坏这些不变量。例如,如果更改向量中的保留空间以获得更高的值,则向量将不会分配新空间,直到它填充现有空间并且在达到未分配的内存之前不会发生:应用程序将崩溃。
如果该属性是私有的,则不适合您使用它,仅适用于类本身或类的朋友,了解该成员,如何使用它,如何不破坏它。如果程序员想要你改变字段,那就是公开的。
答案 10 :(得分:1)
唯一的“道德”问题是你正在为那些将要弄清楚并维护你的代码的可怜的混蛋做些什么。
私人成员就是这样。有一天,他可能,而且很可能会改变那个成员。当发生这种情况时,您可能甚至都没有注意到,因为那里很可能仍然存在记忆,而不是您期望的成员。当你的代码运行时,你可以想象的任何几乎不可能的东西可能会开始发生。怎么会有人能够调试它?
答案 11 :(得分:0)
我认为这个课程是你正在进行的项目的一部分。
这里存在一个道德问题: 如果在您的公司中,您将代码的所有权视为骶骨。或者最糟糕的是,您不允许修改不属于您的代码。是的你可能会伤害维持这门课程的人的感觉。或者如果他的薪水与他的代码有关,他会生气。 所以最好只是向他寻求任何帮助,而且很少有建议,例如。添加getter函数或将private更改为public - 所有这些都基于您使用该新代码的直觉。
你提到的哈克真的是床上练习。如果不能修改该代码和维护者不要改变任何东西。考虑使用适配器设计模式。