Jas*_*ker 64 c++ encapsulation private-members
是的,我完全清楚我所询问的内容是完全愚蠢的,任何想要在生产代码中尝试这样的事情的人都应该被解雇和/或开枪.我主要是想看看是否可以做到.
现在已经不在了,有没有办法从类外部访问C++中的私有类成员?例如,有没有办法用指针偏移来做到这一点?
(天真和其他非生产准备技术欢迎)
正如评论中所指出的,我问了这个问题,因为我想写一篇关于过度封装的博客文章(以及它如何影响TDD).我想看看是否有办法说"使用私有变量不是100%可靠的方法来强制封装,即使在C++中也是如此." 最后,我决定更多地关注如何解决问题,而不是为什么这是一个问题,所以我没有像我原先计划的那样突出显示这里提到的一些东西,但我还是留下了一个链接.
无论如何,如果有人对它的出现感兴趣,那么它就是: 测试驱动开发的敌人第一部分:封装(我建议在你决定我疯了之前阅读它).
dal*_*lle 69
如果类包含任何模板成员函数,您可以专门化该成员函数以满足您的需要.即使原始开发人员没有想到它.
safe.h
class safe
{
int money;
public:
safe()
: money(1000000)
{
}
template <typename T>
void backdoor()
{
// Do some stuff.
}
};
Run Code Online (Sandbox Code Playgroud)
main.cpp中:
#include <safe.h>
#include <iostream>
class key;
template <>
void safe::backdoor<key>()
{
// My specialization.
money -= 100000;
std::cout << money << "\n";
}
int main()
{
safe s;
s.backdoor<key>();
s.backdoor<key>();
}
Run Code Online (Sandbox Code Playgroud)
输出:
900000
800000
Run Code Online (Sandbox Code Playgroud)
Joh*_*itb 54
我在我的博客中添加了一个条目(见下文),展示了如何完成它.以下是如何将其用于以下类的示例
struct A {
private:
int member;
};
Run Code Online (Sandbox Code Playgroud)
只需为它描述一个结构,然后实例化用于抢劫的实现类
// tag used to access A::member
struct A_member {
typedef int A::*type;
friend type get(A_member);
};
template struct Rob<A_member, &A::member>;
int main() {
A a;
a.*get(A_member()) = 42; // write 42 to it
std::cout << "proof: " << a.*get(A_member()) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
在Rob
类模板的定义是这样的需要,只有定义一次,不管有多少私有成员计划访问
template<typename Tag, typename Tag::type M>
struct Rob {
friend typename Tag::type get(Tag) {
return M;
}
};
Run Code Online (Sandbox Code Playgroud)
但是,这并未表明c ++的访问规则不可靠.语言规则旨在防止意外错误 - 如果您尝试抢夺对象的数据,则设计语言不会花费很长时间来阻止您.
Chr*_*isW 29
以下是偷偷摸摸,非法,依赖编译器,并且可能无法工作,具体取决于各种实现细节.
#define private public
#define class struct
Run Code Online (Sandbox Code Playgroud)
但它是你的OP的答案,你明确地邀请了一种技术,我引用它是"完全愚蠢的,并且任何希望在生产代码中尝试这样的事情的人都应该被解雇和/或开枪".
另一种技术是通过使用来自对象开头的硬编码/手动编码偏移来构造指针来访问私有成员数据.
Sma*_*acL 24
嗯,不知道这是否有效,但可能值得一试.创建另一个类,其布局与具有私有成员的对象相同,但私有更改为public.创建指向此类的指针变量.使用简单的强制转换将其指向具有私有成员的对象,并尝试调用私有函数.
期待火花,也许是崩溃;)
Rob*_*b K 12
class A
{
int a;
}
class B
{
public:
int b;
}
union
{
A a;
B b;
};
Run Code Online (Sandbox Code Playgroud)
应该这样做.
ETA:它适用于这种琐碎的课程,但作为一般情况,它不会.
TC++ PL Section C.8.3:"具有构造函数,析构函数或复制操作的类不能是union成员的类型......因为编译器不知道要销毁哪个成员."
所以我们留下最好的选择是宣布class B
匹配A
的布局和黑客来看一个班级的私人.
Mar*_*ork 10
如果您可以获得指向类成员的指针,则无论访问说明符是什么(甚至是方法),都可以使用指针.
class X;
typedef void (X::*METHOD)(int);
class X
{
private:
void test(int) {}
public:
METHOD getMethod() { return &X::test;}
};
int main()
{
X x;
METHOD m = x.getMethod();
X y;
(y.*m)(5);
}
Run Code Online (Sandbox Code Playgroud)
当然,我最喜欢的小黑客是后门的朋友模板.
class Z
{
public:
template<typename X>
void backDoor(X const& p);
private:
int x;
int y;
};
Run Code Online (Sandbox Code Playgroud)
假设上面的创建者为他的正常用途定义了backDoor.但是您想要访问该对象并查看私有成员变量.即使将上面的类编译成静态库,您也可以为backDoor添加自己的模板特化,从而访问成员.
namespace
{
// Make this inside an anonymous namespace so
// that it does not clash with any real types.
class Y{};
}
// Now do a template specialization for the method.
template<>
void Z::backDoor<Y>(Y const& p)
{
// I now have access to the private members of Z
}
int main()
{
Z z; // Your object Z
// Use the Y object to carry the payload into the method.
z.backDoor(Y());
}
Run Code Online (Sandbox Code Playgroud)
绝对可以使用C++中的指针偏移来访问私有成员.让我们假设我有以下类型定义,我想访问.
class Bar {
SomeOtherType _m1;
int _m2;
};
Run Code Online (Sandbox Code Playgroud)
假设Bar中没有虚拟方法,那么简单的情况就是_m1.C++中的成员存储为对象的内存位置的偏移量.第一个对象位于偏移0处,第二个对象位于sizeof(第一个成员)的偏移处,等等...
所以这是一种访问_m1的方法.
SomeOtherType& GetM1(Bar* pBar) {
return*(reinterpret_cast<SomeOtherType*>(pBar));
}
Run Code Online (Sandbox Code Playgroud)
现在_m2有点困难了.我们需要从原始字节移动原始指针sizeof(SomeOtherType)字节.转换为char是为了确保我以字节偏移量递增
int& GetM2(Bar* pBar) {
char* p = reinterpret_cast<char*>(pBar);
p += sizeof(SomeOtherType);
return *(reinterpret_cast<int*>(p));
}
Run Code Online (Sandbox Code Playgroud)
这个答案是基于@Johannes的答案/博客所展示的确切概念,因为这似乎是唯一的“合法”方式。我已将该示例代码转换为一个方便的实用程序。它很容易与 C++03 兼容(通过实现std::remove_reference
和替换nullptr
)。
#define CONCATE_(X, Y) X##Y
#define CONCATE(X, Y) CONCATE_(X, Y)
#define ALLOW_ACCESS(CLASS, MEMBER, ...) \
template<typename Only, __VA_ARGS__ CLASS::*Member> \
struct CONCATE(MEMBER, __LINE__) { friend __VA_ARGS__ CLASS::*Access(Only*) { return Member; } }; \
template<typename> struct Only_##MEMBER; \
template<> struct Only_##MEMBER<CLASS> { friend __VA_ARGS__ CLASS::*Access(Only_##MEMBER<CLASS>*); }; \
template struct CONCATE(MEMBER, __LINE__)<Only_##MEMBER<CLASS>, &CLASS::MEMBER>
#define ACCESS(OBJECT, MEMBER) \
(OBJECT).*Access((Only_##MEMBER<std::remove_reference<decltype(OBJECT)>::type>*)nullptr)
Run Code Online (Sandbox Code Playgroud)
ALLOW_ACCESS(<class>, <member>, <type>);
Run Code Online (Sandbox Code Playgroud)
ACCESS(<object>, <member>) = <value>; // 1
auto& ref = ACCESS(<object>, <member>); // 2
Run Code Online (Sandbox Code Playgroud)
struct X {
int get_member () const { return member; };
private:
int member = 0;
};
ALLOW_ACCESS(X, member, int);
int main() {
X x;
ACCESS(x, member) = 42;
std::cout << "proof: " << x.get_member() << std::endl;
}
Run Code Online (Sandbox Code Playgroud)