всегда должен возвращать указатель на класс в дизайне интерфейса? - PullRequest
15 голосов
/ 01 сентября 2010

Хотелось бы вернуть объект виртуального базового класса, чтобы мне не приходилось иметь дело с управлением памятью (идея программирования функций также стимулирует это стремление).Это означает, что я ищу некоторые вещи, как показано ниже:

class Car
{
  public:
     virtual int price() = 0 ;
     virtual string brand() = 0 ;
}

class Interface
{
  public:
     virtual Car giveMeACar() = 0 ;
     virtual vector<Car> listMeAllTheCars() = 0 ;
}

Однако, это даже не скомпилируется, потому что Car является абстрактным интерфейсом с сообщением об ошибке:

неверный абстрактный тип возвращаемого значения для функции-члена 'virtual Car giveMeACar() = 0;потому что следующие виртуальные функции являются чистыми внутри 'Car': int price()
string brand();

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

class Interface
{
  public:
     virtual Car* giveMeACar() = 0 ;
     virtual vector<Car*> listMeAllTheCars() = 0 ;
}

Мой вопрос: это единственный вариант, который у меня есть, когда я проектирую интерфейс, где каждая вещь (класс) абстрактна?

Возвращение объекта интерфейсного класса идеально подходит для Java.В этом аспекте С ++ кажется немного многословным и противоречащим интуиции.Чаще всего я чувствую, что C ++ - это «указатель на язык объектного программирования» вместо «языка объектного программирования», потому что без указателя вы не сможете получить слишком много преимуществ от объектного программирования.

Ответы [ 6 ]

8 голосов
/ 01 сентября 2010

В Java «возвращение и объект» фактически семантически эквивалентно возвращению указателя на объект в C ++, вы пытаетесь вернуть объект по значению, что делает его копию.Вы не можете сделать копию абстрактного объекта.

Итак, хотя C ++ может быть более многословным, он поддерживает различные семантики для передачи параметров и возвращаемых значений, которые Java не поддерживает (возврат по значению, передачапо ссылке).

Сказав это, вы должны вернуться с помощью умного указателя, который делает управление памятью для вас.Другие указали auto_ptr с семантикой передачи прав собственности, но вы также можете использовать boost::shared_ptr, если вы используете собственное выделение памяти внутри (например, пул), пользовательская функция удаления shared_ptr поможет вам скрыть детали освобождения отпользователь интерфейса.Он также может использоваться в контейнерах STL (в отличие от auto_ptr).

class Car
{
public:
    typedef boost::shared_ptr<Car> Ptr;
    virtual int price() = 0 ;
    virtual string brand() = 0 ;
};

class Interface
{
public:
    virtual Car::Ptr giveMeACar() = 0 ;
    virtual vector<Car::Ptr> listMeAllTheCars() = 0 ;
}
4 голосов
/ 01 сентября 2010

Ваши наблюдения верны, нет простого способа сделать то, что вы хотите сделать.В C ++ вы не можете вернуть Car по значению, потому что (помимо прочего) вызывающий должен выделить для него место.

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

3 голосов
/ 01 сентября 2010

Возврат std::auto_ptr< Car >.Он помещает объект в кучу как указатель, но удаляет его, когда он выходит из области видимости, как переменная стека.

Варианты включают boost::unique_ptr и C ++ 0x std::unique_ptr, которые заменяют auto_ptr.

vector<Car> нельзя заменить на vector< auto_ptr< Car > >, поскольку auto_ptr несовместимо с контейнерами.Для этого вам нужно использовать unique_ptr.

2 голосов
/ 01 сентября 2010

Другой вариант - использовать шаблон:

template<class CarClass>
class Interface {
    virtual CarClass giveMeACar() = 0;
    virtual vector<CarClass> listMeAllTheCars() = 0;
}
1 голос
/ 01 сентября 2010

Я думаю это может быть полезным.

0 голосов
/ 01 сентября 2010

Другие посты в ответ на ваш запрос отлично ответят на ваш запрос. Тем не менее, у меня было несколько замечаний, которые вы можете рассмотреть

Первое наблюдение:

Избегайте раскрытия подробностей о реализации внешнему миру.

Это относится к типу возврата

virtual vector<Car> listMeAllTheCars() = 0 ;.

Почему пользователи класса должны знать, используете ли вы vector или list или что-то еще? Проверьте Шаблон Итератора от GOF. C ++ имеет хорошую поддержку для итераторов.

Второе наблюдение:

Похоже, ваше требование имитирует потребность в шаблоне проектирования Factory Method, особенно когда я смотрю на

virtual Car giveMeACar() = 0 ;

Возможно, вы захотите взглянуть на фабричный метод Design Pattern

Третье наблюдение:

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

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