Ассемблер, C и C++ - это всё линейка языков, позволяющих выжать максимум производительности из процессора. Почти все языковые фичи с идут минимальным overhead'ом, и так, чтобы можно было писать код с полным пониманием, какие переменные и структуры данных влезут в cache lines процессора, и т.п.
Традиционно эффективнее всего было писать на ассемблере, потому что на нём можно делать всякие трюки, до которых компилятор сей не догадается. Зато на C можно думать модульно и писать на чуть более высоком уровне, компактнее (циклы, а не условные переходы вверх, многомерные массивы, а не сложное вычисление индекса в одномерном и т.п.). Но когда мы пишем a[i][j], мы, конечно, понимаем, что в памяти это представляется как одномерный массив, "a" это указатель на его начало, и a[i][j] это эквивалент a + i*N + j, где N это количество строк в объявлении массива (a[N][M]). Мало того, мы понимаем, что операция + с указателями, на самом деле инкрементирует указатель не на указанное число, а на количество байт, которые занимает тип, на который указатель указывает. Т.е. если у нас long a[N][M], то i*N + j это количество long-ов, а в байтах будет 4*(i*N + j).
Ещё один плюс языка C - его (как бы) кроссплатформенность. Именно потому что не нужно нигде hard-code это число 4, можно написать "int" и на какой-то архитектуре он будет 2-байтовый, а на какой-то 4-байтовый, а работать будет корректно и в одном, и в другом случае. (Просто в случае 2-байтового быстрее будет возникать переполнение). Но компилятор скомпилирует разный код (разный ассемблер) в зависимости от платформы. Где-то индексы будут умножаться на 2, а где-то на 4.
C++ это шаг дальше. Это попытка помочь упростить жизнь, когда используешь объектно-ориентированную парадигму. В принципе, ООП можно использовать и на C, просто придётся ручками передавать параметр "this" как ссылку на структуру во все функции, придётся явно обращаться к полям, разыменовывая this, придётся заводить таблицу виртуальных методов в виде массива указателей на фукнции. C++ даёт синтаксис, позволяющий перенести всю эту нудную работу на компилятор. Но тот, кто пишет на C++, прекрасно понимает, как оно будет скомпилировано, и как бы можно было то же самое написать на C. Просто будет громоздко.
Современный C++ (C++ 11/14) - это очередной революционный переход дальше по той же лестнице, в котором добавляется синтаксис для модной нынче функциональной парадигмы (и позволяющей ещё компактнее писать интересные алгоритмы и логику программы), при этом C++ сохраняет традицию генерировать только самый-пресамый прожиточный минимум кода (который ты явно написал бы сам, если бы всё то же самое имплементировал на C), и от некоторых sexy фич C++ отказывается, потому что они не позволяют писать код, оптимальный для процессора.
Кстати, нынешние компиляторы C++ оптимизируют лучше человека, и в большинстве случаев, написав своё на ассемблере, оно будет работать медленее, чем то, что сделает за тебя компилятор C++.
Короче, C и C++ это непростые языки программирования. За ними должно идти глубокое понимание архитектуры процессора и памяти, желание писать оптимальный для процессора код, необходимость писать этот код из-за CPU-bound задач (heavy computation, low latency, heavy real-time, etc). C++ позволяет программисту примирить все модные концепты и парадигмы, позволяющие разрабатывать софт быстро, и желание всё оптимизировать на ассемлерном уровне, чтобы оно ещё и быстро работало.
Тем не менее, если задача оптимизации процессора не стоит, то на Java можно писать примерно в 10 раз быстрее (по времени программиста), чем на C++, даже со всеми его современными приблудами, облегчающими жизнь.