Достижение функциональности интерфейса в C ++ - PullRequest
0 голосов
/ 16 июля 2009

Основная причина, по которой я использую ООП, заключается в создании кода, который легко использовать повторно. Для этой цели идеально подходят интерфейсы в стиле Java. Однако, имея дело с C ++, я действительно не могу достичь какой-либо функциональности, такой как интерфейсы ... по крайней мере, нелегко.

Я знаю о чистых виртуальных базовых классах, но что меня действительно впечатляет, так это то, что они вынуждают меня создавать действительно неуклюжий код с указателями. Например. map<int, Node*> nodes; (где Node - это виртуальный базовый класс).

Иногда это нормально, но иногда указатели на базовые классы просто не являются возможным решением. Например. если вы хотите вернуть объект, упакованный как интерфейс, вам нужно будет вернуть приведенный к объекту указатель базового класса ... но этот объект находится в стеке и не будет там после возврата указателя. Конечно, вы можете начать использовать кучу, чтобы избежать этого, но это добавляет гораздо больше работы, чем должно быть (избегая утечек памяти).

Есть ли способ достичь функциональности, подобной интерфейсу, в C ++ без неловкого обращения с указателями и кучей ?? (Честно говоря, несмотря на все эти проблемы и неудобства, просто придерживайтесь C.)

Ответы [ 6 ]

4 голосов
/ 16 июля 2009

Вы можете использовать boost :: shared_ptr , чтобы избежать необработанных указателей. Как примечание, причина, по которой вы не видите указатель в синтаксисе Java, не имеет ничего общего с тем, как C ++ реализует интерфейсы, а не с тем, как Java реализует интерфейсы, а скорее является результатом того факта, что все объекты в Java неявные указатели (* скрыт).

2 голосов
/ 16 июля 2009

Шаблон MetaProgramming - довольно крутая вещь. Основная идея? «Полиморфизм времени компиляции и неявные интерфейсы», Effective C ++ . По сути, вы можете получить нужные интерфейсы через шаблонные классы. A ОЧЕНЬ простой пример:

template <class T>
bool foo( const T& _object )
{
    if ( _object != _someStupidObject && _object > 0 )
        return true;
    return false;
}

Так что в приведенном выше коде, что мы можем сказать об объекте T? Ну, он должен быть совместим с _someStupidObject ИЛИ он должен быть конвертируемым в тип, который совместим. Он должен быть сопоставим с целочисленным значением или снова преобразован в тип, который есть. Итак, теперь мы определили интерфейс для класса T. Книга «Эффективный C ++» предлагает гораздо лучшее и более подробное объяснение. Надеемся, что приведенный выше код дает вам некоторое представление о возможности «интерфейса» шаблонов. Также взгляните на любую из библиотек надстроек, которые почти полностью заполнены шаблонами.

0 голосов
/ 16 июля 2009

Это на самом деле один из случаев, когда светит C ++. Тот факт, что C ++ предоставляет шаблоны и функции, которые не связаны с классом, делает повторное использование намного проще, чем в чисто объектно-ориентированных языках. Реальность, однако, заключается в том, что вам придется корректировать способ, которым вы пишете свой код, чтобы использовать эти преимущества. Люди, которые приходят из чистых ОО-языков, часто испытывают трудности с этим, но в C ++ интерфейс объектов включает не функции-члены. Фактически считается хорошей практикой в ​​C ++ использовать функции, не являющиеся членами, для реализации интерфейса объектов, когда это возможно. Как только вы освоите использование шаблонных функций, не являющихся членами, для реализации интерфейсов, это уже несколько меняет жизнь. \

0 голосов
/ 16 июля 2009

Хотя у auto_ptr есть некоторые странные правила использования, которые вы должны знать *, он существует, чтобы такие вещи легко работали.

auto_ptr<Base> getMeAThing() {
    return new Derived();
}


void something() {
    auto_ptr<Base> myThing = getMeAThing();
    myThing->foo();  // Calls Derived::foo, if virtual
    // The Derived object will be deleted on exit to this function.
}

* Никогда не помещайте auto_ptrs в контейнеры, например. Понять, что они делают на задании, это другое.

0 голосов
/ 16 июля 2009

Я думаю, что ответ на ваш вопрос - нет, проще нет. Если вам нужны чистые интерфейсы (ну, такие же чистые, какие вы можете получить в C ++), вам придется мириться со всем управлением кучей (или попытаться использовать сборщик мусора. Есть другие вопросы на эту тему, но мой Мнение по этому вопросу таково: если вам нужен сборщик мусора, используйте язык, разработанный на одном языке (например, Java).

Один большой способ облегчить боль при управлении кучей - это автоматические указатели. У Boost есть хороший автоматический указатель, который выполняет за вас большую работу по управлению кучей. Std :: auto_ptr работает, но, на мой взгляд, довольно странно.

Вы также можете оценить, действительно ли вам нужны эти чистые интерфейсы или нет. Иногда вы делаете, но иногда (как часть кода, с которым я работаю), чистые интерфейсы только когда-либо создаются одним классом, и, таким образом, просто становятся дополнительной работой, без выгоды для конечного продукта.

0 голосов
/ 16 июля 2009

Учитывая, что C ++ не требует общих ограничений параметров, таких как C # , тогда, если вам это удастся, вы можете использовать boost :: concept_check . Конечно, это работает только в ограниченных ситуациях, но если вы можете использовать его в качестве решения, то у вас наверняка будет более быстрый код с меньшими объектами (меньше накладных расходов на vtable).

Динамическая диспетчеризация, использующая vtables (например, чисто виртуальные базы), увеличит размер ваших объектов, поскольку они реализуют больше интерфейсов. Управляемые языки не страдают от этой проблемы (это ссылка .NET, но Java похожа).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...