Форум программистов, компьютерный форум CyberForum.ru

Виртуальные конструкторы или выбор паттерна проектирования - C++

Восстановить пароль Регистрация
 
newbie666
Заблокирован
09.04.2014, 14:01     Виртуальные конструкторы или выбор паттерна проектирования #1
Vi danno il benvenuto signori!
Ну так вот. Терзают меня сомнения на счёт наследования в одной программке ....
См. картинку, допустим есть какая - то иерархия классов, ну они там наследуются как - то по своему -ну да не суть.
Цель: нужно, единожды создать всю иерархию классов, тоесть единожды вызвав их все конструкторы, сформировать иерархическую структуру классов, чтоб в каждом дочернем классе были унаследованы от уже проинициализированного родителя данные ... Фишка в том, что дочерних однотипных классов на одном уровне наследования может быть много, тоесть по идее если создавать каждый раз нового "сынка", он вызовет конструктор "папаши", что ясен пень не допустимо, т.к. папаша должен быть всегда один, а сынков - много...
Я так подумал, что для таких целей вообще наследование не подходит - проще хранить указатели на все другие классы в одном каком - то, базовом например, да и всё ..
Кто что думает?
Миниатюры
Виртуальные конструкторы или выбор паттерна проектирования  
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
09.04.2014, 14:01     Виртуальные конструкторы или выбор паттерна проектирования
Посмотрите здесь:

C++ простой пример паттерна (facade)
C++ Что лучше учить сначала C или C++? Выбор литературы.
C++ виртуальные и чисто виртуальные функции
Выбор слова или словосочетания из списка C++
Насчёт шаблонного паттерна SingleTon C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
09.04.2014, 14:09     Виртуальные конструкторы или выбор паттерна проектирования #2
Цитата Сообщение от newbie666 Посмотреть сообщение
дочерних однотипных классов на одном уровне наследования может быть много, тоесть по идее если создавать каждый раз нового "сынка", он вызовет конструктор "папаши", что ясен пень не допустимо, т.к. папаша должен быть всегда один, а сынков - много...
Смешали в кучу иерархию классов и состояние объектов.
Если есть иерархия классов, то конструктор родителя обязан вызываться каждый раз при создании объекта дочернего класса.
Если у Вас есть какие-то общие для всех константные данные - их можно инициализировать где-нибудь один раз и передавать объектам указатель на них при конструировании.
newbie666
Заблокирован
09.04.2014, 14:21  [ТС]     Виртуальные конструкторы или выбор паттерна проектирования #3
Цитата Сообщение от 0x10 Посмотреть сообщение
Если у Вас есть какие-то общие для всех константные данные - их можно инициализировать где-нибудь один раз и передавать объектам указатель на них при конструировании.
это то понятно, вот по этому сейчас у меня все классы одного уровня иерархии без всякого наследования.
Я при создание любого класса передаю в него указатель на основной класс, где хранятся все указатели на другие классы .... Так просто в базовых классах напрягает писать иногда типа
C++
1
base->renderer->show(трулялля) и т д
когда хотелось просто писать show (труляля) :-))
Думаю, тут надо мутить виртуальные конструкторы ...

Добавлено через 2 минуты
Цитата Сообщение от 0x10 Посмотреть сообщение
конструктор родителя обязан вызываться каждый раз при создании объекта дочернего класса.
ваще наследование - вещь сугубо специфическая... Вот нахрена от чего - то наследоваться, что каждый раз родительский конструктор вызывался ... Не проще всю инфу в самом классе проинициализировать без родителя вообще.... Конечно, тут есть профит в приведение типов, типа я в функцию передаю указатель типа родителя, а в функции привожу в зависимости от поля типа объекта в этом родителе указатель к нужному классу..... но это сомнительный профит
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
09.04.2014, 14:31     Виртуальные конструкторы или выбор паттерна проектирования #4
Цитата Сообщение от newbie666 Посмотреть сообщение
в функции привожу в зависимости от поля типа объекта в этом родителе указатель к нужному классу..... но это сомнительный профит
Это вообще антипаттерн, зачем так делать?
newbie666
Заблокирован
09.04.2014, 14:45  [ТС]     Виртуальные конструкторы или выбор паттерна проектирования #5
Цитата Сообщение от 0x10 Посмотреть сообщение
Это вообще антипаттерн, зачем так делать?
ну а как ты сделаешь?
Вот посмотри на схему в первом посте, допусти есть базовый класс Miracle, есть два наследника Renderer и GameProcesor. Мне нужно чтоб в моей программе всегда был один экземпляр и Miracle и Renderer и GameProcesor, и хотелось бы, чтоб в каждом из наследников были данные из Miracle. Причём заранее что будет в Miracle - неизвестно, так как проект на стадии проектирования, каждый раз передавать тонну параметров в наследников - не коширно, передавать указатель на базовый Miracle - ну так я ща так и делаю... А вот хотелось бы, чтоб , ну хрен с остальными, что допустим эти три классы существовали в единственном экземпляре и в каждом наследнике были унаследованные данные из ОДНОГО И ТОГО ЖЕ базового класса Miracle.
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
09.04.2014, 14:48     Виртуальные конструкторы или выбор паттерна проектирования #6
Цитата Сообщение от newbie666 Посмотреть сообщение
Мне нужно чтоб в моей программе всегда был один экземпляр и Miracle и Renderer и GameProcesor
Сделать закрытыми конструкторы и оператор присваивания. Везде, где нужны - передавать указатели или ссылки на них.

