Подтвердить что ты не робот

Должен всегда возвращать указатель на класс в дизайне интерфейса?

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

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. С++, похоже, является многословным и очень интуитивно понятным в этом аспекте. Чаще всего я считаю, что С++ является "указателем на язык программирования объектов" вместо "языка программирования объектов", потому что без указателя вы не можете получить слишком много преимуществ от программирования объектов.

4b9b3361

Ответ 1

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

Итак, хотя С++ может быть более подробным, он поддерживает различную семантику для передачи параметров и возвращающих значений, которые 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 ;
}

Ответ 2

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

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

Ответ 3

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

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

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

Ответ 4

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

template<class CarClass>
class Interface {
    virtual CarClass giveMeACar() = 0;
    virtual vector<CarClass> listMeAllTheCars() = 0;
}

Ответ 5

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

Ответ 6

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

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

Избегайте подвергать деталям информацию о реализации внешнему миру.

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

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

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

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

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

virtual Car giveMeACar() = 0 ;

Возможно, вы захотите посмотреть на шаблон дизайна Factory

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

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