通过将其转换为 void 指针然后转换为结构来访问类的私有成员是否合适?
我认为我没有权限修改包含我需要访问的数据成员的类。如果不道德,我不想冒险以间接方式访问数据成员。
编辑:必须进一步编辑这个......我很确定这个类不会被修改,所以在那个程度上没关系......我唯一担心的是,如果编写该类的人知道这一点,它可能不会和他相处得很好:(。
通过将其转换为 void 指针然后转换为结构来访问类的私有成员是否合适?
我认为我没有权限修改包含我需要访问的数据成员的类。如果不道德,我不想冒险以间接方式访问数据成员。
编辑:必须进一步编辑这个......我很确定这个类不会被修改,所以在那个程度上没关系......我唯一担心的是,如果编写该类的人知道这一点,它可能不会和他相处得很好:(。
让我们暂时不要考虑道德。让我们考虑一下标准。
你提议做的是非标准的。见标准第 9.2 节第 12 条。“由访问说明符分隔的非静态成员的分配顺序未指定。” 因此,如果您有一个具有私有成员的类和一个没有私有成员的结构,则标准不保证成员的顺序相同。
因此,如果你的 hack 有效,它只是偶然的,编译器作者碰巧这样做了。不能保证它可以在另一个编译器、同一编译器的更高版本或不同的类布局上工作。
更不用说,如果您无权修改类(例如,提供简单的访问器函数),那么如果类中的任何实现细节发生更改,您可能无权反对。(public 和 private 背后的想法之一是区分承诺的内容和可自由更改的内容。)因此,布局可能会发生变化,或者成员可能意味着不同的东西,或者被完全删除。
Herb Sutter 就这个问题写了一篇“本周大师”专栏。
哦,就道德而言?如果你真的,真的必须做这样的事情,而且你无法摆脱它,请非常仔细地记录它。如果您的编码标准有某种程序来标记非标准行为,请使用它们。如果没有,请非常小心地记下它,以便在出现问题时不会被忽视。
我不确定“道德”是否真的参与其中。不过,它破坏了封装。
编辑:如果我正在执行代码审查,我几乎永远不会接受这一点。你必须非常努力地说服我没有办法围绕这个需求进行设计。有可能你会成功,但必须到处都有重大警告,并进行严格的单元测试,以确保如果有任何改变来破坏它,你会很快知道。
我刚刚在我的博客中添加了一个条目,展示了如何以完全一致的方式完成它。这是有关如何将其用于以下课程的示例
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>
对象上使用它,这也是允许的。
我遇到过这种情况,因为有一个非常糟糕的源代码控制系统,对于旧版本的应用程序来说,对头文件进行更改几乎是不可能的。
如果在某些情况下你只需要做一个黑客。
在您需要访问私有数据成员的源文件中,您可以将其作为第一行放入:
#define private public
#define protected public
并访问您想要的任何内容。
不,你正在做的是纯粹的邪恶。
“永不说永不”。我敢肯定,在宇宙的某个地方,有一种情况会迫使你不得不这样做……
但如果我不得不这样做,我肯定会畏缩。在扣动扳机之前,您确实需要就您的情况获得很多意见。您能否描述一下您的具体情况,也许我们可以看看它是否有意义或可能存在哪些更好的选择?
回应评论/问题——定义“权限”——机构许可?这听起来不像是一个编程问题,而是可以与主张所述许可的人交谈。也许这更像是一个政治问题而不是技术问题?同样,我认为我们需要更多细节——即使它在某种程度上是关于局势的政治。但是,这可能会或可能不会被视为超出网站的范围。
如果您有这样做的冲动,请忘记强制转换 - 只需修改头文件中的类声明:
class A {
private:
int x;
};
将其更改为:
class A {
public:
int x;
};
你很高兴。好吧,也许“好”这个词不太合适。
这是合乎道德的,但通常有很多脏代码与未定义的行为和不可移植性相邻。只有在绝对必要时才这样做。
啊,抽象——没有它你就活不下去,但有时处理起来很痛苦:)
无论如何,抛开道德问题不谈,如果类的“所有者”决定更改内部实现,或者只是颠倒私有数据成员的顺序怎么办?
唯一的“道德”问题是你对可怜的混蛋所做的事情,他将不得不弄清楚并维护你的代码。
私人会员就是这样。他可能,而且很可能有一天会改变那个成员。发生这种情况时,您甚至可能不会注意到,因为那里很可能仍然存在内存,而不是您期望的成员。当你的代码运行时,任何你能想象到的几乎不可能发生的事情都可能开始发生。怎么会有人能够调试它?
简单的回答:没有。
这是不道德的,并且在某些时候会变成维护的噩梦。库的内部私有成员可以更改和破坏您的代码。库的开发人员不需要知道(也不想知道)您违反了封装。
类通常在其方法上具有不变量,有时不会记录在案,但从外部访问和更改值可能会破坏这些不变量。例如,如果您将向量中的保留空间更改为更高的值,则向量将不会分配新空间,直到它填满现有空间,并且在遇到未分配的内存之前不会发生这种情况:您的应用程序将崩溃。
如果该属性是私有的,则不能供你使用,只供类本身或知道成员、如何使用、如何不破坏它的类朋友使用。如果程序员希望您更改字段,它将是公开的。
我假设这门课是你正在从事的项目的一部分。
这里有一个道德问题:如果在您的公司中,您将代码的所有权视为骶骨。或者最糟糕的是,您不允许修改不属于您的代码。是的,您可能会伤害维持该课程的人的感觉。如果他的薪水与他的代码有关,或者激怒他。所以最好只是向他寻求任何帮助,并提供一些建议,例如。添加 getter 函数或将私有更改为公共 - 所有这些都基于您使用该新代码的直觉。
你提到的黑客真的是床上练习。如果不能修改该代码并且维护者不会改变任何东西。考虑使用适配器设计模式。