Цитата Сообщение от newbie666 Посмотреть сообщение
каждый раз передавать тонну параметров в наследников - не коширно
Сделать один объект класса Context, где разместить общие данные. Указатель или ссылку на него передавать в классы.

Добавлено через 25 секунд
Из требований я повода для наследования не вижу.
newbie666
Заблокирован
09.04.2014, 14:55  [ТС]     Виртуальные конструкторы или выбор паттерна проектирования #7
Цитата Сообщение от 0x10 Посмотреть сообщение
Сделать один объект класса Context, где разместить общие данные. Указатель или ссылку на него передавать в классы.
ну так я и ща делаю, яж говорю.
Цитата Сообщение от 0x10 Посмотреть сообщение
Сделать закрытыми конструкторы и оператор присваивания.
это понятно, но защищать что - то от самого себя я не стану :-)

Вот смотри, допустим есть три класса:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Base
{
public:
    Base(){DATA = rand();};
    ~Base(){};
    int DATA;
};
 
class Child1 : public Base
{
public:
    Child1(){};
    ~Child1(){};
    int GetData(){return DATA;}
};
 
class Child2 : public Base
{
public:
    Child2(){};
    ~Child2(){};
    int GetData(){return DATA;}
};
Мне нужно создать по одному экземпляру каждого класса, но чтоб в экземплярах классов наследников функция GetDate() возвращала одно и тоже число базового класса.

C++
1
2
3
4
5
Base *base; //как то создать
Child1 *child1; //как то создать
Child2 *child2; //как то создать
if(child1->GetData() != child2->GetData())
    std::cout << "SHIT :-)" << std::endl;
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
09.04.2014, 15:25     Виртуальные конструкторы или выбор паттерна проектирования #8
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
#include <iostream>
#include <memory>
 
class Base {
public:
    Base(const std::shared_ptr<int>& sd) : shared_data_{sd} { }
    int& GetData() const { return *shared_data_; }
 
private:
    std::shared_ptr<int> shared_data_;
};
 
class C1 : public Base {
public:
    C1(const std::shared_ptr<int>& sd) : Base{sd} {}
};
 
class C2 : public Base {
public:
    C2(const std::shared_ptr<int>& sd) : Base{sd} {}
};
 
class Factory {
public:
    Factory() : shared_data_{std::make_shared<int>(42)} {}
    
    C1 CreateC1() const { return C1(shared_data_); }
    C2 CreateC2() const { return C2(shared_data_); }
private:
    std::shared_ptr<int> shared_data_;
};
 
 
int main() {
    Factory f;
    
    C1 c1 = f.CreateC1();
    C2 c2 = f.CreateC2();
    
    std::cout << "C1: " << c1.GetData() << std::endl;
    std::cout << "C2: " << c2.GetData() << std::endl;
    
    c1.GetData() = 10;
    
    std::cout << "C1: " << c1.GetData() << std::endl;
    std::cout << "C2: " << c2.GetData() << std::endl;
    
    
    return 0;
}
http://ideone.com/l5n6qe
newbie666
Заблокирован
09.04.2014, 15:36  [ТС]     Виртуальные конструкторы или выбор паттерна проектирования #9
Цитата Сообщение от 0x10 Посмотреть сообщение
shared_data_{sd} { }
В списке инициализации значения присваиваются в круглых скобках, а не в фигурных
Ну да ладно, ну ты хоть понимаешь, что это тоже самое, как и у меня сейчас? Тоесть есть главный класс, в котором хранятся указатели на все другие....
Я для понта у себя тоже мог бы написать, типа в главном классе есть функция QueryInterface, которая мне б возвращала указатель на любой из классов, указатель на который есть в основном ....
Мне думаю подошёл бы downcasting, но уж очень криво он работает, точнее вообще нормально не работает ...
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
09.04.2014, 15:43     Виртуальные конструкторы или выбор паттерна проектирования #10
Цитата Сообщение от newbie666 Посмотреть сообщение
В списке инициализации значения присваиваются в круглых скобках, а не в фигурных
Hello, C++11. Я специально ниже указал ссылку на ideone как пруф компилируемости.

