Ответ 1
Что касается методов расширения С#: Не напрямую. С++ имеет меньшую потребность в этих вещах, потому что С++ поддерживает бесплатные функции. Я никогда не использовал Objective-C, поэтому я не могу комментировать там.
Есть ли способ реализовать такие функции, как категории классов (из Objective-C) или методы расширения (С# 3.0) на C и/или С++?
Что касается методов расширения С#: Не напрямую. С++ имеет меньшую потребность в этих вещах, потому что С++ поддерживает бесплатные функции. Я никогда не использовал Objective-C, поэтому я не могу комментировать там.
С++ имеет бесплатные функции, но иногда методы расширения работают лучше, когда вы объединяете множество функций вместе. Взгляните на этот код С#:
var r = numbers.Where(x => x > 2).Select(x => x * x);
Если мы напишем это на С++, используя свободную функцию, это будет выглядеть так:
auto r = select(where(numbers, [](int x) { return x > 2; }), [](int x) { return x * x; });
Это трудно читать, но писать сложно. Общим способом решения этой проблемы является создание так называемой функции-конвейера. Эти функции создаются путем перегрузки оператора трубы |
(который действительно является оператором или оператором). Таким образом, приведенный выше код можно написать следующим образом:
auto r = numbers | where([](int x) { return x > 2; }) | select([](int x) { return x * x; });
Что гораздо проще читать и писать. Многие библиотеки используют функцию pipable для диапазонов, но ее можно расширить и для других классов. Boost использует его в своей библиотеке range, pstade oven использует его, а также эта библиотека С++ linq также использует его.
Если вы хотите написать свою собственную функцию для подключения, объясните, как это сделать здесь. Однако другие библиотеки предоставляют функциональные адаптеры, чтобы упростить их работу. Яйца Pstade имеет переходный адаптер, а linq предоставляет адаптер range_extension
для создания функции с плавающей запятой для диапазонов как минимум.
Используя linq, вы сначала просто создаете свою функцию как объект функции следующим образом:
struct contains_t
{
template<class Range, class T>
bool operator()(Range && r, T && x) const
{ return (r | linq::find(x)) != boost::end(r); };
};
Затем вы инициализируете функцию с помощью статической инициализации следующим образом:
range_extension<contains_t> contains = {};
Затем вы можете использовать свою функцию для подключения:
if (numbers | contains(5)) printf("We have a 5");
Не совсем. Это не способ С++ для обработки таких классов.
Среди прочих, Майерс утверждает, что лучше всего иметь небольшой класс с минимальным набором операций, которые делают его полностью полезным. Если вы хотите расширить набор функций, вы можете добавить пространство имен утилиты (например, пространство имен ClassUtil), которое содержит функции-члены, не являющиеся членами, которые работают с этим минимальным классом. Легко добавлять функции в пространство имен из любого места.
Вы можете проверить обсуждение темы здесь.
С++ не имеет закрытых классов или наследования одного класса, поэтому в большинстве случаев вы можете подклассифицировать базовый класс. Существуют творческие способы сделать класс ненаследуемым, но они немногочисленны и далеко друг от друга. В общем, С++ не имеет проблем, с которыми С# порождает методы расширения.
C не ориентирован на объект, поэтому вопрос не применяется.
Можете ли вы использовать интерфейс? Методы расширения - это простой способ избежать подклассификации, но они становятся бесполезными при использовании надлежащих методов OO. Причина, по которой они используются с Linq настолько велика, что команде VS не нужно было идти и обновлять код, который, скорее всего, сломал бы много устаревших приложений.
В MSDN: "В общем, мы рекомендуем применять методы расширения экономно и только тогда, когда вам нужно. Когда это возможно, клиентский код, который должен расширять существующий тип, должен сделать это, создав новый тип, полученный из существующего типа".