Форум программистов, компьютерный форум, киберфорум
Наши страницы
С++ для начинающих
Войти
Регистрация
Восстановить пароль
 
Рейтинг 4.67/3: Рейтинг темы: голосов - 3, средняя оценка - 4.67
notAll
470 / 187 / 66
Регистрация: 27.05.2016
Сообщений: 487
Завершенные тесты: 2
1

Abstract Factory, переделка примера из книги Александреску с variadic templetes

13.09.2016, 22:17. Просмотров 604. Ответов 5
Метки нет (Все метки)

Александреску ("Современное проектирование на С++"), 9 глава. Там автор приводит очень интересный способ проектирования Abstract Factory. Я решил все это дело переписать с использованием вариадиков. Застрял на этом коде, дальше не знаю, как решить:
enemy.h
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
#ifndef ABSTRACTFACTORY_ENEMY_H
#define ABSTRACTFACTORY_ENEMY_H
 
#include <cstdio>
 
struct Enemy
{
    virtual void info() const = 0;
    virtual ~Enemy() = default;
};
 
struct Soldier : Enemy {};
struct Monster : Enemy {};
struct SuperMonster : Enemy {};
 
struct SillySoldier : Soldier
{
    void info() const override {puts(__PRETTY_FUNCTION__);}
};
 
struct BadSoldier : Soldier
{
    void info() const override {puts(__PRETTY_FUNCTION__);}
};
 
struct SillyMonster : Monster
{
    void info() const override {puts(__PRETTY_FUNCTION__);}
};
 
struct BadMonster : Monster
{
    void info() const override {puts(__PRETTY_FUNCTION__);}
};
 
struct SillySuperMonster : SuperMonster
{
    void info() const override {puts(__PRETTY_FUNCTION__);}
};
 
struct BadSuperMonster : SuperMonster
{
    void info() const override {puts(__PRETTY_FUNCTION__);}
};
 
#endif //ABSTRACTFACTORY_ENEMY_H
enemyHierarchyFactory.h
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
#ifndef ABSTRACTFACTORY_ENEMYHIERARCHYFACTORY_H
#define ABSTRACTFACTORY_ENEMYHIERARCHYFACTORY_H
 
#include <memory>
 
template <typename T>
class AbstractFactoryUnit
{
public:
    virtual std::unique_ptr<T> DoCreate() = 0;
    virtual ~AbstractFactoryUnit() = default;
};
 
template <template <typename> class Unit, typename ... AbstractProducts>
class AbstractFactory : public Unit<AbstractProducts>...
{
public:
    template <typename T>
    std::unique_ptr<T> Create()
    {
        Unit<T>& unit = *this;
        return unit.DoCreate();
    }
};
 
template <typename ConcreteProduct, typename Base>
class OpNewConcreteFactoryUnit : public Base
{
public:
    std::unique_ptr<ConcreteProduct> DoCreate() override
    {
        return std::make_unique<ConcreteProduct>();
    }
};
 
template <typename AbstractFact, template <typename, typename> class Unit, typename ... ConcreteProducts>
class ConcreteFactory : public Unit<ConcreteProducts, AbstractFact>...
{
 
};
 
#endif //ABSTRACTFACTORY_ENEMYHIERARCHYFACTORY_H
main
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>
#include <memory>
#include "enemy.h"
#include "enemyHierarchyFactory.h"
 
int main()
{
    using AbstractEnemyFactory =
    AbstractFactory<AbstractFactoryUnit, Soldier, Monster, SuperMonster>;
 
    using EasyFactory =
    ConcreteFactory<AbstractEnemyFactory, OpNewConcreteFactoryUnit,
            SillySoldier, SillyMonster, SillySuperMonster>;
 
    std::unique_ptr<AbstractEnemyFactory> pFactory{new EasyFactory};
    auto monster = pFactory->Create<Monster>();
    monster->info();
}
Ошибки возникают для DoCreate() - invalid covariant return type. И я не уверен, правильно ли реализовано наследование для ConcreteFactory.
Кто подскажет, как исправить.
0
QA
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
13.09.2016, 22:17
Ответы с готовыми решениями:

Курсовая работа Паттерн «Абстрактная фабрика/Abstract Factory»
Задание на курсовой проект: Паттерн «Абстрактная фабрика/Abstract Factory». Реализация 2-х/3-х...

