なぜなら、Bjarneが言うように、C ++はマキャヴェリではなく、マーフィーから保護するように設計されているからです。
言い換えれば、それは事故からあなたを守ることになっています-しかし、あなたがそれを破壊するために何か仕事に行く場合(キャストを使用するなど)、それはあなたを止めようとさえしません。
私がそれについて考えるとき、私は幾分異なるアナロジーを念頭に置いています:それは浴室のドアの錠のようなものです。おそらく今はそこに足を踏み入れたくないという警告が表示されますが、必要に応じて外側からドアのロックを解除するのは簡単です。
編集:@Xeoが議論する質問に関して、なぜ標準が「すべてのパブリックアクセス制御を持っている」のではなく「同じアクセス制御を持っている」と言っているのかについて、答えは長くて少し曲がりくねっています。
最初に戻って、次のような構造体について考えてみましょう。
struct X {
int a;
int b;
};
Cには、このような構造体に対して常にいくつかのルールがありました。1つは、構造体のインスタンスでは、構造体自体のアドレスがのアドレスと等しくa
なければならないため、構造体へのポインターをへのポインターにキャストし、明確に定義された結果int
でアクセスできることです。a
もう1つは、メンバーを構造体で定義されているのと同じ順序でメモリ内に配置する必要があることです(ただし、コンパイラはそれらの間にパディングを自由に挿入できます)。
C ++の場合、特に既存のC構造体の場合、それを維持する意図がありました。同時に、コンパイラーが実行時に強制(および)したい場合は、それを(合理的に効率的に)簡単に実行できるはずであるという明らかな意図がありました。private
protected
したがって、次のようなものが与えられます:
struct Y {
int a;
int b;
private:
int c;
int d;
public:
int e;
// code to use `c` and `d` goes here.
};
コンパイラは、およびに関してCと同じルールを維持する必要がY.a
ありY.b
ます。同時に、実行時にアクセスを強制する場合は、すべてのパブリック変数をメモリ内で一緒に移動する必要があるため、レイアウトは次のようになります。
struct Z {
int a;
int b;
int e;
private:
int c;
int d;
// code to use `c` and `d` goes here.
};
次に、実行時に実行する場合、基本的に次のようなことができます。if (offset > 3 * sizeof(int)) access_violation();
私の知る限り、誰もこれを行ったことがなく、標準の残りの部分が実際にそれを許可するかどうかはわかりませんが、少なくともその線に沿ってアイデアの半分の形の芽があったようです。
これらの両方を強制するために、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のようなルールを破る。
それを解決するために、彼らは標準を少し言い換えて、メンバー間にアクセス指定子があるかどうかではなく、すべてのメンバーが同じアクセス権を持っていることについて話しました。はい、彼らは規則が公のメンバーにのみ適用されるとただ布告したかもしれません、しかし誰もそれから得られるものを見なかったように見えます。これがかなり長い間使用されていた多くのコードで既存の標準を変更していたことを考えると、彼らが行うことができる最小の変更を選択したので、それでも問題は解決します。