Цитата Сообщение от newbie666 Посмотреть сообщение
Ну да ладно, ну ты хоть понимаешь, что это тоже самое, как и у меня сейчас?
Цитата Сообщение от newbie666 Посмотреть сообщение
Мне думаю подошёл бы downcasting, но уж очень криво он работает, точнее вообще нормально не работает ...
В предыдущих постах чередование запросов: то "мне нужны шареные данные", то "мне нужно знать тип во время выполнения". Чтобы не даункастить, есть паттерн visitor.
newbie666
Заблокирован
09.04.2014, 15:58  [ТС]     Виртуальные конструкторы или выбор паттерна проектирования #11
На самом деле в даункастинге нет ничего плохого.
Но вот кто - нибуть мне может внятно объяснить, почему в таком случае вылетает аксес виолэйшен?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Base
{
public:
    Base(){};
    ~Base(){};  
};
class Child : public Base
{
public:
    Child();
    ~Child();
    std::vector<int> childData;
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    Base *base = new Base;
    Child *child = static_cast<Child*>(base);   
    child->childData.push_back(rand()); // Access violation!
    
    return 0;
}
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
09.04.2014, 16:03     Виртуальные конструкторы или выбор паттерна проектирования #12
newbie666, потому что фактический тип - Base, у которого нет поля, к которому Вы обращаетесь.

Добавлено через 1 минуту
Цитата Сообщение от newbie666 Посмотреть сообщение
На самом деле в даункастинге нет ничего плохого.
И тут же:
Цитата Сообщение от newbie666 Посмотреть сообщение
почему в таком случае вылетает аксес виолэйшен?
newbie666
Заблокирован
09.04.2014, 16:06  [ТС]     Виртуальные конструкторы или выбор паттерна проектирования #13
Цитата Сообщение от 0x10 Посмотреть сообщение
потому что фактический тип - Base, у которого нет поля, к которому Вы обращаетесь.
не верно, т.к. если сделать так, то всё ок:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Base
{
public:
    Base(){};
    ~Base(){};  
};
class Child : public Base
{
public:
    Child();
    ~Child();
    std::vector<int> childData;
    int x;
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    Base *base = new Base;
    Child *child = static_cast<Child*>(base);       
    child->x = 3;   
    return 0;
}
тут наверное фишка в выделенной памяти под Base, точнее в её ограничение ... Т.к. vector динамический выделяет память ...
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
09.04.2014, 16:08     Виртуальные конструкторы или выбор паттерна проектирования #14
У вас не был сконструирован объект класса Child - следовательно, не было вызвано конструкторов для его полей. Получите UB.
newbie666
Заблокирован
09.04.2014, 16:11  [ТС]     Виртуальные конструкторы или выбор паттерна проектирования #15
Цитата Сообщение от 0x10 Посмотреть сообщение
У вас не был сконструирован объект класса Child - следовательно, не было вызвано конструкторов для его полей. Получите UB.
воо плавно переходим к цели данного треда Как перевести базовый класс в дочерний, при этом:
1. вызвав класс дочернего
2. не вызвав класс базового
3. имея возможность работать с данными базового класса в дочернем
0x10
2425 / 1597 / 232
Регистрация: 24.11.2012
Сообщений: 3,919
09.04.2014, 16:15     Виртуальные конструкторы или выбор паттерна проектирования #16
Изврат какой-то.
Наверняка исходную задачу можно решить более прямым способом, чем Вам хочется.

