Каковы часто непонятые понятия в С++?
Каковы часто неправильно понимаемые концепции на С++?
Ответ 1
С++ не является C с классами!
И нет языка C/С++. Все идет вниз.
Ответ 2
У С++ есть автоматическое управление ресурсами.
(Большинство людей, которые утверждают, что С++ не имеет управления памятью, пытаются слишком много использовать новые и удалять, не понимая, что, если они позволят С++ управлять самим ресурсом, задача становится намного проще).
Пример: (Сделано с составленным API, потому что у меня нет времени проверить документы сейчас)
// C++
void DoSomething()
{
File file("/tmp/dosomething", "rb");
... do stuff with file...
// file is automatically free'ed and closed.
}
// C#
public void DoSomething()
{
File file = new File("/tmp/dosomething", "rb");
... do stuff with file...
// file is NOT automatically closed.
// What if the caller calls DoSomething() in a tight loop?
// C# requires you to be aware of the implementation of the File class
// and forces you to accommodate, thus voiding implementation-hiding
// principles.
// Approaches may include:
// 1) Utilizing the IDisposable pattern.
// 2) Utilizing try-finally guards, which quickly gets messy.
// 3) The nagging doubt that you've forgotten something /somewhere/ in your
// 1 million loc project.
// 4) The realization that point #3 can not be fixed by fixing the File
// class.
}
Ответ 3
Свободные функции неплохие, потому что они не входят в класс. С++ не является языком ООП, но основывается на целом ряде методов.
Я слышал это много раз, когда люди говорят, что свободные функции (те, что находятся в пространствах имен и глобальном пространстве имен) являются "реликтовыми времен C", и их следует избегать. Совершенно верно. Свободные функции позволяют отделять функции от определенных классов и допускать повторное использование функциональных возможностей. Также рекомендуется использовать бесплатные функции вместо функций-членов, если функции не требуется доступ к деталям реализации, потому что это исключает каскадные изменения, когда один из них изменяет реализацию класса среди других преимуществ.
Это также отражается в языке: цикл, основанный на диапазоне для C++0x
(следующая версия С++, выпущенная очень скоро) будет основана на бесплатных вызовах функций. Он получит начальные/конечные итераторы, вызвав бесплатные функции begin
и end
.
Ответ 4
Разница между назначением и инициализацией:
string s = "foo"; // initialisation
s = "bar"; // assignment
Инициализация всегда использует конструкторы, назначение всегда использует operator =
Ответ 5
В порядке убывания:
- обязательно отпустите указатели на выделенную память
- когда деструкторы должны быть виртуальными
- как работают виртуальные функции.
Интересно, что многие люди не знают полной информации о виртуальных функциях, но все же, похоже, все в порядке с выполнением работы.
Ответ 6
Самая пагубная концепция, которую я видел, заключается в том, что ее следует рассматривать как C с некоторыми аддонами. На самом деле, с современными С++-системами, его следует рассматривать как другой язык, и большая часть С++-bashing, которую я вижу, основана на модели "C с надстройками".
Чтобы указать на некоторые проблемы:
Хотя вам, вероятно, нужно знать разницу между delete
и delete[]
, вы, как правило, не должны писать. Используйте интеллектуальные указатели и std::vector<>
.
Фактически, вы должны использовать *
только редко. Используйте std::string для строк. (Да, это плохо спроектировано. Используйте его в любом случае.)
RAII означает, что вам обычно не нужно писать код очистки. Код очистки - это плохой стиль и разрушает концептуальную локальность. В качестве бонуса использование RAII (включая интеллектуальные указатели) дает вам массу базовых исключений бесплатно. В целом, это намного лучше, чем сбор мусора в некотором роде.
В общем, члены данных класса не должны быть непосредственно видимыми либо путем public
, либо с помощью геттеров и сеттеров. Существуют исключения (такие как x и y в точечном классе), но они являются исключениями и должны рассматриваться как таковые.
И большой: нет такого языка, как C/С++. Можно писать программы, которые могут быть скомпилированы надлежащим образом на любом языке, но такие программы не являются хорошими С++ и обычно не хороши C. Языки расходятся, поскольку Stroustrup начал работать над "C с классами" и теперь менее похож на Когда-либо. Использование "C/С++" в качестве имени языка является prima facie доказательством того, что пользователь не знает, о чем он или она говорит. С++, правильно используемый, больше не похож на C, чем на Java или С#.
Ответ 7
Распространение наследования, не связанное с полиморфизмом. В большинстве случаев, если вы действительно не используете полиморфизм времени выполнения, состав или статический полиморфизм (т.е. Шаблоны) лучше.
Ответ 8
Ключевое слово static, которое может означать одну из трех разных вещей в зависимости от того, где она используется.
- Это может быть статическая функция-член или переменная-член.
- Это может быть статическая переменная или функция, объявленная в области пространства имен.
- Это может быть статическая переменная, объявленная внутри функции.
Ответ 9
Массивы не являются указателями
Они разные. Поэтому &array
не является указателем на указатель, а указателем на массив. По-моему, это самая непонятная концепция как на C, так и на С++. Вы должны посетить все те ответы SO, которые передают 2-мерные массивы как type**
!
Ответ 10
Вот некоторые из них:
- Использование шаблонов для реализации полиморфизма без vtables, à la ATL.
- Логическое
const
-ness против фактическогоconst
-ness в памяти. Когда использовать ключевое словоmutable
.
ПОДТВЕРЖДЕНИЕ: Спасибо за исправление моей ошибки, spoulson.
EDIT:
Вот еще:
- Виртуальное наследование (а не виртуальные методы): На самом деле, я этого не понимаю! (я имею в виду, что я не знаю, как это реализовано)
- Союзы, чьи члены являются объектами, соответствующие классы которых имеют нетривиальные конструкторы.
Ответ 11
Учитывая это:
int x = sizeof(char);
какое значение X?
Ответ, который вы часто слышите, зависит от уровня понимания спецификации.
- Beginner - x является одним, потому что символы всегда имеют восемь бит.
- Промежуточное - это зависит от реализации компилятора, символы могут быть в формате UTF16.
- Expert - x является одним и всегда будет одним, так как char является наименьшей адресуемой единицей памяти, а sizeof определяет количество единиц памяти, необходимых для хранения экземпляра типа. Таким образом, в системе, где char - восемь бит, 32-битное значение будет иметь размер 4; но в системе, где char - 16 бит, 32-битное значение будет иметь размер 2.
Несчастливо, что стандарт использует "byte" для обозначения единицы памяти, поскольку многие программисты думают о байте как о восьми бит.
Ответ 12
Вот важное понятие в С++, которое часто забывается:
С++ нельзя просто использовать как объект ориентированный язык, такой как Java или С#. Вдохните себя из STL и напишите общий код.
Ответ 13
классический среди новичков до С++ от c:
путать delete
и delete[]
EDIT:
другой классический провал среди всех уровней опыта при использовании C API:
std::string helloString = "hello world";
printf("%s\n", helloString);
вместо:
printf("%s\n", helloString.c_str());
это случается со мной каждую неделю. Вы можете использовать потоки, но иногда вам приходится иметь дело с API-интерфейсами, подобными printf.
Ответ 14
Указатели.
Разыменование указателей. Через .
или ->
Адрес использования &
для указания указателя.
Функции, которые принимают параметры по ссылке, задавая &
в сигнатуре.
Указатель на указатели на указатели ***
или указатели по ссылке void someFunc(int *& arg)
Ответ 15
Есть несколько вещей, которые люди, кажется, постоянно путаются или не имеют представления о:
-
Указатели, особенно указатели на функции и несколько указателей (например, int (*) (void *), void ***)
-
Ключевое слово const и константная корректность (например, какая разница между константой const char *, char * const и const char * const, и что делает void class:: member() const; значит?)
-
Распределение памяти (например, каждый указатель new'ed должен быть удален, malloc/free не следует смешивать с новым/удалять, когда использовать delete [] вместо delete, почему функции C по-прежнему полезны (например, expand(), realloc()))
-
Область (т.е. вы можете использовать {} самостоятельно, чтобы создать новую область для имен переменных, а не только как часть if, для и т.д.)
-
Вывод операторов. (например, не понимая, что они могут также оптимизировать (или лучше в некоторых случаях), чем цепочки ifs, не понимая провалиться и его практические приложения (например, для развертывания цикла) или что есть случай по умолчанию)
-
Вызывающие соглашения (например, какая разница между cdecl и stdcall, как реализовать функцию pascal, почему это даже имеет значение?)
-
Наследование и множественное наследование и, в более общем смысле, вся парадигма OO.
-
Встроенный ассемблер, как он обычно реализуется, не является частью С++.
Ответ 16
С++ - это язык с несколькими парадигмами. Многие люди связывают С++ строго с ООП.
Ответ 17
- Указатели на элементы и указатели на функции-члены.
- Параметры шаблона непигового типа.
- Множественное наследование, в частности виртуальные базовые классы и общие базовые объекты.
- Порядок построения и уничтожения, состояние виртуальных функций в середине построения промежуточного базового класса.
- Безопасность и переменные размеры. Нет, вы не можете предположить, что
sizeof(void *) == sizeof(int)
(или любой другой тип, если только портативный заголовок специально не гарантирует его) в переносном коде. - Арифметика указателя.
Ответ 18
Заголовки и файлы реализации
Это также концепция, которую многие не поняли. Вопросы вроде того, что входит в заголовочные файлы и почему они вызывают ошибки ссылок, если определения функций появляются несколько раз в программе с одной стороны, но не тогда, когда определения классов появляются несколько раз с другой стороны.
Очень похоже на эти вопросы, поэтому важно иметь защитные элементы заголовков.
Ответ 19
Если функция принимает указатель на указатель, void*
все равно сделает это
Я видел, что понятие указателя пустоты часто путается. Он считал, что если у вас есть указатель, вы используете void*
, и если у вас есть указатель на указатель, вы используете void**
. Но вы можете и должны в обоих случаях использовать void*
. A void**
не имеет специальных свойств, которые имеет a void*
.
Это специальное свойство, которому a void*
также может быть назначен указатель на указатель и при возврате исходного значения.
Ответ 20
Я думаю, что самая непонятная концепция С++ - это то, почему она существует и какова ее цель. Его часто под огнем сверху (Java, С# и т.д.) И снизу (C). С++ имеет возможность работать рядом с машиной, чтобы справляться с вычислительной сложностью и механизмами абстракции для управления сложностью домена.
Ответ 21
Выравнивание памяти.
Ответ 22
NULL
всегда равен нулю.
Многие путают NULL
с адресом и считают, что он не обязательно равен нулю, если платформа имеет другой адрес нулевой указатель.
Но NULL
всегда равно нулю, и это не адрес. Это нулевое постоянное целочисленное выражение, которое может быть преобразовано в типы указателей.
Ответ 23
Хе-хе, это глупый ответ: самая непонятная вещь в программировании на C++ - это сообщения об ошибках из g++, когда классы шаблонов не скомпилируются!
Ответ 24
С++ не является C со строкой и вектором!
Ответ 25
С++ не является типичным объектно-ориентированным языком.
Не верьте мне? посмотрите STL, больше шаблонов, чем объектов.
Практически невозможно использовать методы Java/С# для написания объектно-ориентированного кода; он просто не работает.
- В программировании на Java/С# имеется много
new
ing, множество объектов утилиты, которые реализуют некоторые единые связные функции. - В С++ любой объект
new
ed должен быть удален, но всегда существует проблема того, кто владеет объектом - В результате объекты, как правило, создаются в стеке
- Но когда вы это делаете, вам приходится копировать их все время, если вы собираетесь передавать их другим функциям/объектам, таким образом тратя много работы, которая, как говорят, достигается с неуправляемой средой С++
- Понимая это, вам нужно подумать о других способах организации вашего кода.
- Вы можете в конечном итоге сделать что-то процедурным способом или использовать метапрограммирующие идиомы, такие как умные указатели.
- На этом этапе вы поняли, что OO в С++ нельзя использовать так же, как и в Java/С#
Если вы настаиваете на выполнении указаний с указателями, у вас обычно будут большие (гигантские!) классы с четко определенными отношениями между объектами, чтобы избежать утечек памяти. И тогда, даже если вы это сделаете, вы уже слишком далеко от идиомы Java/С# oop.
На самом деле я составил термин "объектно-ориентированный", и могу сказать, что у меня не было С++. - Алан Кей (щелкните ссылку, это видео, цитата находится в 10:33)
Хотя с точки зрения пуриста (например, Алана Кей) даже Java и С# не соответствуют истинным oop
Ответ 26
Структуры C Структуры VS С++ часто неправильно понимаются.
Ответ 27
std::vector
не создает элементы при использовании резерва
Я видел, что программисты утверждают, что они могут получить доступ к элементам на позициях, превышающих, чем size()
возвращает, если они reserve()
доведены до этих позиций. Это ошибочное предположение, но очень распространено среди программистов - особенно потому, что компилятору достаточно сложно диагностировать ошибку, которая заставит заставить вещи "работать".
Ответ 28
Указатель - это итератор, но итератор не всегда является указателем
Это также неправильно понятая концепция. Указатель на объект - это итератор произвольного доступа: его можно увеличивать/уменьшать на произвольное количество элементов и читать и писать. Тем не менее, класс итератора, который выполняет перегрузку оператора, выполняет эти требования. Таким образом, он также является итератором, но, конечно, не является указателем.
Я помню, что один из моих прошлых учителей на С++ учил (ошибочно), что вы получаете указатель на элемент вектора, если вы делаете vec.begin()
. Он фактически предполагал - не зная, - что вектор реализует свои итераторы с помощью указателей.
Ответ 29
- Это анонимные пространства имен почти всегда то, что действительно нужно, когда люди создают статические переменные в С++
- При создании файлов заголовков библиотеки, идиома pimpl (http://www.gotw.ca/gotw/024.htm) должна использоваться почти для всех частных функций и членов для помощи в управление зависимостями
Ответ 30
Я все еще не понимаю, почему в векторе нет pop_front и тот факт, что я не могу сортировать (list.begin(), list.end()).