Форум программистов, компьютерный форум, киберфорум
С++ для начинающих
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск Заказать работу  
 
Рейтинг 4.85/13: Рейтинг темы: голосов - 13, средняя оценка - 4.85
3 / 2 / 1
Регистрация: 15.11.2020
Сообщений: 34

возможен ли std::vector с объектами абстрактного класса?

19.11.2020, 23:06. Показов 2842. Ответов 8

Студворк — интернет-сервис помощи студентам
добрый вечер!
создам отдельную тему, так как то обсуждение было несколько другое.

написал абстрактный класс "файл":
C++
1
2
3
4
class File {
public:
    virtual void WriteValue(_In_ int value) = 0;
};
сделал от него наследника "поток":
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class FileStream : public File {
protected:
    std::wofstream stream;
public:
    FileStream(char* fileName) {
        stream.open(fileName);
    }
    void WriteValue(_In_ int value) {
        stream << value;
    }
    ~FileStream() {
        stream.close();
    }
};
теперь я хочу сделать класс "группа файлов", содержащий список любых наследников от "файл", плюс сам поддерживающий интерфейс "файл":
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Files : public File {
protected:
    std::vector<File> files;
public:
    Files() {}
    void AddFile(File& file) {
        files.push_back(file);
    }
    void WriteValue(_In_ int val) {
        for (auto& file : files)
            file.WriteValue(val);
    }
    ~Files() {}
};
но так не пропускает компилятор, ругается что:
Ошибка C2259 "File": невозможно создать экземпляр абстрактного класса
тогда я попытался изменить со "списка классов", на "список указателей на классы":
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Files : public File {
protected:
    std::vector<File*> files;
public:
    Files() {}
    void AddFile(File& file) {
        files.push_back(&file);
    }
    void WriteValue(_In_ int value) {
        for (auto& file : files)
            file->WriteValue(value);
    }
    ~Files() {}
};
но запутался как правильно передавать в AddFile() и делать освобождение. если я сделаю так:
C++
1
2
3
4
5
6
    FileStream file_1("file_1");
    FileStream file_2("file_2");
    Files all_files;
    all_files.AddFile(file_1);
    all_files.AddFile(file_2);
    all_files.WriteValue(123456);
то вроде бы всё работает (хотя и выдаёт две утечки, кстати откуда они?), но если сделаю вот так, то уже не работает совсем:
C++
1
2
3
4
5
6
7
8
9
10
    FileStream file_1("file_1");
    FileStream file_2("file_2");
    Files all_files;
    all_files.AddFile(file_1);
    all_files.AddFile(file_2);
    if ( ... ) {
        FileStream file_3("file_3");
        all_files.AddFile(file_3);
    }
    all_files.WriteValue(123456);
подумав, я кажется догадался - оно уничтожает file_3 на строке номер 9. и в all_files остаётся указатель на удалённый объект.
но как тут сделать правильнее? объявлять FileStream* и выделять через new? но тогда надо будет и за освобождением самому следить. а если исключение какое?
может всё же как-то можно автоматизировать? может будет лучше изменить что-то вообще в другом месте?
так будет вроде как-то совсем криво:
C++
1
2
3
4
5
6
7
    FileStream* file_3;
    if ( ... ) {
        file_3 = new FileStream("file_3");
        all_files.AddFile(*file_3);
    }
    all_files.WriteValue(123456);
    delete file_3;
или как-то возможно сделать std::vector с объектами абстрактного класса?

p.s. то что классы FileStream и Files требуют доработок, связанных с конструкторами копирования/перемещения - я уже знаю, просто ещё не доразобрался...

Добавлено через 3 минуты
весь текущий код:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>
 
#include <iostream>
#include <fstream>
#include <vector>
 
class File {
public:
    virtual void WriteValue(_In_ int value) = 0;
};
 
class FileStream : public File {
protected:
    std::wofstream stream;
public:
    FileStream(_In_ const char* fileName) {
        stream.open(fileName);
    }
    void WriteValue(_In_ int value) {
        stream << value;
    }
    ~FileStream() {
        stream.close();
    }
};
 