Добавлено через 2 минуты
Как вариант можно конструировать новые объекты на основе существующих.
Исходной задачи я не знаю, поэтому конкретики дать не могу.
newbie666
Заблокирован
09.04.2014, 16:53  [ТС]     Виртуальные конструкторы или выбор паттерна проектирования #17
Цитата Сообщение от newbie666 Посмотреть сообщение
Мне нужно чтоб в моей программе всегда был один экземпляр и Miracle и Renderer и GameProcesor, и хотелось бы, чтоб в каждом из наследников были данные из Miracle. Причём заранее что будет в Miracle - неизвестно, так как проект на стадии проектирования, каждый раз передавать тонну параметров в наследников - не коширно, передавать указатель на базовый Miracle - ну так я ща так и делаю... А вот хотелось бы, чтоб , ну хрен с остальными, что допустим эти три классы существовали в единственном экземпляре и в каждом наследнике были унаследованные данные из ОДНОГО И ТОГО ЖЕ базового класса Miracle.
Так вот:
1. Хочу создать один экземпляр базового класса
2. Хочу создать два дочерних класса, после создания базового, чтоб в этих дочерних классах были данные одного и того же базового

Мне это нужно чисто для удобства работы, т.к. если передавать во все классы указатель на общий класс, приходится долго дустукиваться до нужных данных, например: base->child1->child2->child3->getData()

Добавлено через 3 минуты
P.S.: в С++ ясно такой возможности не хватает. очень много где читал, что челы извращаются для достижения этой цели...
Было бы круто, если б я создал например базовый класс, а потом, просто отдельно, создавал бы дочерний от базового класс, но при этом в скобках бы указывал допустим указатель на существующий базовый класс, чтоб у него конструктор не вызывался, а просто все его данные перетекли бы в дочерний класс... Понятно излагаю ?

Добавлено через 21 минуту
Я вот на чём продемонстрирую суть вопроса:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Base
{
public:
    Base(){};
    ~Base(){};  
    int baseData;
};
 
class Child : public Base
{
public:
    Child(){};
    ~Child(){}; 
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    Base *base = new Base;
    base->baseData = 33;
    Child *child = new Child;       
    return 0;
}
Вот смотрите, я создаю экземпляр базового класса Base *base = new Base;, устанавливаю значение переменной в нём base->baseData = 33;, далее я создаю экземпляр дочернего класса
C++
1
Child *child = new Child;
. Так вот, при создание дочернего класса, он понятное дело вызовет конструктор базового, в результате в дочернем классе будет переменная базового класса с мусором, т.к. она никак не инициализировалась, а я хочу сделать так, чтоб при создание дочернего класса в нём была переменная базогово, равная в моём случае 33-м, тоесть чтоб при создание дочернего класса, он как бы создавался от уже существующего базового со всеми его значениями

Добавлено через 9 минут
ааа В общем парни забейте, автоматического средства нет
Придётся в каждом классе делать конструктор, в который передаётся родитель данного класса и в этом конструкторе устанавливаются ВРУЧНУЮ все переменные текущего класса исходя и данных переданного указателя... Ээххх вручную.... добавил переменную - переписывай конструктор
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
class Base
{
public:
    Base(){};
    ~Base(){};  
    int baseData;
};
 
class Child : public Base
{
public:
    Child(){};
    Child(Base* base)
    {
        baseData = base->baseData;
    }
    ~Child(){}; 
};
 
class Child2 : public Child
{
public:
    Child2(){};
    Child2(Child* child)
    {
        baseData = child->baseData;
    }
    ~Child2(){};    
};
 
int _tmain(int argc, _TCHAR* argv[])
{
    Base *base = new Base;
    base->baseData = 33;
    Child *child = new Child(base); 
    Child2 *child2 = new Child2(child);
    return 0;
}
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
09.04.2014, 17:40     Виртуальные конструкторы или выбор паттерна проектирования
Еще ссылки по теме:

C++ Объектно-ориентированного проектирования и проектирования на основе структур данных
Поясните принцип работы паттерна "абстрактная фабрика" C++
C++ Сделать сортировку или выбор из класса?

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

Или воспользуйтесь поиском по форуму:
Tulosba
:)
Эксперт С++
4378 / 3221 / 297
Регистрация: 19.02.2013
Сообщений: 9,044
09.04.2014, 17:40     Виртуальные конструкторы или выбор паттерна проектирования #18
Сообщение было отмечено автором темы, экспертом или модератором как ответ
newbie666, не надо путать иерархию классов C++ (которая фиксируется на момент компиляции) и возможность объектов ссылаться друг на друга в рантайме. См. паттерн "компоновщик" например.
Yandex
Объявления
09.04.2014, 17:40     Виртуальные конструкторы или выбор паттерна проектирования
Ответ Создать тему
Опции темы

Текущее время: 12:33. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru