Ответ 1
С++ не является C с классами!
И нет языка C/С++. Все идет вниз.
Каковы часто непонятые понятия в С++?
С++ не является C с классами!
И нет языка C/С++. Все идет вниз.
У С++ есть автоматическое управление ресурсами.
(Большинство людей, которые утверждают, что С++ не имеет управления памятью, пытаются слишком много использовать новые и удалять, не понимая, что, если они позволят С++ управлять самим ресурсом, задача становится намного проще).
Пример: (Сделано с составленным 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.
}
Свободные функции неплохие, потому что они не входят в класс. С++ не является языком ООП, но основывается на целом ряде методов.
Я слышал это много раз, когда люди говорят, что свободные функции (те, что находятся в пространствах имен и глобальном пространстве имен) являются "реликтовыми времен C", и их следует избегать. Совершенно верно. Свободные функции позволяют отделять функции от определенных классов и допускать повторное использование функциональных возможностей. Также рекомендуется использовать бесплатные функции вместо функций-членов, если функции не требуется доступ к деталям реализации, потому что это исключает каскадные изменения, когда один из них изменяет реализацию класса среди других преимуществ.
Это также отражается в языке: цикл, основанный на диапазоне для C++0x
(следующая версия С++, выпущенная очень скоро) будет основана на бесплатных вызовах функций. Он получит начальные/конечные итераторы, вызвав бесплатные функции begin
и end
.
Разница между назначением и инициализацией:
string s = "foo"; // initialisation
s = "bar"; // assignment
Инициализация всегда использует конструкторы, назначение всегда использует operator =
В порядке убывания:
Интересно, что многие люди не знают полной информации о виртуальных функциях, но все же, похоже, все в порядке с выполнением работы.
Самая пагубная концепция, которую я видел, заключается в том, что ее следует рассматривать как C с некоторыми аддонами. На самом деле, с современными С++-системами, его следует рассматривать как другой язык, и большая часть С++-bashing, которую я вижу, основана на модели "C с надстройками".
Чтобы указать на некоторые проблемы:
Хотя вам, вероятно, нужно знать разницу между delete
и delete[]
, вы, как правило, не должны писать. Используйте интеллектуальные указатели и std::vector<>
.
Фактически, вы должны использовать *
только редко. Используйте std::string для строк. (Да, это плохо спроектировано. Используйте его в любом случае.)
RAII означает, что вам обычно не нужно писать код очистки. Код очистки - это плохой стиль и разрушает концептуальную локальность. В качестве бонуса использование RAII (включая интеллектуальные указатели) дает вам массу базовых исключений бесплатно. В целом, это намного лучше, чем сбор мусора в некотором роде.
В общем, члены данных класса не должны быть непосредственно видимыми либо путем public
, либо с помощью геттеров и сеттеров. Существуют исключения (такие как x и y в точечном классе), но они являются исключениями и должны рассматриваться как таковые.
И большой: нет такого языка, как C/С++. Можно писать программы, которые могут быть скомпилированы надлежащим образом на любом языке, но такие программы не являются хорошими С++ и обычно не хороши C. Языки расходятся, поскольку Stroustrup начал работать над "C с классами" и теперь менее похож на Когда-либо. Использование "C/С++" в качестве имени языка является prima facie доказательством того, что пользователь не знает, о чем он или она говорит. С++, правильно используемый, больше не похож на C, чем на Java или С#.
Распространение наследования, не связанное с полиморфизмом. В большинстве случаев, если вы действительно не используете полиморфизм времени выполнения, состав или статический полиморфизм (т.е. Шаблоны) лучше.
Ключевое слово static, которое может означать одну из трех разных вещей в зависимости от того, где она используется.
Массивы не являются указателями
Они разные. Поэтому &array
не является указателем на указатель, а указателем на массив. По-моему, это самая непонятная концепция как на C, так и на С++. Вы должны посетить все те ответы SO, которые передают 2-мерные массивы как type**
!
Вот некоторые из них:
const
-ness против фактического const
-ness в памяти. Когда использовать ключевое слово mutable
.ПОДТВЕРЖДЕНИЕ: Спасибо за исправление моей ошибки, spoulson.
EDIT:
Вот еще:
Учитывая это:
int x = sizeof(char);
какое значение X?
Ответ, который вы часто слышите, зависит от уровня понимания спецификации.
Несчастливо, что стандарт использует "byte" для обозначения единицы памяти, поскольку многие программисты думают о байте как о восьми бит.
Вот важное понятие в С++, которое часто забывается:
С++ нельзя просто использовать как объект ориентированный язык, такой как Java или С#. Вдохните себя из STL и напишите общий код.
классический среди новичков до С++ от c:
путать delete
и delete[]
EDIT:
другой классический провал среди всех уровней опыта при использовании C API:
std::string helloString = "hello world";
printf("%s\n", helloString);
вместо:
printf("%s\n", helloString.c_str());
это случается со мной каждую неделю. Вы можете использовать потоки, но иногда вам приходится иметь дело с API-интерфейсами, подобными printf.
Указатели.
Разыменование указателей. Через .
или ->
Адрес использования &
для указания указателя.
Функции, которые принимают параметры по ссылке, задавая &
в сигнатуре.
Указатель на указатели на указатели ***
или указатели по ссылке void someFunc(int *& arg)
Есть несколько вещей, которые люди, кажется, постоянно путаются или не имеют представления о:
Указатели, особенно указатели на функции и несколько указателей (например, 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.
Встроенный ассемблер, как он обычно реализуется, не является частью С++.
С++ - это язык с несколькими парадигмами. Многие люди связывают С++ строго с ООП.
sizeof(void *) == sizeof(int)
(или любой другой тип, если только портативный заголовок специально не гарантирует его) в переносном коде.Заголовки и файлы реализации
Это также концепция, которую многие не поняли. Вопросы вроде того, что входит в заголовочные файлы и почему они вызывают ошибки ссылок, если определения функций появляются несколько раз в программе с одной стороны, но не тогда, когда определения классов появляются несколько раз с другой стороны.
Очень похоже на эти вопросы, поэтому важно иметь защитные элементы заголовков.
Если функция принимает указатель на указатель, void*
все равно сделает это
Я видел, что понятие указателя пустоты часто путается. Он считал, что если у вас есть указатель, вы используете void*
, и если у вас есть указатель на указатель, вы используете void**
. Но вы можете и должны в обоих случаях использовать void*
. A void**
не имеет специальных свойств, которые имеет a void*
.
Это специальное свойство, которому a void*
также может быть назначен указатель на указатель и при возврате исходного значения.
Я думаю, что самая непонятная концепция С++ - это то, почему она существует и какова ее цель. Его часто под огнем сверху (Java, С# и т.д.) И снизу (C). С++ имеет возможность работать рядом с машиной, чтобы справляться с вычислительной сложностью и механизмами абстракции для управления сложностью домена.
Выравнивание памяти.
NULL
всегда равен нулю.
Многие путают NULL
с адресом и считают, что он не обязательно равен нулю, если платформа имеет другой адрес нулевой указатель.
Но NULL
всегда равно нулю, и это не адрес. Это нулевое постоянное целочисленное выражение, которое может быть преобразовано в типы указателей.
Хе-хе, это глупый ответ: самая непонятная вещь в программировании на C++ - это сообщения об ошибках из g++, когда классы шаблонов не скомпилируются!
С++ не является C со строкой и вектором!
С++ не является типичным объектно-ориентированным языком.
Не верьте мне? посмотрите STL, больше шаблонов, чем объектов.
Практически невозможно использовать методы Java/С# для написания объектно-ориентированного кода; он просто не работает.
new
ing, множество объектов утилиты, которые реализуют некоторые единые связные функции.new
ed должен быть удален, но всегда существует проблема того, кто владеет объектомЕсли вы настаиваете на выполнении указаний с указателями, у вас обычно будут большие (гигантские!) классы с четко определенными отношениями между объектами, чтобы избежать утечек памяти. И тогда, даже если вы это сделаете, вы уже слишком далеко от идиомы Java/С# oop.
На самом деле я составил термин "объектно-ориентированный", и могу сказать, что у меня не было С++. - Алан Кей (щелкните ссылку, это видео, цитата находится в 10:33)
Хотя с точки зрения пуриста (например, Алана Кей) даже Java и С# не соответствуют истинным oop
Структуры C Структуры VS С++ часто неправильно понимаются.
std::vector
не создает элементы при использовании резерва
Я видел, что программисты утверждают, что они могут получить доступ к элементам на позициях, превышающих, чем size()
возвращает, если они reserve()
доведены до этих позиций. Это ошибочное предположение, но очень распространено среди программистов - особенно потому, что компилятору достаточно сложно диагностировать ошибку, которая заставит заставить вещи "работать".
Указатель - это итератор, но итератор не всегда является указателем
Это также неправильно понятая концепция. Указатель на объект - это итератор произвольного доступа: его можно увеличивать/уменьшать на произвольное количество элементов и читать и писать. Тем не менее, класс итератора, который выполняет перегрузку оператора, выполняет эти требования. Таким образом, он также является итератором, но, конечно, не является указателем.
Я помню, что один из моих прошлых учителей на С++ учил (ошибочно), что вы получаете указатель на элемент вектора, если вы делаете vec.begin()
. Он фактически предполагал - не зная, - что вектор реализует свои итераторы с помощью указателей.
Я все еще не понимаю, почему в векторе нет pop_front и тот факт, что я не могу сортировать (list.begin(), list.end()).