class Files : public File {
protected:
    std::vector<File*> files;
public:
    Files() {}
    void AddFile(_In_ File& file) {
        files.push_back(&file);
    }
    void WriteValue(_In_ int value) {
        for (auto& file : files)
            file->WriteValue(value);
    }
    ~Files() {}
};
 
int main() {
    _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
    _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG);
    std::cout << "Hello World!\n";
    FileStream file_1("file_1");
    FileStream file_2("file_2");
    Files all_files;
    all_files.AddFile(file_1);
    all_files.AddFile(file_2);
    FileStream* file_3;
    if (true) {
        file_3 = new FileStream("file_3");
        all_files.AddFile(*file_3);
    }
    /*
    if (true) {
        FileStream file_4("file_4");
        all_files.AddFile(file_4);
    }
    */
    all_files.WriteValue(123456);
    delete file_3;
    std::cout << "Done!\n";
    _CrtDumpMemoryLeaks();
    return 0;
}
0
Programming
Эксперт
39485 / 9562 / 3019
Регистрация: 12.04.2006
Сообщений: 41,671
Блог
19.11.2020, 23:06
Ответы с готовыми решениями:

На основе исходного std::vector<std::string> содержащего числа, создать std::vector<int> с этими же числами
подскажите есть вот такая задача. Есть список . Создать второй список, в котором будут все эти же числа, но не в виде строк, а в виде...

Реализация класса MyString. Стандартная библиотека, std::string, std::vector
как добавить реализацию конкатенации строк через перегрузку оператора &quot;+=&quot; в классе MyString и почему ошибка выдается???#include...

Деструктор для абстрактного класса, использующего static vector
Доброго времени суток. Возникла проблема с написание деструктора абстрактного класса, использующего static vector для хранения ссылок на...

8
Заблокирован
19.11.2020, 23:12
Абстрактный класс на то и абстрактный, не может существовать объектов абстрактного класса.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
19.11.2020, 23:29
WillyM, много текста, но сам вопрос прозрачен, если мой ответ не попадёт в цель, - продолжим. Тогда вы покажете поконкретнее проблему.
Абстрактные классы очень хороши для работы в коллекциях. Только типом элемента коллекции нужно выбрать указатель на базовый класс. Можно использовать умные указатели. Какие - вопрос конкретной задача. Будет некоторый оверхед в том смысле, что вектор выделит память под указатели, а указатели выделят под соответствуюие объекты наследников. Но такова се ля ++.
0
3 / 2 / 1
Регистрация: 15.11.2020
Сообщений: 34
19.11.2020, 23:48  [ТС]
SmallEvil, я не собирался создавать объекты абстрактного класса, мне надо создавать объекты не абстрактных наследников абстрактного класса и я планировал совать их в vector<базовый_абстрактный>
теперь задумался и понял - наследники же могут быть вовсе разного размера в памяти, так что да, в принципе бы не вышло такого. только с указателями.

IGPIGP, я только учусь пользоваться классами std, до этих штук ещё не дошёл. их там вроде три вида, да?
если я создам объект класса не как локальную переменную, а через new - получается указатель.
я как-то могу сунуть этот указатель в std::vector<?> files, чтоб при освобождении files сами объекты по тем указателям освобождались сами?
или как ещё можно организовать?
0
 Аватар для Nishen
1357 / 856 / 365
Регистрация: 26.02.2015
Сообщений: 3,814
19.11.2020, 23:52
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
#include <iostream>
#include <memory>
#include <vector>
 
 
class IFile {
 
public:
    virtual ~IFile() { }
 
    virtual void write() const = 0;
 
};
 
class File : public IFile {
 
public:
    virtual ~File() { }
 
    virtual void write() const override final {
 
        std::cout << "File::write\n";
 
    }
 
};
 
class FileStream : public IFile {
 
public:
    virtual ~FileStream() { }
 
    virtual void write() const override final {
 
        std::cout << "FileStream::write\n";
 
    }
 
};
 
class Catalog : public IFile {
 
public:
    virtual ~Catalog() { }
 
    void add(std::shared_ptr<IFile> file) {
 
        storage_.push_back(file);
 
    }
    
