В C или C ++ есть способ расширить класс без наследования? - PullRequest
14 голосов
/ 28 мая 2010

Есть ли способ реализовать такую ​​функциональность, как категории классов (из Objective-C) или методы расширения (из C # 3.0) в C и / или C ++?

Ответы [ 5 ]

24 голосов
/ 14 февраля 2013

C ++ имеет свободные функции, но иногда методы расширения работают лучше, когда вы вкладываете много функций вместе. Посмотрите на этот код C #:

var r = numbers.Where(x => x > 2).Select(x => x * x);

Если мы напишем это в C ++, используя свободную функцию, это будет выглядеть так:

auto r = select(where(numbers, [](int x) { return x > 2; }), [](int x) { return x * x; });

Мало того, что это трудно читать, но и трудно писать. Обычный способ решить эту проблему - создать так называемую функцию. Эти функции создаются путем перегрузки оператора канала | (который на самом деле является оператором or). Таким образом, приведенный выше код может быть написан так:

auto r = numbers | where([](int x) { return x > 2; }) | select([](int x) { return x * x; });

Что гораздо проще читать и писать. Многие библиотеки используют функцию pipable для диапазонов, но ее можно расширить и на другие классы. Boost использует его в своей библиотеке range , pstade духовка использует его, а также эта библиотека C ++ linq также использует его.

Если вы хотите написать свою собственную переносимую функцию, boost объяснит, как это сделать здесь . Другие библиотеки, однако, предоставляют функциональные адаптеры, чтобы упростить его. Pstade egg имеет адаптер для трубопровода , а 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 = {};

Тогда вы можете использовать свою функцию pipable следующим образом:

if (numbers | contains(5)) printf("We have a 5");
4 голосов
/ 28 мая 2010

Не совсем.Это не способ C ++ для обработки таких классов.

Среди прочего, Мейерс утверждает, что лучше иметь маленький класс с минимальным набором операций, которые делают его полностью полезным.Если вы хотите расширить набор функций, вы можете добавить пространство имен служебных программ (например, пространство имен ClassUtil), которое содержит служебные функции, не являющиеся членами, которые работают с этим минимальным классом.Легко добавлять функции в пространство имен из любого места.

Вы можете проверить обсуждение по теме здесь .

1 голос
/ 28 мая 2010

C ++ не имеет запечатанных классов или наследования одного класса, поэтому в большинстве случаев вы можете создать подкласс базового класса. Существуют творческие способы сделать класс не наследуемым, но их мало, и они между ними. В общем, в C ++ нет проблем, которые создает C #, что породило методы расширения.

C не является объектно-ориентированным, поэтому вопрос на самом деле не применим.

0 голосов
/ 28 мая 2010

Можете ли вы использовать интерфейс? Методы расширения - это простой способ избежать создания подклассов, но они становятся бесполезными, когда используются надлежащие методы ОО. Причина, по которой они так часто используются в Linq, заключается в том, что команде VS не пришлось идти и обновлять код, который, скорее всего, сломал бы множество устаревших приложений.

За MSDN: «В общем, мы рекомендуем реализовывать методы расширения экономно и только тогда, когда это необходимо. Когда это возможно, клиентский код, который должен расширять существующий тип, должен делать это путем создания нового типа, производного от существующего типа».

http://msdn.microsoft.com/en-us/library/bb383977.aspx

0 голосов
/ 28 мая 2010

Что касается методов расширения C #: не напрямую. C ++ меньше нуждается в этих вещах, потому что C ++ поддерживает свободные функции. Я никогда не использовал Objective-C, поэтому я не могу комментировать там.

...