error: недопустимое новое выражение абстрактного типа класса в векторном распределителе [duplicate]

Чтобы получить наилучший ответ на этот вопрос, я объединяю все ответы.

Альтернативы google maps api:

62
задан BlueTrin 29 January 2010 в 10:17
поделиться

7 ответов

Вы не можете создавать абстрактные классы, поэтому вектор абстрактных классов не может работать.

Однако вы можете использовать вектор указателей для абстрактных классов:

std::vector<IFunnyInterface*> ifVec;

Это также позволяет фактически использовать полиморфное поведение - даже если класс не был абстрактным, сохранение по значению привело бы к проблеме разбиения объектов .

95
ответ дан Georg Fritzsche 27 August 2018 в 01:57
поделиться
  • 1
    +1 для упоминания нарезки тоже – xtofl 29 January 2010 в 10:25
  • 2
    Спасибо за ответ – BlueTrin 29 January 2010 в 10:29
  • 3
    или вы можете использовать std :: vector & lt; std :: tr1 :: shared_ptr & lt; IFunnyInterface & gt; & GT; если вы не хотите работать с временем жизни объекта вручную. – Sergey Teplyakov 29 January 2010 в 11:51
  • 4
    Или даже лучше, boost :: ptr_vector & gt ;. – Roel 29 January 2010 в 15:06
  • 5
    Или теперь, std :: vector & lt; std :: unique_ptr & lt; IFunnyInterface & gt; & gt ;. – Kaz Dragon 2 November 2014 в 20:21

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

-2
ответ дан David Gruzman 27 August 2018 в 01:57
поделиться
  • 1
    +1 для объяснения того, почему происходит разбиение объектов – BlueTrin 29 January 2010 в 10:55
  • 2
    Это не основная причина, и это не «печальное ограничение». – user 29 January 2010 в 11:25
  • 3
    Пожалуйста, объясните, почему, по вашему мнению, это не ограничение? Было бы неплохо иметь возможность. И есть некоторые накладные расходы на программиста, когда он / она вынужден указывать указатели на контейнер и беспокоится о делеции. Я согласен, что наличие объектов разных размеров в одном и том же контейнере ухудшит производительность. – David Gruzman 29 January 2010 в 11:47
  • 4
    Отправка виртуальных функций в зависимости от типа объекта, который у вас есть. Вся точка конструктора состоит в том, что у него нет объекта еще . Связано с тем, почему у вас нет статических виртуальных функций: также нет объекта. – MSalters 29 January 2010 в 14:17
  • 5
    Я могу сказать, что шаблон контейнера класса не должен быть объектом, но фабрика классов и конструктор являются его естественной частью. – David Gruzman 29 January 2010 в 16:15

std :: vector попытается выделить память для хранения вашего типа. Если ваш класс является чисто виртуальным, вектор не может знать размер класса, который он должен будет выделить.

Я думаю, что с вашим обходным путем вы сможете скомпилировать vector<IFunnyInterface>, но вы выиграли ' t иметь возможность манипулировать FunnyImpl внутри него. Например, если IFunnyInterface (абстрактный класс) имеет размер 20 (я действительно не знаю), а FunnyImpl имеет размер 30, потому что у него больше членов и кода, вы в конечном итоге попытаетесь поместить 30 в свой вектор из 20

Решение заключалось бы в том, чтобы выделить память в куче с помощью «новых» и указателей хранения в vector<IFunnyInterface*>

1
ответ дан Eric 27 August 2018 в 01:57
поделиться
  • 1
    Я думал, что это был ответ, но посмотрите на gf-ответ и нарезку объектов, он точно объяснит, что произойдет в контейнере – BlueTrin 29 January 2010 в 10:52
  • 2
    В этом ответе описывалось, что произойдет, но без использования слова «разрезание», так что этот ответ правильный. При использовании вектора ptrs никакого нарезки не произойдет. В этом весь смысл использования ptrs. – Roel 29 January 2010 в 15:09

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

Вы можете использовать указатель, как и другие.

2
ответ дан kennytm 27 August 2018 в 01:57
поделиться

Традиционная альтернатива - использовать vector указателей, как уже отмечалось.

Для тех, кто ценит, Boost поставляется с очень интересной библиотекой: Pointer Containers, которая отлично подходит для задание и освобождает вас от различных проблем, связанных с указателями:

  • управление жизненным циклом
  • двойное разыменование итераторов

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

Теперь существует 3-я альтернатива, которая заключается в изменении вашей иерархии. Для лучшей изоляции пользователя я несколько раз использовал следующий шаблон:

class IClass;

class MyClass
{
public:
  typedef enum { Var1, Var2 } Type;

  explicit MyClass(Type type);

  int foo();
  int bar();

private:
  IClass* m_impl;
};

struct IClass
{
  virtual ~IClass();

  virtual int foo();
  virtual int bar();
};

class MyClass1: public IClass { .. };
class MyClass2: public IClass { .. };

Это довольно просто, а вариация Pimpl идиомы, обогащенная шаблоном Strategy .

Это работает, конечно, только в том случае, если вы не хотите напрямую манипулировать «истинными» объектами и вовлекаете глубокую копию. Возможно, это не так, как вы пожелаете.

6
ответ дан Matthieu M. 27 August 2018 в 01:57
поделиться
  • 1
    Спасибо за ссылку Boost и шаблон проектирования – BlueTrin 29 January 2010 в 19:06

В этом случае мы не сможем использовать даже этот код:

std::vector <IFunnyInterface*> funnyItems;

или

std::vector <std::tr1::shared_ptr<IFunnyInterface> > funnyItems;

Поскольку нет связи ISA между FunnyImpl и IFunnyInterface и существует нет неявного преобразования между FUnnyImpl и IFunnyInterface из-за частного наследования.

Вы должны обновить свой код следующим образом:

class IFunnyInterface
{
public:
    virtual void IamFunny()  = 0;
};

class FunnyImpl: public IFunnyInterface
{
public:
    virtual void IamFunny()
    {
        cout << "<INSERT JOKE HERE>";
    }
};
5
ответ дан Sergey Teplyakov 27 August 2018 в 01:57
поделиться
  • 1
    Большинство людей смотрели на личное наследство, которое я думаю :) Но давайте не будем путать ОП еще больше :) – Roel 29 January 2010 в 15:11
  • 2
    Ага. Особенно после фразы стартера: «Проведя довольно некоторое время, развиваясь в C #», (где нет личного наследования вообще). – Sergey Teplyakov 29 January 2010 в 15:13

Вы не можете создать вектор абстрактного типа класса, потому что вы не можете создавать экземпляры абстрактного класса и контейнеры стандартной библиотеки C ++, такие как std :: vector store values ​​(например, экземпляры). Если вы хотите это сделать, вам нужно будет создать вектор указателей на абстрактный тип класса.

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

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

18
ответ дан user 27 August 2018 в 01:57
поделиться
  • 1
    Спасибо за рекомендацию книги в дополнение к ответу на сообщение! – BlueTrin 29 January 2010 в 10:31
  • 2
    +1 Вы спасли мне два часа на эту проблему, спасибо. – Ory Band 19 November 2012 в 18:33
  • 3
    Но когда вы объявляете вектор абстрактных классов, вы не просите его создать какой-либо абстрактный класс, а просто вектор, способный удерживать неабстрактный подкласс этого класса? Если вы не передадите число в конструктор векторов, как он может знать, сколько экземпляров абстрактного класса необходимо создать? – Jonathan. 20 October 2014 в 17:48
Другие вопросы по тегам:

Похожие вопросы: