为什么C ++允许使用这种方法修改私有成员? [英] Why does C++ allow private members to be modified using this approach?

查看:160
本文介绍了为什么C ++允许使用这种方法修改私有成员?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

几分钟前看到这个问题后,我想知道为什么语言设计者允许它,因为它允许私人数据的间接修改。作为示例

  class TestClass {
private:
int cc;
public:
TestClass(int i):cc(i){};
};

TestClass cc(5);
int * pp =(int *)& cc;
* pp = 70; //私人会员已被修改

我测试了上述代码,确实私人数据已被修改。有什么解释为什么这是允许发生或这只是一个监督的语言?它似乎直接破坏了私人数据成员的使用。

解决方案

因为,正如Bjarne所说的,C ++旨在防止Murphy而不是Machiavelli。



换句话说,它应该保护你免受意外 - 但如果你去任何工作来颠覆它(例如使用演员),它甚至不会试图阻止你。



当我想到它时,我有一个不同的类比:它就像浴室门上的锁。它会给你一个警告,你可能不想要现在走在那里,但如果你决定,从外面解开门是微不足道的。



编辑:关于@Xeo讨论的问题,关于为什么标准说具有相同的访问控制,而不是有所有公共访问控制,答案是长而曲折的。 >

让我们回到开始,考虑一个像下面这样的结构:

  struct X {
int a;
int b;
};

C总是有一些像这样的结构的规则。一个是在结构体的实例中,结构体本身的地址必须等于 a 的地址,所以你可以将结构体的指针转换为指针 int ,并访问 a 并定义良好的结果。另一个是成员必须按照它们在结构中定义的顺序在内存中排列(尽管编译器可以在它们之间自由插入填充)。



对于C ++,有一个意图维护,尤其是对于现有的C结构。同时,有一个明显的意图,如果编译器想要强制 private (和 protected

因此,给定如下:

  struct Y {
int a;
int b;
private:
int c;
int d;
public:
int e;

//这里使用`c`和`d`的代码。
};

编译器应该被要求保持与C相同的规则,相对于 Ya Yb 。同时,如果它将在运行时强制访问,它可能需要将所有公共变量移动到内存中,因此布局将更像:

  struct Z {
int a;
int b;
int e;
private:
int c;
int d;
//使用`c`和`d`的代码在这里。
};

然后,当它在运行时强制执行时,它基本上可以做 if(offset> 3 * sizeof(int))access_violation();



据我所知,没有人做过这个, 'm不确定标准的其余部分是否真的允许它,但似乎至少有一个想法沿着那条线的半形成胚芽。



执行这两者,C ++ 98表示 Y :: a Y :: b 必须在这个顺序在内存中,并且 Y :: a 必须在结构的开头(即C样规则)。但是,由于中间访问说明符, Y :: c Y :: e 不再必须相对于彼此的顺序。换句话说,在它们之间没有访问说明符的情况下定义的所有连续变量被分组在一起,编译器可以自由地重新排列这些组(但仍然必须保持第一个在开头)。



这是很好,直到有些冲击(即我)指出,规则的写法有另一个小问题。如果我编写代码如下:

  struct A {
int a;
public:
int b;
public:
int c;
public:
int d;
};

...你最终有一点自相矛盾。一方面,这仍然是一个POD结构,所以类似C的规则应该适用 - 但是由于你有(无可否认的)成员之间的访问说明符,它也给了编译器重新排列成员的权限,因此打破他们想要的类似C的规则。



为了解决这个问题,他们重新写了标准,所以它会谈论所有具有相同访问权限的成员,而不是关于它们之间是否存在访问说明符。是的,他们可能刚刚宣布规则只适用于公共成员,但似乎没有人看到从中获得任何东西。鉴于这是修改一个现有的标准,有很多的代码已经使用了一段时间,选择了最小的变化,他们可以做,仍然可以解决这个问题。


After seeing this question a few minutes ago, I wondered why the language designers allow it as it allows indirect modification of private data. As an example

 class TestClass {
   private:
    int cc;
   public:
     TestClass(int i) : cc(i) {};
 };

 TestClass cc(5);
 int* pp = (int*)&cc;
 *pp = 70;             // private member has been modified

I tested the above code and indeed the private data has been modified. Is there any explanation of why this is allowed to happen or this just an oversight in the language? It seems to directly undermine the use of private data members.

解决方案

Because, as Bjarne puts it, C++ is designed to protect against Murphy, not Machiavelli.

In other words, it's supposed to protect you from accidents -- but if you go to any work at all to subvert it (such as using a cast) it's not even going to attempt to stop you.

When I think of it, I have a somewhat different analogy in mind: it's like the lock on a bathroom door. It gives you a warning that you probably don't want to walk in there right now, but it's trivial to unlock the door from the outside if you decide to.

Edit: as to the question @Xeo discusses, about why the standard says "have the same access control" instead of "have all public access control", the answer is long and a little tortuous.

Let's step back to the beginning and consider a struct like:

struct X {
    int a;
    int b;
};

C always had a few rules for a struct like this. One is that in an instance of the struct, the address of the struct itself has to equal the address of a, so you can cast a pointer to the struct to a pointer to int, and access a with well defined results. Another is that the members have to be arranged in the same order in memory as they are defined in the struct (though the compiler is free to insert padding between them).

For C++, there was an intent to maintain that, especially for existing C structs. At the same time, there was an apparent intent that if the compiler wanted to enforce private (and protected) at run-time, it should be easy to do that (reasonably efficiently).

Therefore, given something like:

struct Y { 
    int a;
    int b;
private:
    int c;
    int d;
public:
    int e;

    // code to use `c` and `d` goes here.
};

The compiler should be required to maintain the same rules as C with respect to Y.a and Y.b. At the same time, if it's going to enforce access at run time, it may want to move all the public variables together in memory, so the layout would be more like:

struct Z { 
    int a;
    int b;
    int e;
private:
    int c;
    int d;
    // code to use `c` and `d` goes here.
};

Then, when it's enforcing things at run-time, it can basically do something like if (offset > 3 * sizeof(int)) access_violation();

To my knowledge nobody's ever done this, and I'm not sure the rest of the standard really allows it, but there does seem to have been at least the half-formed germ of an idea along that line.

To enforce both of those, the C++98 said Y::a and Y::b had to be in that order in memory, and Y::a had to be at the beginning of the struct (i.e., C-like rules). But, because of the intervening access specifiers, Y::c and Y::e no longer had to be in order relative to each other. In other words, all the consecutive variables defined without an access specifier between them were grouped together, the compiler was free to rearrange those groups (but still had to keep the first one at the beginning).

That was fine until some jerk (i.e., me) pointed out that the way the rules were written had another little problem. If I wrote code like:

struct A { 
    int a;
public:
    int b;
public:
    int c;
public:
    int d;
};

...you ended up with a little bit of self contradition. On one hand, this was still officially a POD struct, so the C-like rules were supposed to apply -- but since you had (admittedly meaningless) access specifiers between the members, it also gave the compiler permission to rearrange the members, thus breaking the C-like rules they intended.

To cure that, they re-worded the standard a little so it would talk about the members all having the same access, rather than about whether or not there was an access specifier between them. Yes, they could have just decreed that the rules would only apply to public members, but it would appear that nobody saw anything to be gained from that. Given that this was modifying an existing standard with lots of code that had been in use for quite a while, the opted for the smallest change they could make that would still cure the problem.

这篇关于为什么C ++允许使用这种方法修改私有成员?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