访问说明符不是万无一失的吗?
如果我有一个这样的类,
class Sample
{
private:
int X;
};
那么我们无法从外部访问 X,所以这是非法的,
Sample s;
s.X = 10; // error - private access
但是我们可以使其可以访问而无需编辑类!我们需要做的就是这个,
#define private public //note this define!
class Sample
{
private:
int X;
};
//outside code
Sample s;
s.X = 10; //no error!
ideone 的工作代码: http://www.ideone.com/FaGpZ
这意味着,我们可以通过在类定义之前或 #include
之前定义此类宏来更改访问说明符,
#define public private //make public private
//or
#define protected private //make protected private
//or
#define so on
这不是 C++ 的问题吗(Macros/访问说明符/其他)?
无论如何,这个主题的要点是:
使用宏,我们很容易违反封装性。访问说明符并非万无一失! 我是对的吗?
If I've a class like this,
class Sample
{
private:
int X;
};
Then we cannot access X from outside, so this is illegal,
Sample s;
s.X = 10; // error - private access
But we can make it accessible without editing the class! All we need to do is this,
#define private public //note this define!
class Sample
{
private:
int X;
};
//outside code
Sample s;
s.X = 10; //no error!
Working code at ideone : http://www.ideone.com/FaGpZ
That means, we can change the access-specifiers by defining such macros just before the class definition, or before #include <headerfile.h>
,
#define public private //make public private
//or
#define protected private //make protected private
//or
#define so on
Isn't it a problem with C++ (Macros/access-specifiers/whatever)?
Anyway, the point of this topic is:
Using macros, we can easily violate encapsulation. Access-specifiers are not foolproof! Am I right?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
首先,这样做是违法的。
private
是一个关键字,不能将其用作宏中的标识符;你的程序将是格式错误的。但无论如何,这根本不是宏的问题。是那些以愚蠢的方式使用它们的傻瓜。 :) (他们的存在是为了帮助你保持安全,但他们不是为了帮助你保持安全并阻止对它们的所有访问,无论你尝试什么。C++ 可以防止 Murphy,而不是 Machiavelli。)
请注意,你可以访问私有内容以格式良好且定义明确的方式,如 此处演示。再说一次,这不是语言的问题,只是语言的工作不是做超出必要的事情来防止窥探。
First of all, it's illegal to do that.
private
is a keyword, and you can't use it as an identifier in a macro; your program would be ill-formed.But in any case, it's not a problem with macro's at all. It's with the fool who used them in a silly manner. :) (They're there to help you be safe, they're not there to help you be safe and block all access to them no matter what you try. C++ protects against Murphy, not Machiavelli.)
Note that you can access privates in a well-formed and well-defined manner, as demonstrated here. Again, this isn't a problem with the language, it's just not the job of the language to do more than necessary to keep prying hands out.
从技术上讲,您所展示的只是“我们可以将合法程序变成未定义的行为”,而无需编辑一个特定的类。
这已经不是什么新闻了。您还可以将其变成未定义的行为,只需在
main()
末尾添加这样一行:C++ 中的访问说明符不是安全功能 它们不能防止黑客尝试,而且它们不要防范人们故意试图在您的代码中引入错误。
它们只是允许编译器帮助您维护某些类不变量。如果您不小心尝试像访问公共成员一样访问私有成员,它们允许编译器通知您。您所展示的只是“如果我专门尝试破坏我的程序,我可以”。希望这不会让任何人感到惊讶。
正如 @Gman 所说,在 C++ 语言中重新定义关键字是未定义的行为。它似乎可以在您的编译器上运行,但它不再是一个定义良好的 C++ 程序,并且编译器原则上可以做任何它喜欢做的事情。
Technically, all you've shown is that "we can turn a legal program into Undefined Behavior" without editing one specific class.
That's hardly news. You can also turn it into undefined behavior just by adding a line such as this to the end of
main()
:Access specifiers in C++ are not a security feature They do not safeguard against hacking attempts, and they do not safeguard against people willfully trying to introduce bugs into you code.
They simply allow the compiler to help you maintain certain class invariants. They allow the compiler to inform you if you accidentally try to access a private member as if it were public. All you've shown is that "if I specifically try to break my program, I can". That, hopefully, should be a surprise to absolutely no one.
As @Gman said, redefining keywords in the C++ language is undefined behavior. It may seem to work on your compiler, but it is no longer a well-defined C++ program, and the compiler could in principle do anything it likes.
但不编辑包含该类的源文件。
是的,宏会让你搬起石头砸自己的脚。这几乎不是什么新闻......但这是一个特别不麻烦的例子,至于“违反封装”,你必须强制类要么定义简单的宏本身,要么包含一个这样做的头文件。
换句话说:您能认为这是负责任的软件开发中的一个问题吗?
Not without editing the source file containing the class though.
Yes, macros let you shoot yourself in the foot. This is hardly news... but this is a particularly non-troubling example of it, as to "violate encapsulation" you have to force the class to either define the bone-headed macro itself, or include a header file which does so.
To put it another way: can you see this being an issue in real, responsible software development?
@Nawaz,你的帖子很有趣,我以前从未想过这一点。然而,我相信你的问题的答案很简单:将 C++(或可能任何语言)安全性视为组织代码的一种方式,而不是一种警察。
基本上,由于所有变量都是在您自己的代码中定义的,因此无论您在何处定义它们,您都应该能够访问它们。因此,您不应该对找到访问私人成员的方法感到惊讶。
实际上,还有一种更简单的方法来访问私有变量。想象一下,您有一个包含此类的库:
假设我在代码中使用您非常安全的类。我可以通过这种方式轻松访问私人成员:
怎么样?!!
@Nawaz, your post is interesting, I never thought of this before. However, I believe the answer to your question is simple: think of C++ (or probably any language) security as a way to organize your code, rather than a police.
Basically, since all the variables are defined in your own code, you should be able to access them ALL, no matter where you define them. So you shouldn't be surprised you found a way to access a private member.
Actually, there is even an easier method to access private variables. Imagine you have a library with this class:
And let's say I am using your very secure class in my code. I can easily access the private member this way:
How is that?!!
不,它会破坏私有方法。如果编译器能够判断这些私有方法不能在其他地方访问,那么它们可以被内联和优化掉,并且它们可能不会出现在目标文件中,因此它们将不可访问。
以此为例。它要么工作,要么无法链接,要么无法运行可执行文件,具体取决于您使用的优化/剥离标志以及编译方式(即,您可以将实现放在共享库中或不将实现放在共享库中)
实现文件:
用户文件 :
No. it will break havoc with private methods. if the compiler is able to tell that these private methods cannot be accessed elsewhere, then they can be inlined and optimized-out, and they may not appear in the object file, so they will be inaccessible.
Take this as an example. It either works, can't link or can't run the executable depending on the optimization/stripping flags you use and how you compile the thing (ie, you can put the implementation in a shared library or not)
implementation file :
the user file :