Потому что, как выразился Бьярне, C++ предназначен для защиты от Мерфи, а не Макиавелли.
Другими словами, он должен защищать вас от несчастных случаев, но если вы идете на любую работу, чтобы подорвать ее (например, используя приведение), она даже не попытается остановить вас.
Когда я думаю об этом, у меня есть несколько другая аналогия в виду: это как замок на двери в ванной. Это дает вам предупреждение, что вы, вероятно, не должны хотите, чтобы идти туда прямо сейчас, но это тривиально, чтобы открыть дверь снаружи, если вы решите.
Редактировать: что касается вопроса @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;
// 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();
Насколько мне известно, никто никогда не делал этого, и я не уверен, что остальная часть стандарта действительно позволяет это, но похоже, что, по крайней мере, сформированный зародыш идеи вдоль этой линии.
Для применения обоих из них, С ++ 98 сказал Y::a
и Y::b
должен был быть в том порядке, в памяти, и Y::a
должны были быть в начале структуры (т.е. С-подобные правила). Но из-за промежуточных спецификаторов доступа Y::c
и Y::e
больше не должны были быть относительно друг друга.Другими словами, все последовательные переменные, определенные без спецификатора доступа между ними, были сгруппированы вместе, компилятор был свободен для перегруппировки этих групп (но все же должен был сохранить первый в начале).
Это было хорошо, пока какой-нибудь рывок (то есть я) не указал, что способ написания правил имел еще одну небольшую проблему. Если бы я написал код вроде:
struct A {
int a;
public:
int b;
public:
int c;
public:
int d;
};
... у вас получилось немного самоуничтожения. С одной стороны, это была официально структура POD, поэтому правила C-like должны были применяться, но поскольку у вас были (по общему признанию, бессмысленные) спецификаторы доступа между членами, это также давало компилятору разрешение на переупорядочение членов, таким образом нарушая правила C, подобные им.
Чтобы исправить это, они немного переформулировали стандарт, чтобы он говорил о членах, имеющих одинаковый доступ, а не о том, существует ли между ними спецификатор доступа. Да, они могли бы просто постановили, что правила будут применяться только к публичным членам, но, похоже, никто не видел ничего, что можно было бы извлечь из этого. Учитывая, что это модифицировало существующий стандарт с большим количеством кода, который использовался в течение довольно долгого времени, они выбрали наименьшее изменение, которое они могли бы сделать, что все равно вылечило бы проблему.
В C++, в тот момент, когда вы используете подобные ролики, вы сказали компилятору, что вы не заботитесь о его типе безопасности и проверках. Это не безопасность сети; компилятор позволит вам испортить ваши собственные вещи, если вы настаиваете, как и ваш код. – tenfour
@tenfour Да, я понимаю, что я был немного удивлен, что это возможно. Я изменил C-cast на static_cast, а затем компилятор действительно жаловался. – mathematician1975
вы действительно не должны использовать C-cast в C++. В основном они говорят, что компилятор «уходит, я знаю, что я делаю, и я беру на себя всю ответственность». Они еще хуже, чем reinterpret_cast (что также должно было сработать кстати. Static_cast не будет работать, потому что нет четко определенного способа делать то, что вы просите) –