Abstract factory
Как более грамотно можно переписать на джаве? class operation { public: virtual double...

Abstract Factory pattern
Всем привет, является ли такой подход реализацией паттерна в шапке, и что думаете на счет...

Использование совместно паттернов Builder и Abstract Factory
Добрый день. При изучении паттернов возникла идя написать программу моделирующую процесс...

Объясните паттерн Абстрактная фабрика (Abstract Factory)
Изучаю паттерны и застрял на одном из них. Есть код описывающий паттерн абстрактной фабрики. ...

5
DrOffset
10698 / 5717 / 1406
Регистрация: 30.01.2014
Сообщений: 9,179
13.09.2016, 22:25 2
notAll, либо избавляйся от std::unique_ptr в возвращаемом значении виртуальной функции, чтобы не блокировать ковариантность, либо делай его везде одинаковым (std::unique_ptr на базовый класс).
0
notAll
470 / 187 / 66
Регистрация: 27.05.2016
Сообщений: 487
Завершенные тесты: 2
14.09.2016, 11:02  [ТС] 3
Цитата Сообщение от DrOffset Посмотреть сообщение
либо делай его везде одинаковым (std::unique_ptr на базовый класс)
Ну вот так тоже не хочет:
Кликните здесь для просмотра всего текста
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
#include <memory>
#include "enemy.h"
 
class SuperAbstractFactory
{
public:
    virtual std::unique_ptr<Enemy> DoCreate() = 0;
    virtual ~SuperAbstractFactory() = default;
};
 
template <typename T>
class AbstractFactoryUnit : public SuperAbstractFactory
{
public:
    virtual std::unique_ptr<Enemy> DoCreate() = 0;
    virtual ~AbstractFactoryUnit() = default;
};
 
template <template <typename> class Unit, typename ... AbstractProducts>
class AbstractFactory : public Unit<AbstractProducts>...
{
public:
    template <typename T>
    T* Create()
    {
        Unit<T>& unit = *this;
        return unit.DoCreate();
    }
};
 
template <typename ConcreteProduct, typename Base>
class OpNewConcreteFactoryUnit : public Base
{
public:
    std::unique_ptr<ConcreteProduct> DoCreate() override
    {
        return std::make_unique<ConcreteProduct>();
        //return new ConcreteProduct;
    }
};
 
template <typename AbstractFact, template <typename, typename> class Unit, typename ... ConcreteProducts>
class ConcreteFactory : public Unit<ConcreteProducts, AbstractFact>...
{
};
ошибка
Bash
1
invalid covariant return type for 'std::unique_ptr<_Tp> OpNewConcreteFactoryUnit<ConcreteProduct, Base>::DoCreate() [with ConcreteProduct = SillySoldier; Base = AbstractFactory<AbstractFactoryUnit, Soldier, Monster, SuperMonster>]'
with ConcreteProduct = SillySoldier - тип, который возвращает DoCreate(), производный же от Base = AbstractFactory<AbstractFactoryUnit, Soldier, Monster, SuperMonster>. Тогда в чем же дело?

Добавлено через 2 минуты
На голых указателях тоже самое.

Добавлено через 11 часов 21 минуту
Короче, суть проблемы я кажись уже понял. DoCreate() можна правильно будет выбирать с помощью фиктивного параметра функции (так как и в книге; я думал что это не существенно). Вот как я это переделал:
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
#ifndef ABSTRACTFACTORY_ENEMYHIERARCHYFACTORY_H
#define ABSTRACTFACTORY_ENEMYHIERARCHYFACTORY_H
 
#include <memory>
#include <tuple>
 
template <typename T>
struct Type2Type
{
    using type = T;
};
 
template <typename T>
class AbstractFactoryUnit
{
public:
    virtual
    std::unique_ptr<T>
    //T*
    DoCreate(Type2Type<T>) = 0;
 
    virtual ~AbstractFactoryUnit() = default;
};
 
template <template <typename> class Unit, typename ... AbstractProducts>
class AbstractFactory : public Unit<AbstractProducts>...
{
public:
    using ProductList = std::tuple<AbstractProducts...>;
 
    template <typename T>
    std::unique_ptr<T>
    //T*
    Create()
    {
        Unit<T>& unit = *this;
        return unit.DoCreate(Type2Type<T>());
    }
};
 
template <typename ConcreteProduct, typename Base>
class ConcreteFactoryUnit : public Base
{
    using BaseProductList = typename Base::ProductList;
public:
    // надо получить эллемент тюпла для каждога базового класса по порядку
    using AbstractProduct = std::tuple_element_t<0, BaseProductList>; 
 
    std::unique_ptr<AbstractProduct>
    //ConcreteProduct*
    DoCreate(Type2Type<AbstractProduct>) override
    {
        //return new ConcreteProduct;
        return std::make_unique<ConcreteProduct>();
    }
};
 
template <typename AbstractFact, template <typename, typename> class Unit, typename ... ConcreteProducts>
class ConcreteFactory : public Unit<ConcreteProducts, AbstractFact>...
{
 
};
 
#endif //ABSTRACTFACTORY_ENEMYHIERARCHYFACTORY_H
Проблема в 47 строке - надо в каждом следующем экземпляре ConcreteFactoryUnit откусывать по одному елементу тюпла из каждого базового класса (std::tuple<AbstractProducts...>). Как это можна реализовать?
0
DrOffset
10698 / 5717 / 1406
Регистрация: 30.01.2014
Сообщений: 9,179
14.09.2016, 14:06 4
Цитата Сообщение от notAll Посмотреть сообщение
Как это можна реализовать?
Здесь все-таки без рекурсивного наследования не обойтись.

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

Добавлено через 26 минут

Не по теме:

Если не решишь сам, то вечером покажу примерную реализацию.
Сейчас некогда возиться.

2
notAll
470 / 187 / 66
Регистрация: 27.05.2016
Сообщений: 487
Завершенные тесты: 2
14.09.2016, 14:36  [ТС] 5
Решил сам. Так :
enemyHierarchyFactory.h
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
#ifndef ABSTRACTFACTORY_ENEMYHIERARCHYFACTORY_H
#define ABSTRACTFACTORY_ENEMYHIERARCHYFACTORY_H
 
#include <memory>
#include <tuple>
 
template <typename T>
struct Type2Type
{
    using type = T;
};
 
template <typename T>
class AbstractFactoryUnit
{
public:
    virtual std::unique_ptr<T> DoCreate(Type2Type<T>) = 0;
 
    virtual ~AbstractFactoryUnit() = default;
};
 
template <template <typename> class Unit, typename ... AbstractProducts>
class AbstractFactory : public Unit<AbstractProducts>...
{
protected:
    using ProductList = std::tuple<AbstractProducts...>;
public:
    template <typename T>
    std::unique_ptr<T> Create()
    {
        Unit<T>& unit = *this;
        return unit.DoCreate(Type2Type<T>());
    }
};
 
template <typename ConcreteProduct, typename Base, std::size_t Index>
class ConcreteFactoryUnit : public Base
{
    using BaseProductList = typename Base::ProductList;
    static constexpr std::size_t ProductSize = std::tuple_size<BaseProductList>::value;
public:
 
    using AbstractProduct = std::tuple_element_t<ProductSize - Index - 1, BaseProductList>;
 
    std::unique_ptr<AbstractProduct>
    DoCreate(Type2Type<AbstractProduct>) override
    {
        return std::make_unique<ConcreteProduct>();
    }
};
 
template <typename AbstractFact, template <typename, typename, std::size_t> class Unit,
          typename ... ConcreteProducts>
class ConcreteFactory;
 
template <typename AbstractFact, template <typename, typename, std::size_t> class Unit,
          typename T, typename ... ConcreteProducts>
class ConcreteFactory<AbstractFact, Unit, T, ConcreteProducts...>
        : public Unit<T, ConcreteFactory<AbstractFact, Unit, ConcreteProducts...>, sizeof...(ConcreteProducts)>
{
};
 
template <typename AbstractFact, template <typename, typename, std::size_t> class Unit,
          typename ConcreteProduct>
class ConcreteFactory<AbstractFact, Unit, ConcreteProduct>
        : public Unit<ConcreteProduct, AbstractFact, 0>
{
 
};
 
#endif //ABSTRACTFACTORY_ENEMYHIERARCHYFACTORY_H
main
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
#include <iostream>
#include <memory>
#include "enemy.h"
#include "enemyfactory.h"
 
int main()
{
    using AbstractEnemyFactory =
    AbstractFactory<AbstractFactoryUnit,
    Soldier,
    Monster,
    SuperMonster>;
 
    using EasyFactory =
    ConcreteFactory<AbstractEnemyFactory, ConcreteFactoryUnit,
    SillySoldier,
    SillyMonster,
    SillySuperMonster>;
 
    std::unique_ptr<AbstractEnemyFactory> pFactory{new EasyFactory};
    std::unique_ptr<Enemy> pEnemy = pFactory->Create<Monster>();
    pEnemy->info();
 
    pEnemy = pFactory->Create<Soldier>();
    pEnemy->info();
 
    using HardFactory =
    ConcreteFactory<AbstractEnemyFactory, ConcreteFactoryUnit,
    BadSoldier,
    BadMonster,
    BadSuperMonster>;
 
    pFactory.reset(new HardFactory);
    pEnemy = pFactory->Create<Monster>();
    pEnemy->info();
 
    pEnemy = pFactory->Create<Soldier>();
    pEnemy->info();
}


Добавлено через 39 секунд
Цитата Сообщение от DrOffset Посмотреть сообщение
Если не решишь сам, то вечером покажу примерную реализацию.
Да, хотелось бы увидеть.
0
DrOffset
10698 / 5717 / 1406
Регистрация: 30.01.2014
Сообщений: 9,179
14.09.2016, 22:20 6
Цитата Сообщение от notAll Посмотреть сообщение
Да, хотелось бы увидеть.
Да смысла нет теперь.
Оно почти так же выглядит, как у тебя, только вместо tuple, я использовал свои списки типов.
Их реализацию можно посмотреть здесь.
2
14.09.2016, 22:20
Answers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
14.09.2016, 22:20

ProxyServer поддержка httpS переделка примера
Вообщем на многим известном ресурсе нашел пример using System; using...

Variadic Templates - как обращаться к аргументам variadic-функции?
Всем привет! Наверное, рано мне ещё с моими скудными знаниями в это лезть, но, изучив шаблоны и...

Class is not abstract and doesn't override abstract method destroyApp(boolean)
Занялся програмированием,взял самый простой код &quot;hello.World!&quot;,но в нём было много ошибок,я их...


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

Или воспользуйтесь поиском по форуму:
6
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2019, vBulletin Solutions, Inc.
Рейтинг@Mail.ru