Почему не может мы объявлять станд.:: вектор <AbstractClass>?

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

#pragma once
#include <iostream>
#include <vector>

using namespace std;

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

class FunnyImpl: IFunnyInterface
{
public:
    virtual void IamFunny()
    {
        cout << "<INSERT JOKE HERE>";
    }
};

class FunnyContainer
{
private:
    std::vector <IFunnyInterface> funnyItems;
};

Строка, объявляющая вектор абстрактного класса, вызывает эту ошибку в MS VS2005:

error C2259: 'IFunnyInterface' : cannot instantiate abstract class

Я вижу очевидное обходное решение, которое должно заменить IFunnyInterface следующим:

class IFunnyInterface
{
public:
    virtual void IamFunny()
    {
        throw new std::exception("not implemented");
    }
};

Действительно ли это - приемлемый мудрый C++ обходного решения? В противном случае есть ли какая-либо сторонняя библиотека как повышение, которое могло помочь мне обойти это?

Спасибо за чтение этого!

Anthony

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

7 ответов

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

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

std::vector<IFunnyInterface*> ifVec;

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

116
ответ дан 24 November 2019 в 10:34
поделиться

STD :: Vector постарается выделить память, чтобы содержать ваш тип. Если ваш класс является чисто виртуальным, вектор не может знать размер класса, он должен выделить.

Я думаю, что с вашим общим обломком вы сможете составить вектор , но вы не сможете манипулировать FunnyImpl внутри него. Например, если ifunnyInterface (абстрактный класс) имеет размер 20 (я не знаю, не знаю) и FunnyImpl размером 30, потому что у него есть больше членов и кода, вы получите попытку вписаться в 30 в своем векторе 20

Было бы выделить память на куче с «новыми» и магазинными указателями в векторных

1
ответ дан 24 November 2019 в 10:34
поделиться

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

-2
ответ дан 24 November 2019 в 10:34
поделиться

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

std::vector <IFunnyInterface*> funnyItems;

или

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

Потому что между FunnyImpl и IFunnyInterface нет отношения IS A и нет неявного преобразования между FUnnyImpl и IFunnyInterface из-за частного наследования.

Обновите код следующим образом:

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

class FunnyImpl: public IFunnyInterface
{
public:
    virtual void IamFunny()
    {
        cout << "<INSERT JOKE HERE>";
    }
};
6
ответ дан 24 November 2019 в 10:34
поделиться

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

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

std::vector<IFunnyInterface*> ifVec;

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

-121--866239-

Хотя я никогда лично не использовал его раньше, существует пакет PEAR для кэширования. Рассмотрим его среди других вариантов, таких как Zend_Cache.

-121--3732576-

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

Указатель можно использовать в соответствии с другими предложениями.

2
ответ дан 24 November 2019 в 10:34
поделиться

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

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

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

21
ответ дан 24 November 2019 в 10:34
поделиться

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

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

  • Управление пожизнению
  • Двойное размышление итераторы

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

Теперь есть 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 идиома, обогащенная стратегией шаблон.

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

6
ответ дан 24 November 2019 в 10:34
поделиться
Другие вопросы по тегам:

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