    virtual void write() const override final {
 
        for (const auto& file : storage_)
            file->write();
 
    }
 
private:
    std::vector<std::shared_ptr<IFile>> storage_;
 
};
 
 
int main() {
 
    std::shared_ptr<IFile> file = std::make_shared<File>();
    std::shared_ptr<IFile> fileStream = std::make_shared<FileStream>();
 
    Catalog catalog;
    catalog.add(file);
    catalog.add(fileStream);
 
    catalog.write();
 
    return 0;
 
}
2
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
19.11.2020, 23:56
Цитата Сообщение от WillyM Посмотреть сообщение
IGPIGP, я только учусь пользоваться классами std, до этих штук ещё не дошёл. их там вроде три вида, да?
если я создам объект класса не как локальную переменную, а через new - получается указатель.
я как-то могу сунуть этот указатель в std::vector<?> files, чтоб при освобождении files сами объекты по тем указателям освобождались сами?
или как ещё можно организовать?
Про смарты почитайте. unique_ptr может быть тем что нужно. Но в принципе, можно и сырой указатель: std::vector<MyBase*> и вперёд) Но помните, - вектор запускает деструктора своих элементов. Если элемент - raw pointer то у него вообще нет деструктора. Он просто поте6ряется как и любой указатель (при выходе из области). Поэтому вам нужно будет перед выходам из области вектора - пройти по нему и вызвать delete на каждом элементе. Виртуальный деструктор всех поубивает разнообразно и изощрённо.А передавать сам вектор (if any) по ссылке или указателю. Копии создавать осторожно (лучше этого не делать) и с пониманием происходящего. Можно обернуть вектор в класс и весь его (вектора) lifecycle контролировать от конструктора до деструктора. В деструкторе и вызывать итерацию с delete)
1
3 / 2 / 1
Регистрация: 15.11.2020
Сообщений: 34
20.11.2020, 00:13  [ТС]
спасибо огромное!

Добавлено через 8 минут
у абстрактного класса виртуальный деструктор - это чтоб при освобождении shared_ptr вызывался правильный деструктор правильного потомка? иначе бы пытаться вызвать деструктор самого IFile? так я понял?
и в потомках тоже надо писать virtual перед методами? но я же вот не писал и вроде было всё нормально.
в чём плюсы shared_ptr? а если такой случай что мне допустим больше совсем никогда не нужен созданный объект? можно так?
C++
1
catalog.add(std::make_shared<File>());
Добавлено через 1 минуту
я имел ввиду никогда не нужен указатель на объект и доступ к нему. он будет в catalog а обратно уже не нужен.
0
 Аватар для Nishen
1357 / 856 / 365
Регистрация: 26.02.2015
Сообщений: 3,814
20.11.2020, 00:40
Цитата Сообщение от WillyM Посмотреть сообщение
ызывался правильный деструктор правильного потомка?
Да.
Цитата Сообщение от WillyM Посмотреть сообщение
и в потомках тоже надо писать virtual перед методами?
Можно не писать.
Цитата Сообщение от WillyM Посмотреть сообщение
в чём плюсы shared_ptr?
Почитай про умные указатели.
0
Комп_Оратор)
Эксперт по математике/физике
 Аватар для IGPIGP
9005 / 4706 / 630
Регистрация: 04.12.2011
Сообщений: 14,003
Записей в блоге: 16
20.11.2020, 01:00
Цитата Сообщение от WillyM Посмотреть сообщение
и в потомках тоже надо писать virtual перед методами?
Можно не писать. Можно и override не писать. Но приучитесь писать по возможности. Оно предотвратит неприятные сюрпризы.
Цитата Сообщение от WillyM Посмотреть сообщение
в чём плюсы shared_ptr?
он сам удалит объект, когда объект ни кому не нужен. Имеет свойство отстреливать ноги. Лучше сначала
Цитата Сообщение от IGPIGP Посмотреть сообщение
обернуть вектор в класс и весь его (вектора) lifecycle контролировать от конструктора до деструктора. В деструкторе и вызывать итерацию с delete)
Это имеет вид в тот же профиль, что и освобождение выделенной памяти в простейшем классе с "динамическим" массивом. Но поупражнявшись, вы будете читать про смарты овладев темой владения властно и персонально. Легче будет понять, про что пишут и если повезёт, - испытать RAII'ское наслаждение)
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
inter-admin
Эксперт
29715 / 6470 / 2152
Регистрация: 06.03.2009
Сообщений: 28,500
Блог
20.11.2020, 01:00
Помогаю со студенческими работами здесь

