Как стать автором
Обновить

Комментарии 29

НЛО прилетело и опубликовало эту надпись здесь

А еще он не сможет создать этот StringBuilder на стеке

Точно так же как и плюсовый объект, для которого есть только ISomething и фабрика. Автор же не утверждает, что C круче - просто то, что в нём легко реализуется обычная схема инкапсуляции.

А что мешает создать конструктор, который возвращает StringBuilder*, а принимает указатель на память. Так извне можно аллоцировать буфер хоть на стеке, хоть на хипе. К тому же это лучше с точки зрения архитектуры - разделить ответственность получения ресурса(выделения памяти) и конструирования объекта.

НЛО прилетело и опубликовало эту надпись здесь

и молиться, чтобы не забыть его при каких-либо изменениях в StringBuffer'е

Можно static_assert'ом проверить - надеюсь, про fastpImpl от Полухина все в курсе ) У него, правда, плюсы, но static_assert и в C11 есть, что то похожее можно сделать.

НЛО прилетело и опубликовало эту надпись здесь

Покажите, как проще делается скрытие реализации с возможностью аллокации на стеке. private в C++ эту задачу не решает.

НЛО прилетело и опубликовало эту надпись здесь

Практически этого недостаточно, нужно убрать зависимость при компиляции - так что в реальных больших плюсовых проектах используется либо чисто абстрактный интерфейс, либо pimpl c разными вариациями.

Что-то не вижу проблем (поправьте, если что):

size_t GetStringBuilderSizeof(); // Реализован где-то


В коде пользовательской функции:

StringBuilder* sb = (StringBuilder*)alloca(GetStringBuilderSizeof());
// Далее используем объект на стеке: явный вызов конструктора и т.д.

НЛО прилетело и опубликовало эту надпись здесь

Способ я не предлагал. Но думаю вы правы в чем-то.
Можно разместить на стеке? - Да
Будет ли это удобно, как при обычном использовании стека? - Нет

У нас нет наследования

Стоило бы тогда рассказать про стандартную схему реализации полиморфизма (структура с указателями на функции).

В качестве альтернативы предлагают generic macro, которые даже можно автогенерировать с помощью макросной магии)

А можно поконкретнее? Как на них сделать, скажем, объект, который умеет read/write (и при этом иметь несколько реализаций, скрытых от пользователя)?

_Generic про параметрический полиморфизм. Обычно делают так:


  1. Пишут header-only реализацию контейнера, того же листа, например
  2. Пишут модуль, в котором конкретизируются структуры данных и методы. В этом случае read является _Generic макросом, который подставляется в зависимости от переданного типа, а сокрытие сделано как в описано в статье

Все вместе похоже на программирование на шаблонах в плюсах.
Вот примеры, лучше смотреть в том порядке, какой я предложил, есть разные подходы к реализации: [1], [2], [3]
На самом деле довольно грязно и сложновато в отладке, хоть и не как подход с void*. Поэтому есть несколько подробных статей, как сохранить типобезопасность ([4], [5]) и не острелить себе ноги [6]. Если мы широко используем X-macro, который включается без include guard и который легко забыть undef-нуть, становится еще интереснее)

Ну так это не альтернатива, а другая функциональность. Так то все, наверное, когда то писали свои списки для произвольного типа на чистом C )

Там можно еще делать структры с указательми на функции, и получаем методы. Которые можно "переопределить".

С одной стороны руками это достаточно напряжно, но в конце выглядит прикольно (и очень не читаемо).

Что напряжного в том, чтобы объявить несколько указателей в структуре, заполнить в функции инициализации и дальше вызывать obj->method(obj,...) ? Да, нет неявного this и в реализациях надо руками кастить объект к нужному типу - но всё равно дополнительной писанины не так много.

Сделать несложно. А вот понять что в конкретный момент там за указателем скрывается ...

Так весь смысл инкапсуляции - за указателем скрывается сущность с такими то методами, больше о ней ничего неизвестно. Конкретных реализаций несколько, могут добавляться уже после того, как написан использующий их код - так что закладываться на внутренности в принципе нельзя.

Просто приятно, когда умная IDE шка подсказывает, или по имени класса все яснт

А вот случае С иди и думай, чего ты там присвоил 100500 строк кода до того

typedef struct StringBuilder StringBuilder;

самая идиотская вещь, которую смогли придумать Сишники. Эту структуру даже в умный указатель не возможно по нормальному потом завернуть... И всё это ради каких то приватных полей... для компилятора!

Какие умные указатели в C?

НЛО прилетело и опубликовало эту надпись здесь

довольно часто делается линковка C++ кода с чисто-C либами

При этом надо сразу понимать, что несмотря на общую базу это разные языки с разыми подходами к реализации одних и тех же концепций, так что часто надо писать явный враппер.

правильно, все можно, хотя слово "можно" имеет много разных оттенков, мне к примеру без разницы на чем писать embedded sw, что действительно заботит - как и сколько долго придется систему тестировать и отлаживать, имея в виду довольно сложные сценарии для real time, по опыту для embedded С++ больших преимуществ не дает, конечно код можно сделать более читабельный и красивый, но отлаживать будет труднее, хотя многое конечно зависит от личных предпочтений

А собственно, что там невозможного, написать кастомный делитер?

#include <memory>

struct StringBuilderDeleter {
  operator()(StringBuilder* ptr) const {
    DestroyStringBuilder(ptr);
  }
};

using StringBuilderPtr = std::unique_ptr<StringBuilder, StringBuilderDeleter>;

Язык С не создавался под ООП парадигму, и подобные конструкции лично на мой взгляд усложняют читаемость кода. Мораль - пишем на С++ если уж очень нужно ООП.

Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации