Указатель на адрес члена данных

Я прочитал (внутри объектной модели C ++), что адрес указателя на элемент данных в C ++ является смещением элемента данных плюс 1?
Я пытаюсь это на VC ++ 2005, но я не получаю точные значения смещения.
Например:

Class X{  
  public:  
    int a;  
    int b;  
    int c;
}

void x(){  
  printf("Offsets of a=%d, b=%d, c=%d",&X::a,&X::b,&X::c);
}  

должен печатать смещения a = 1, b = 5, c = 9. Но в VC ++ 2005 это будет a = 0, b = 4, c = 8.
Я не могу понять это поведение.
Отрывок из книги:

«Это ожидание, однако, опровергается одним - несколько традиционная ошибка для программистов как на C, так и на C ++.

Физическое смещение трех координатных членов в классе расположение соответственно 0, 4 и 8, если vptr размещен в конец или 4, 8 и 12, если vptr находится в начале учебный класс. Значение, возвращаемое от взятия адреса участника, однако, всегда увеличивается на 1. Таким образом, фактические значения 1, 5 и 9, и скоро. Проблема заключается в различении указателя на отсутствие данных член и указатель на первый член данных. Рассмотрим для примера:

 float Point3d :: * p1 = 0;
float Point3d :: * p2 = & Point3d :: x; 

// упс: как отличить? 
if (p1 == p2) { 
 cout << "p1 & p2 содержат одинаковое значение -"; 
cout << "они должны обратиться к одному и тому же участнику!" << endl;
}

Чтобы различать p1 и p2, каждое фактическое значение смещения элемента увеличено на 1. Следовательно, и компилятор (и пользователь) должны помнить Есть ли версия в духе C ++?

14
задан einpoklum - reinstate Monica 12 April 2014 в 06:55
поделиться

9 ответов

Я постоянно вспоминаю о том, что, когда вы разрешаете сложные типы, возникает риск возникновения исключений в конструкторе типа. И, поскольку язык в настоящее время разработан, нет абсолютно никакого способа отловить такое исключение. Если бы было решено, что такие исключения следует перехватывать, тогда это потребовало бы значительно большей работы как для комитета, так и для авторов компилятора, что сделало бы все это несколько более проблематичным, чем просто сказать «разрешить std :: vector > ".

Могут быть и другие проблемы. Вся «несовместимость со средой выполнения» кажется мне отвлекающим маневром, учитывая, что теперь вы можете обеспечить практически ту же функциональность с помощью макросов. Но что-то вроде этого гораздо сложнее.

4
ответ дан 1 December 2019 в 06:47
поделиться

Как и @jalf, я иногда ловлю себя на том, что пишу

int main(int argc, char** argv) {
    std::vector<std::string> args(argv, argv+argc);

Но да, как все сказали, main должен быть C-совместимым. Я рассматриваю его как интерфейс для среды выполнения ОС, которая (по крайней мере, в тех системах, которые я использую) написана на C.

Хотя некоторые среды разработки поощряют замены, такие как wmain или _tmain . Вы можете написать свой собственный компилятор / IDE, который будет поощрять использование int vmain (const std :: vector & args) .

4
ответ дан 1 December 2019 в 06:47
поделиться

В основном, чтобы оставаться совместимыми с C. Если бы мы отказались от этого, main () переместилась бы в класс.

2
ответ дан 1 December 2019 в 06:47
поделиться

Есть еще одна причина, кроме совместимости с C. В C++, стандартная библиотека должна быть полностью необязательной. В самом языке C++ нет ничего, что заставляло бы вас использовать такие вещи из стандартной библиотеки, как std::string и std::vector, и это совершенно случайно. На самом деле, по замыслу, вы должны иметь возможность использовать некоторые части стандартной библиотеки без необходимости использовать другие (хотя это и привело к таким раздражающим вещам, как std::ifstream и std::ofstream, работающие со строками const char* в стиле C, а не с объектами std::string).

Теория заключается в том, что вы должны иметь возможность взять язык C++ и использовать любую библиотеку объектов, контейнеров и т.д., которую вы хотите, будь то стандартная библиотека или какая-то собственная библиотека (например, Qt, MFC), или что-то, что вы создали сами. Определение main для приема аргумента, состоящего из типов, определенных в стандартной библиотеке, противоречит этой цели проектирования.

10
ответ дан 1 December 2019 в 06:47
поделиться

Потому что это заставит вас включить <вектор> и <строка> .

5
ответ дан 1 December 2019 в 06:47
поделиться

Я попытаюсь объяснить в лучшем из возможных предложений.

C++ был разработан для обратной совместимости с C, и std::vector был включен в библиотеку, которая появилась только в C++.

Кроме того, программы на C++ и C были разработаны для запуска в оболочках или командных строках (windows, linux, mac), а ОС передают аргументы программе в виде массива String. Как бы ОС действительно переводила векторы?

Это самая большая причина, которую я могу придумать, не стесняйтесь критиковать ее.

1
ответ дан 1 December 2019 в 06:47
поделиться

Потому что C++ существовал задолго до появления стандарта C++ и в значительной степени основывался на C. И, как и в оригинальном стандарте ANSI C, кодификация существующей практики была его важной частью.

Нет смысла менять то, что работает, особенно если это приведет к поломке целого ряда существующих кодов.

Даже ISO C, который прошел через множество итераций, все еще относится к обратной совместимости очень серьезно.

3
ответ дан 1 December 2019 в 06:47
поделиться

Множественные определения main () на самом деле не являются множественными определениями. Их три:

  • int main (void) (C99)
  • int main (int argc, char * argv []) (C99)
  • int main (int argc, char * argv [], char * envp []) (POSIX, я думаю)

Но в POSIX вы только действительно получаете третий. Тот факт, что вы можете вызывать функцию с дополнительными аргументами, зависит от соглашения о вызовах C.

Вы не можете иметь extern "C" int main (std :: vector argv) , если только макет памяти не окажется магически совместимым в портативный способ. Среда выполнения вызовет main () с неправильными аргументами и завершится ошибкой. Нет простого способа обойти это.

Вместо этого, при условии, что main () не extern «C» , среда выполнения может пробовать различные поддерживаемые символы по порядку, пока не найдет один. Я полагаю, что main () - это extern «C» по умолчанию, и что вы не можете перегружать функции extern «C» .

Для большего удовольствия void main (void) .

2
ответ дан 1 December 2019 в 06:47
поделиться

Потому что C++ был разработан для (почти) обратной совместимости с кодом на C.

Есть случаи, когда код на Си будет ломаться в компиляторе Си++, но они довольно редки, и обычно есть веская причина, почему эта поломка необходима.

Но изменение сигнатуры main, хотя и удобно для нас, не является необходимым. Для кого-то, портирующего код с C, это будет просто еще одна вещь, которую придется изменить, без особого выигрыша.

Другая причина в том, что std::vector - это библиотека, а не часть основного языка. И поэтому вам придется #include в каждой программе на C++.

И конечно, в первые годы своего существования C++ не имел вектора. Поэтому, когда вектор был добавлен в язык, конечно, они могли изменить сигнатуру main, но тогда они сломали бы не только код на C, но и каждую существующую программу на C++.

Стоит ли оно того?

11
ответ дан 1 December 2019 в 06:47
поделиться
Другие вопросы по тегам:

Похожие вопросы: