online compiler and debugger for c/c++

code. compile. run. debug. share.
Source Code   
Language
#include <stdio.h> #include <stdint.h> #include <inttypes.h> #include <stdlib.h> /** ООП через инкапсуляцию **/ /* Проверка на выделение памяти опущена умышленно */ /* Обратите внимание, что вы можете написать функции печати и ИНАЧЕ, * Имея функцию печати для *каждого* объекта не перетирая старую. * Это позволит перед выводом новых полей вывести старые, вызвав функцию * глубиной "ниже" * Например: * ~~~ * struct my_figure { * struct my_object object; * object_printer_t printer; // = _printer_figure * } * void _printer_figure(void * object) { * struct my_figure * figure = object; * // Вызываем принтер объекта, в котором печатаем имя и, например ptr * figure->object.printer(figure->object); * // Непосредственно новые данные фигуры * printf( * "Данные фигуры: %" PRIu32 ":%" PRIu32 "\n", * figure->coords.x, * figure->coords.y * ); * } * ~~~ * В объекте следующего уровня не нужно вызывать `figure->object.printer` * Достаточно вызвать принтер непосредственного родителя: * ~~~ * struct my_square * square = object; * square->figure.printer(square->figure); * <...> * ~~~ */ /* Также можно применить union, для того, чтобы при доступе к полям структуры * не перечислять всех родителей чтобы добраться до нужного поля: * ~~~ * union my_square { * struct my_object object; * struct my_figure figure; * struct { * uint32_t width; * } square; * } * * my_square->square.width; * my_square->figure.points; * my_square->object.name; * ~~~ * Это потребует перечислить все подлежащие объекты в объявлении (если, конечно, * вы не хотите скрыть часть из них) */ /* Также вместо приведения типа в каждом месте можно использовать функцию, * которая скроет от пользователя каст, что позволит иметь более чистый код * плюс позволит достаточно быстро изменить структуру наследования: * ~~~ * struct my_figure * _figure_get(void * ptr) { * return (struct my_figure *)ptr; * } * * struct my_figure * figure = _figure_get(square); * ~~~ * Вы можете добавить защиту от дурака при помощи typeof самостоятельно, * позволяя кастить только дозволенные объекты при условии, что тип объекта * известен compile-time */ /*! \brief Функция печати данных объекта. */ typedef void (* object_printer_t)(void * object); /* ## Первый уровень */ /*! \brief Объект-родитель */ struct my_object { object_printer_t printer; /**< Функция печати данных объекта */ const char * name; /**< Имя объекта */ }; /*! \brief Функция печати объекта. Обычно замещается другой * \param[in] object Объект `struct my_object *` */ static void _printer_object(void * object) { struct my_object * my_object = object; printf("Object: %s\n", my_object->name); } /*! \brief Конструктор объекта * \param[in] name Имя объекта * \return Объект */ static struct my_object * _create_object(const char * name) { struct my_object * object = malloc(sizeof(struct my_object)); object->printer = _printer_object; object->name = name; return object; } /*! \brief Деструктор объекта * \param[in] object Объект */ static void _destroy_object(struct my_object * object) { free(object); } /* ## Второй уровень */ /*! \brief Пример первого уровня - Фигура */ struct my_figure { struct my_object object; /**< Родительский объект */ uint32_t points; /**< Количество углов */ struct { /**< Координаты LT-угла */ uint32_t x; /**< Горизонтальная */ uint32_t y; /**< Вертикальная */ } coords; }; /*! \brief Функция печати фигуры. * \param[in] object Объект `struct my_figure *` */ static void _printer_figure(void * object) { struct my_object * my_object = object; struct my_figure * my_figure = object; printf( "Figure \"%s\": %" PRIu32 ":%" PRIu32 "\n", my_object->name, my_figure->coords.x, my_figure->coords.y ); } /*! \brief Конструктор фигуры * \param[in] name Имя фигуры * \param[in] points Количество углов фигуры * \param[in] x X-координата фигуры * \param[in] y Y-координата фигуры * \return Фигура */ static struct my_figure * _create_figure( const char * name, uint32_t points, uint32_t x, uint32_t y ) { // Создаем объект на 1 уровень ниже struct my_object * object = _create_object(name); object->printer = _printer_figure; // Создаем свойства текущего уровня struct my_figure * figure = realloc(object, sizeof(struct my_figure)); figure->points = points; figure->coords.x = x; figure->coords.y = y; return figure; } /*! \brief Деструктор фигура * \param[in] object Фигура */ static void _destroy_figure(struct my_figure * figure) { // Здесь мы должны вызвать деструкторы полей НАШЕГО объекта. // У нас их нет. Иначе мы могли бы вызвать например free(figure->string); // Вызываем деструктор родителя _destroy_object((struct my_object *)figure); } /* ## Третий уровень */ /*! \brief Пример третьего уровня - Квадрат */ struct my_square { struct my_figure figure; /**< Родительский объект */ uint32_t width; /**< Размер грани куба */ }; /*! \brief Функция печати фигуры. * \param[in] object Объект `struct my_figure *` */ static void _printer_square(void * object) { struct my_object * my_object = object; struct my_figure * my_figure = object; struct my_square * my_square = object; printf( "Square \"%s\": %" PRIu32 ":%" PRIu32 ", with a side of %" PRIu32 "\n", my_object->name, my_figure->coords.x, my_figure->coords.y, my_square->width ); } /*! \brief Конструктор квадрата * \param[in] name Имя квадрата * \param[in] width Ширина квадрата * \param[in] x X-координата квадрата * \param[in] y Y-координата квадрата * \return Квадрат */ static struct my_square * _create_square( const char * name, uint32_t width, uint32_t x, uint32_t y ) { static const uint32_t square_points = 4; // Создаем объект на 1 уровень ниже struct my_figure * figure = _create_figure(name, square_points, x, y); // Нам всё еще нужен объект для переписываения принтера. // См. одно из примечаний для того чтобы сделать иначе. struct my_object * object = (struct my_object *)figure; object->printer = _printer_square; // Создаем свойства текущего уровня struct my_square * square = realloc(figure, sizeof(struct my_square)); square->width = width; return square; } /*! \brief Деструктор квадрата * \param[in] object Объект */ static void _destroy_square(struct my_square * square) { // Здесь мы должны вызвать деструкторы полей НАШЕГО объекта. // У нас их нет. Иначе мы могли бы вызвать например free(square->alloced); // Вызываем деструктор родителя // См. одно из примечаний для того, чтобы не использовать каст _destroy_figure((struct my_figure *)square); } int main() { struct my_object * object = _create_object("Just an object"); struct my_figure * figure = _create_figure("Figure", 5, 21, 34); struct my_square * square = _create_square("Square", 50, 1, 2); // Вы можете не использовать всю цепочку, если будете использовать union // как в одном из примечаний. object->printer(object); figure->object.printer(figure); square->figure.object.printer(square); // Мы также можем использовать принтер в функции, которая принимает // более неглубокую версию объекта: struct my_object * casted_object = (struct my_object *)square; casted_object->printer(casted_object); // Мы всё равно получим вывод исходного объекта // Ну и также мы можем использовать принтер более низкого уроня на более // высокий объект: figure->object.printer(square); _destroy_square(square); _destroy_figure(figure); _destroy_object(object); return 0; }

Compiling Program...

Command line arguments:
Standard Input: Interactive Console Text
×

                

                

Program is not being debugged. Click "Debug" button to start program in debug mode.

#FunctionFile:Line
VariableValue
RegisterValue
ExpressionValue