Ядро линукс, драйверы, даже некоторые части игр (например рендер) — это системное программирование, оно отличается от прикладного. Для прикладного программирования придуманы кучи патернов, чтобы огромная армия программистов не отстреливала себе ноги. В системном свои правила, и основное — выжать максимум. Выжимается максимум явно нарушая правила прикладного программирования. Вот для обычных программистов то что в этой статье это ненормальное программирование. Для системого программирования это нормально!
Собственно это я и хотел выразить своим предыдущим посланием.
Я это послание понял, но разве сейчас используется C в «прикладном» программировании, где не важна скорость, тем более людьми, не знающими о возможности выстрелить во все части тела?
Почему нет? Я под линуксом пишу для GTK именно на нем. Конечно не глобальные проекты, от 500 до 4000 строк. Но лично для себя не вижу пока необходимости перелазить на что-то другое.
В исходниках Quake2 подобных виртуальных функций было полно. В общем-то в C++ обычно делается отдельно таблица функций, а в объекте хранится только указатель на таблицу для экономии памяти.
О glib и linux уже сказали.
В Go наследование тоже аналогичным образом делается.
А всё потому, что ООП — это, прежде всего, не синтаксический сахар, а парадигма. Почти на любом языке можно писать и в объектно-ориентированном стиле, и в функциональном, и в процедурном. Неудивительно, что элементы ООП встречаются во многих крупных проектах даже на тех языках, в которых нет специальных средств для ООП.
Вы забыли «virtual» в самом первом примере кода на C++, — все три метода класса compressor должны быть виртуальными, иначе это не будет работать как вы написали.
Вот очень интересная дискуссия на тему того, почему код написанный на D может быть более эффективным чем код скомпилированный на чистом С forum.dlang.org/thread/l7tij3$v6m$1@digitalmars.com
Хабр криво парсит ссылку, так, что лучше ее копировать в адресную строку.
1. указатели на функции можно было бы завернуть в табличку виртуальных функций, чтобы было как на си++. Либо сделать как в Go/Rust и создавать интерфейсы с указателем на данные + указателем на табличку виртуальных функций.
2. не понял зачем union в наследовании «a pointer to a structure is automatically converted to a pointer to an anonymous field for assignments and function calls» gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html
Union затем, чтобы можно было обращаться к базовому объекту по имени для передачи в код, ожидающий объект базового типа, т.е. для полиморфного использования в существующем коде и также чтобы возможно использовать данные базового объекта напрямую. В статье об этом есть.
Да, вы правы, похоже сейчас это стало возможным без `union`, по крайней мере компилируется, работоспособность не проверял. Только компилировать нужно с другим флагом: `-fplan9-extensions`. Спасибо.
Список «что я хочу от Си» можно дополнить возможностью перегружать обычные функции. В Си этого нет, к сожалению. Нельзя давать функциям одинаковые имена. Код int add2(int ar) { return ar+2;};
float add2(float ar) { return ar+2.0;};
не компилируется компиляторами чистого Си, например TinyCC. Можно писать без классов и шаблонов и думать, что они пишешь на чистом Си. И компиляторы C++ поддерживают в этом заблуждении. Когда же берёшь шустрый в компиляции TinyCC, то тут открываются глаза.
Из компиляторов Си вроде бы только LCC поддерживает перегрузку функций. Но это расширение, не соответствующее стандарту.
Думаю, перегрузки никогда не будет в C, т.к. это требует манглинга имён, что автоматически ломает обратную совместимость и прозрачность работы компилятора и линковщика. К примеру, неясно будет, что нужно передавать в dlsym.
Object oriented C