Экстремальный C
Экстремальный Cи. Параллелизм, ООП и продвинутые возможности [2021] Амини Камран
BEST OF THE BEST
Читал эту книгу, когда устроился в Huawei на C-программиста. Книга — одна из лучших, если нужно глубже разобраться в C и понять процесс сборки и линковки. Мне понравился детальный разбор, как исходный код превращается в исполняемый файл. Затронуты объектные файлы (.o), статические библиотеки (.a) и динамические библиотеки (.so). Никогда раньше не встречал такого подробного объяснения.
Автор показывает, как реализовать основы ООП на C:
- Инкапсуляция: Здесь мы учимся создавать собственные конструкторы, деструкторы и методы “классов”.
- Композиция и агрегация: Объясняется, как создавать классы, которые владеют или используют другие классы.
- Наследование: Автор сводит наследование к композиции и предлагает два варианта реализации. Также приводится пример, как реализовать множественное наследование.
- Полиморфизм: Классная часть, где показывается, как своими руками создать таблицу виртуальных функций.
В книге представлены основы UNIX/Linux: системные вызовы, ядро, процессы, синхронизация и многопоточность. Заканчивается книга обзором вспомогательного ПО: фреймворки для тестирования, системы сборки, отладка.
Приведу пример кода с “ООП” на С. Создадим кошку, которая зверь. Все звери умеют издавать звук и знают свое имя.
animal_private.h - связующий заголовок для базового класса и наследников. В нем лежит наш виртуальный метод “звук”
typedef void (*MakeSound_t)();
typedef struct Animal{
char* name;
MakeSound_t makeSound;
} Animal_t;
animal.h - интерфейс зверя
struct Animal;
struct Animal* AnimalNew();
void AnimalCtor(struct Animal* obj, const char* name);
void AnimalDtor(struct Animal* obj);
void AnimalMakeSound(struct Animal* obj);
const char* AnimalGetName(struct Animal* obj);
animal.c - пишем конструкторы, деструкторы и методы: звук, имя. Методы будут иметь реализацию по умолчанию
#include "animal_private.h"
Animal_t* AnimalNew() {
return malloc(sizeof(Animal_t));
}
static void MakeSound() {
printf("No sound\n");
}
void AnimalCtor(Animal_t* obj, const char* name) {
obj->name = malloc(strlen(name) + 1);
strcpy(obj->name, name);
obj->makeSound = MakeSound;
}
void AnimalDtor(Animal_t* obj) {
if (obj) {
free(obj->name);
}
}
void AnimalMakeSound(Animal_t* obj) {
obj->makeSound();
}
const char* AnimalGetName(Animal_t* obj) {
return obj->name;
}
cat.h - интерфейс кошки. В нем нет мяуканья и имени, потому что оно есть у зверя уже
struct Cat;
struct Cat* CatNew();
void CatCtor(struct Cat* obj, const char* name);
void CatDtor(struct Cat* obj);
int CatLivesLeft(struct Cat* obj);
cat.c - реализуем свои методы и переопределяем только звук
#include "animal_private.h"
#include "animal.h"
typedef struct {
Animal_t base;
int lives;
} Cat;
static void MakeSoundCat() {
printf("Meow\n");
}
struct Cat* CatNew() {
return malloc(sizeof(Cat));
}
void CatCtor(Cat* obj, const char* name){
AnimalCtor((Animal_t*)obj, name);
obj->lives = 9;
obj->base.makeSound = MakeSoundCat;
}
void CatDtor(Cat* obj){
AnimalDtor((Animal_t*)obj);
}
int CatLivesLeft(Cat* obj) {
return obj->lives;
}
main.c
#include "animal.h"
#include "cat.h"
int main(int argc, char** argv) {
struct Animal* animal = AnimalNew();
AnimalCtor(animal, "Unknown");
printf("Name: %s\n", AnimalGetName(animal)); // Name Unknown
AnimalMakeSound(animal); // No sound
AnimalDtor(animal);
free(animal);
struct Cat* cat = CatNew();
CatCtor(cat, "Circle");
printf("Name: %s\n", AnimalGetName((struct Animal*)cat)); // Name Circle
AnimalMakeSound((struct Animal*)cat); // Meow
printf("Cat have %d lives\n", CatLivesLeft(cat)); // Cat have 9 lives
CatDtor(cat);
free(cat);
return 0;
}