Целью создания C++ было расширение возможностей Си, наиболее распространённого языка системного программирования. Ориентированный на ту же самую область применения, C++ унаследовал множество не самых лучших, с теоретической точки зрения, особенностей Си. Перечисленные выше принципы, которых придерживался автор языка, предопределили многие недостатки C++.
В области прикладного программирования альтернативой C++ стал его язык-потомок, Java. Несмотря на преемственность по отношению к C++, Java строилась на принципиально иной основе, её разработчики не были связаны требованиями совместимости с языком-предком и обеспечения максимально достижимой эффективности, благодаря чему они смогли кардинально переработать язык, отказаться от множества синтаксических средств, чтобы добиться идеологической целостности языка. Позже фирма Майкрософт предложила язык C#, представляющий собой ещё одну переработку C++ в том же направлении, что и Java. В дальнейшем появился язык Nemerle, в котором к средствам C# добавлены средства функционального программирования. Ещё позже появилась попытка объединения эффективности C++ с безопасностью и скоростью разработки Java и C# — был предложен язык D, который пока не получил широкого признания.
Java и C++ можно рассматривать как два языка-потомка Си, разработанных из различных соображений и пошедших, вследствие этого, по разным путям. В этой связи представляет интерес сравнение данных языков (всё, сказанное ниже про Java, можно с равным успехом отнести к языкам C# и Nemerle, поскольку в рассматриваемых деталях эти языки отличаются лишь внешне).
C++ сохраняет совместимость с C, насколько это возможно. Java сохраняет внешнее подобие C и C++, но, в действительности, сильно отличается от них — из языка удалено большое число синтаксических средств, объявленных необязательными. В результате программы на Java бывают более громоздки по сравнению с их аналогами на С++. С другой стороны, Java проще, что облегчает как изучение языка, так и создание трансляторов для него.
Java-код компилируются в промежуточный код, который в дальнейшем интерпретируется или компилируется, тогда как C++ изначально ориентирован на компиляцию в машинный код заданной платформы (хотя, теоретически, ничто не мешает создавать для C++ трансляторы в промежуточный код). Это уже определяет разницу в сферах применения языков: Java вряд ли может быть использована при написании таких специфических программ, как драйверы устройств или низкоуровневые системные утилиты. Механизм исполнения Java делает программы, даже откомпилированные (в байт-код) полностью переносимыми. Стандартное окружение и среда исполнения позволяют выполнять программы на Java на любой аппаратной платформе и в любой ОС, без каких-либо изменений, усилия по портированию программ минимальны (при соблюдении рекомендаций по созданию переносимых программ — и вовсе нулевые). Ценой переносимости становится потеря эффективности — работа среды исполнения приводит к дополнительным накладным расходам.
C++ позволяет использовать принцип «захват ресурсов путём инициализации» (RAII), при котором ресурсы ассоциированы с объектом и автоматически освобождаются при разрушении объекта (например, std::vector <T> и std::ifstream). Также возможен подход, когда программист, выделяя ресурсы (память под объекты, открытые файлы и т. п.), обязан явно позаботиться о своевременном их освобождении. Java работает в среде со сборкой мусора, которая автоматически отслеживает прекращение использования объектов и освобождает занимаемую ими память, если в этом есть необходимость, в некоторый неопределённый момент времени. Ручное управление предпочтительнее в системном программировании, где требуется полный контроль над ресурсами, RAII и сборка мусора удобнее в прикладном программировании, поскольку в значительной степени освобождают программиста от необходимости отслеживать момент прекращения использования ресурсов. Сборщик мусора Java требует системных ресурсов, что снижает эффективность выполнения программ, лишает программы на Java детерминированности выполнения и способен следить только за памятью. Файлы, каналы, сокеты, объекты графического интерфейса программист на Java всегда освобождает явно.
В Java есть чётко определённые стандарты на ввод-вывод, графику, геометрию, диалог, доступ к базам данных и прочим типовым приложениям. C++ в этом отношении гораздо более свободен. Стандарты на графику, доступ к базам данных и т. д. являются недостатком, если программист хочет определить свой собственный стандарт.
C++ сохраняет возможность работы с низкоуровневыми указателями. В Java указателей нет. Использование указателей часто является причиной труднообнаруживаемых ошибок, но необходимо для низкоуровневого программирования. В принципе, C++ обладает набором средств (конструкторы и деструкторы, стандартные шаблоны, ссылки), позволяющих почти полностью исключить выделение и освобождение памяти вручную и опасные операции с указателями. Однако такое исключение требует определённой культуры программирования, в то время как в языке Java оно реализуется автоматически.
В отличие от С++, Java является чисто объектно-ориентированным языком, без возможности процедурного программирования. Для объявления свободных функций или глобальных переменных в Java необходимо создавать фиктивные классы, содержащие только static члены . Для задания главной функции даже самой простой программы на Java необходимо поместить её в класс .
в C++ RTTI ограничена возможностью сравнивать типы объектов между собой и с буквальными значениями типов. В системе Java доступна более подробная информация о типах. Эту возможность можно было бы реализовать в C++, имея полную информацию о типах во время компиляции CTTI.
C++ использует препроцессор для включения определений функций и классов, для подключения библиотек, полностью выполненных в исходном коде, а также позволяет осуществлять метапрограммирование с использованием препроцессора, которое, в частности, решает сложные проблемы высокоуровневого дублирования кода[8]. Есть мнение, что этот механизм небезопасен, так как имена макросов препроцессора глобальны, а сами макросы почти никак не связаны с конструкциями языка. Это может приводить к сложным конфликтам имён. С другой точки зрения, C++ предоставляет достаточно средств (константы, шаблоны, встроенные функции) для того, чтобы практически полностью исключить использование препроцессора. Java исключила препроцессор полностью, избавившись разом от всех проблем с его использованием, потеряв при этом возможности метапрограммирования препроцессора и текстовых замен в коде средствами языка.
Отличия языков приводят к ожесточённым спорам между сторонниками двух языков о том, какой язык лучше. Споры эти во многом беспредметны, поскольку сторонники Java считают различия говорящими в пользу Java, а сторонники C++ полагают обратное. Некоторая аргументация устаревает со временем, например, упрёки в неэффективности Java из-за наличия среды исполнения, бывшие справедливыми в первой половине 1990-х годов, в результате лавинообразного роста производительности компьютеров и появления более эффективной техники исполнения (JIT) в значительной мере потеряли актуальность. C++, в свою очередь, развивался, и ряд его недостатков устранён в последних версиях стандарта (например, появился механизм частичной спецификации шаблонов).
Далеко не все программисты являются сторонниками одного из языков. По мнению большинства программистов, Java и C++ не являются конкурентами, потому что обладают различными областями применимости. Другие считают, что выбор языка для многих задач является вопросом личного вкуса.