Структура данных с наследованием. Проблемы с инициализацией - PullRequest
2 голосов
/ 30 января 2011

Мне нужно создать класс, скажем, FineStack, который должен объявить структуру, способную управлять различными видами штрафов (LightFine, SeriousFine).Суперкласс для обоих: Fine.

Вопрос в том, нужны ли мне шаблоны?Я думал, что в этом нет необходимости, поэтому я подумал:

-> Объявить Fine *fines;(своего рода массив штрафов?) И ... создавая массив объектов Fine (суперкласс), он должен иметь возможность управлять объектами LightFine и SeriousFine.

-> Проблема в том.Как мне это объявить?Fine должен быть абстрактным классом, поэтому экземпляры не могут быть созданы (экземпляры должны быть LightFine или SeriousFine).

Я застрял с этим, так как не могу найти способ его получить.Здесь, в Stackoverflow, я прочитал несколько вопросов, которые вы, ребята, обычно предлагаете использовать std::vector, что упрощает управление такими вещами.

Должен ли я пойти таким путем и забыть об оригиналеидея?

Мне нужна структура, которая должна быть в состоянии обрабатывать любой объект из обоих подклассов, в любом порядке (скажем .. 3 LightFine и 2 SeriousFine ... или альтернативно друг друга изначало до конца структуры ... что угодно.

Ответы [ 5 ]

10 голосов
/ 30 января 2011

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

Хотя Fine не может быть создан, вы можете указать на это, поэтому:

Fine* f1 = new LightFine();
Fine* f2 = new SeriousFine();

оба законны, потому чтоLightFine is-a Fine и SeriousFine is-a Fine.

Редактировать: Я вижу, что это еще не ясно.Если вы прочтете вышеизложенное, вы увидите, что я могу удерживать указатель Fine*, но при этом «тайно» указывать либо на LightFine, либо на SeriousFine.Это означает, что если бы я держал кучу Fine* указателей, некоторые из них могли бы быть LightFine, а некоторые SeriousFine.то есть, я могу сделать это:

Fine** fines = new Fine*[5];
f[0] = new LightFine();
f[1] = new SeriousFine();
...
for (int i=0; i<5; i++) {
    std::cout << fines[i]->toString() << std::endl;
}

, и результат будет:

легкий штраф

серьезный штраф

...

Если вы do хотите использовать вектор, он также должен иметь тип vector<Fine*> и , а не vector<Fine>.

2 голосов
/ 30 января 2011

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

Решение состоит в том, чтобы использовать либо массив указателей (например, Fine **fines и fines = new Fine*[whatever-size-you-need]), либо вектор указателей (например, std::vector<Fine*> fines). После этого вы можете создать экземпляр любого подкласса Fine с помощью new, и он будет неявно повышен до Fine*, когда вы поместите его в массив / вектор.

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

1 голос
/ 30 января 2011

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

В идеале вы должны использовать vector<std::tr1::shared_ptr<Fine> >. Документация Boost хорошо объясняет, почему shared_ptr упрощает управление памятью; shared_ptr в TR1 - это то же самое, что и Boost, за исключением того, что , вероятно, уже поставляется с вашим компилятором .

Если вы довольны собственным управлением памятью, используйте vector<Fine*>. Не использовать vector<Fine> - это приведет к разрезанию объекта .

Что такое нарезка объектов? LightFine (возможно) больше, чем Fine, поэтому он не помещается в тот же объем памяти. Если вы объявили Fine a; LightFine b; a = b;, это скомпилируется, но весь объект LightFine не поместится в a, поэтому будет скопирован только подобъект Fine из b. По сути, то же самое происходит при вставке LightFine объекта в vector<Fine>.

Вы не сможете обрабатывать a как объект LightFine после этого назначения, так как его статический тип - просто Fine, и все LightFine "части" все равно были отброшены. Кроме того, обработка a как объекта Fine может привести к непредвиденному поведению - например, Fine может иметь внутреннее поле данных, которое перепрофилируется на LightFine и, таким образом, содержит значение вне пределов при интерпретации * Методы 1041 *.

1 голос
/ 30 января 2011

Пересмотренный ответ после первых ошибок:

Будут ли в LightFine и SeriousFine реализован только интерфейс из Fine, или у них будут дополнительные методы, о которых FineStack нужно будет знать?

Если FineStack будет взаимодействовать только с объектами Fine с использованием методов, определенных в интерфейсе Fine, то я не вижу проблем с вашим подходом к массиву, если вы используете Fine** fines ( т.е. массив указателей на Fine с). Хотя я бы вместо этого использовал std::vector<Fine*>.

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

0 голосов
/ 30 января 2011

звучит так, как будто вы должны идти с std::vector<Fine>

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