Как передать целочисленную матрицу типа std::vector<std::vector<int> > в функцию?
Здравствуйте. Почитал на форуме, но так и не понял что я делаю не так. Имеется двумерный вектор. Размера .. Нужно его передать в...

Ошибка: E2034 Cannot convert 'int' to 'std::vector<std::vector<TRabbitCell,std::allocator<TRabbitCell>>...
Есть двухмерный вектор: std::vector&lt;std::vector&lt;TRabbitCell&gt; &gt; *cells(5, 10); Пытаюсь заполнить его объектами класса...

Передать инициализированный std::vector конструктору базового класса
В общем появилась одна проблема. Никак не пойму как можно сделать. В общем дело такое: 1) Есть класс Coord, который содержит координаты. ...

Реализовать аналог класса std::string с помощью vector
Помогите, пожалуйста, с кодом к заданию: Реализовать аналог класса std::string с помощью vector Заранее спасибо!

Вывести значения std::vector<std::vector<int*> >
Подскажите, как вывести значения? const size_t row = 3; const size_t col = 3; std::vector&lt;std::vector&lt;int*&gt; &gt; imatrix; ...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
9
Ответ Создать тему
Новые блоги и статьи
PhpStorm 2025.3: WSL Terminal всегда стартует в ~
and_y87 14.12.2025
PhpStorm 2025. 3: WSL Terminal всегда стартует в ~ (home), игнорируя директорию проекта Симптом: После обновления до PhpStorm 2025. 3 встроенный терминал WSL открывается в домашней директории. . .
Access
VikBal 11.12.2025
Помогите пожалуйста !! Как объединить 2 одинаковые БД Access с разными данными.
Новый ноутбук
volvo 07.12.2025
Всем привет. По скидке в "черную пятницу" взял себе новый ноутбук Lenovo ThinkBook 16 G7 на Амазоне: Ryzen 5 7533HS 64 Gb DDR5 1Tb NVMe 16" Full HD Display Win11 Pro
Музыка, написанная Искусственным Интеллектом
volvo 04.12.2025
Всем привет. Некоторое время назад меня заинтересовало, что уже умеет ИИ в плане написания музыки для песен, и, собственно, исполнения этих самых песен. Стихов у нас много, уже вышли 4 книги, еще 3. . .
От async/await к виртуальным потокам в Python
IndentationError 23.11.2025
Армин Ронахер поставил под сомнение async/ await. Создатель Flask заявляет: цветные функции - провал, виртуальные потоки - решение. Не threading-динозавры, а новое поколение лёгких потоков. Откат?. . .
Поиск "дружественных имён" СОМ портов
Argus19 22.11.2025
Поиск "дружественных имён" СОМ портов На странице: https:/ / norseev. ru/ 2018/ 01/ 04/ comportlist_windows/ нашёл схожую тему. Там приведён код на С++, который показывает только имена СОМ портов, типа,. . .
Сколько Государство потратило денег на меня, обеспечивая инсулином.
Programma_Boinc 20.11.2025
Сколько Государство потратило денег на меня, обеспечивая инсулином. Вот решила сделать интересный приблизительный подсчет, сколько государство потратило на меня денег на покупку инсулинов. . . .
Ломающие изменения в C#.NStar Alpha
Etyuhibosecyu 20.11.2025
Уже можно не только тестировать, но и пользоваться C#. NStar - писать оконные приложения, содержащие надписи, кнопки, текстовые поля и даже изображения, например, моя игра "Три в ряд" написана на этом. . .
Мысли в слух
kumehtar 18.11.2025
Кстати, совсем недавно имел разговор на тему медитаций с людьми. И обнаружил, что они вообще не понимают что такое медитация и зачем она нужна. Самые базовые вещи. Для них это - когда просто люди. . .
Создание Single Page Application на фреймах
krapotkin 16.11.2025
Статья исключительно для начинающих. Подходы оригинальностью не блещут. В век Веб все очень привыкли к дизайну Single-Page-Application . Быстренько разберем подход "на фреймах". Мы делаем одну. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2025, CyberForum.ru