Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> подскажите что плохого в этом проектировании 
:(
    Опции темы
Alek86
Дата 5.11.2007, 23:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



есть такая ситуация.
существует класс Channel, который получается путем разбора строк файла.
у него есть Name и список Event'ов (так называется программа или фильм)

файл должен иметь примерно такой вид:

Код

ch: Интер
06:30 Новости
07:00 Подьем
07:30 Кофе в постель
...
01:20 Х/ф "Горячие тройняшки"


но, поскольку файл пишется человеком, то возможны опечатки и какая-то строка не будет подходить под общий вид Event'а, и поэтому будет считаться мусором (Garbage). Но и мусор мне также нужно хранить, чтобы человек его мог исправить.

Иерархия у меня такова:

Код

class IPart {/*реализация*/};
class Event : public IPart {/*реализация*/};
class Garbage : public IPart {/*реализация*/};
class Channel {
    /*реализация*/
    std::vector<shared_ptr<IPart> > m_Parts;
    /*реализация*/
};


для того, чтобы вывести Channel в виде строки я использую полиморфизм и вызываю функцию
Код

    std::string IPart::ToString();

для каждого элемента контейнера по очереди

но если мне нужно в классе Channel повызывать функцию, к примеру
Код

    void Event::GetTime(byte* bH, byte* bM);

для всех событий из списка, я хочу использовать dynamic_cast. Но мне тут сказали, что, скорее всего, я где-то заблуждаюсь...

Ну вот и сам вопрос - заблуждаюсь ли я где-то здесь? smile


ЗЫ Если чето неясно, уточню. К функциям не придираться, в реальности они чуть более оптимизированны.


--------------------
user posted image    user posted image
PM MAIL   Вверх
JackYF
Дата 6.11.2007, 02:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 18
Всего: 162



Цитата(Alek86 @  5.11.2007,  23:14 Найти цитируемый пост)
Но мне тут сказали, что, скорее всего, я где-то заблуждаюсь...

Очень точная фраза :\. smile

А так вообще - проектирование как проектирование. Можно сделать и по-другому, наверняка, но имеет, имхо, право на жизнь.


--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
Alek86
Дата 6.11.2007, 08:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



Цитата(JackYF @  6.11.2007,  02:06 Найти цитируемый пост)
Очень точная фраза

постараюсь поточнее:
Цитата(archimed7592 @  5.11.2007,  22:45 Найти цитируемый пост)
Насколько я понял задачу, dynamic_cast тут не приштопай, не пришей


если кому не жалко времени - как нужно сделать лучше (проще)?



--------------------
user posted image    user posted image
PM MAIL   Вверх
MAKCim
Дата 6.11.2007, 10:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 52
Всего: 207



Alek86, 
в IPart описать метод, который возвращает уникальное число, идентифицирующее класс объекта
в Channel вызывать его и сравнивать результат с числом, идентифицирующим нужный класс
думаю, будет эффективнее


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
UnrealMan
Дата 6.11.2007, 11:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 722
Регистрация: 30.3.2006

Репутация: 27
Всего: 32



Цитата(Alek86 @  5.11.2007,  23:14 Найти цитируемый пост)
для всех событий из списка, я хочу использовать dynamic_cast

Ты так и не объяснил, зачем тебе нужен dynamic_cast smile

Цитата(MAKCim @  6.11.2007,  10:17 Найти цитируемый пост)
в IPart описать метод, который возвращает уникальное число, идентифицирующее класс объекта
в Channel вызывать его и сравнивать результат с числом, идентифицирующим нужный класс
думаю, будет эффективнее 

Если имеется в виду имитация RTTI посредством виртуальных вызовов, то добиться таким трюком прироста производительности можно разве что при кривом компиле, который неэффективно реализует RTTI smile Например, на MinGW я разницы не заметил (правда, сравнивал не с dynamic_cast, а с typeid).
PM MAIL   Вверх
MAKCim
Дата 6.11.2007, 12:22 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 52
Всего: 207



Цитата(UnrealMan @  6.11.2007,  11:52 Найти цитируемый пост)
Если имеется в виду имитация RTTI посредством виртуальных вызовов, то добиться таким трюком прироста производительности можно разве что при кривом компиле, который неэффективно реализует RTTI

обоснуй
GCC, к примеру, генерирует вот такой код (для вызова виртуального метода)
Код

...
; в EDX - указатель типа базового класса на объект производного класса
mov eax, dword ptr [edx] ; получаем указатель на таблицу виртуальных методов
add eax, OFFSET ; OFFSET - смещение в таблице, по которому находится адрес нужного метода
push edx ; this
jmp dword ptr [eax] ; вызов метода
...

код крайне эффективный на самом деле
RTTI можно реализовать быстрее?
соглашусь, если приведешь описание реализации в каком-нибудь компиляторе

Это сообщение отредактировал(а) MAKCim - 6.11.2007, 12:24


--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
Alek86
Дата 6.11.2007, 12:43 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



Цитата(UnrealMan @  6.11.2007,  11:52 Найти цитируемый пост)
Ты так и не объяснил, зачем тебе нужен dynamic_cast 


чтобы циклом пройтись по контейнеру и преобразовать IPart в Event, чтобы вызвать Event::GetTime


Цитата(MAKCim @  6.11.2007,  10:17 Найти цитируемый пост)
в IPart описать метод, который возвращает уникальное число, идентифицирующее класс объектав Channel вызывать его и сравнивать результат с числом, идентифицирующим нужный классдумаю, будет эффективнее


то есть, на моем месте примерно такой бы "проект" у проги и был? ведь, ка я понял, суть такая же, как и у динамик каста....


--------------------
user posted image    user posted image
PM MAIL   Вверх
UnrealMan
Дата 6.11.2007, 21:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 722
Регистрация: 30.3.2006

Репутация: 27
Всего: 32



Цитата(MAKCim @  6.11.2007,  12:22 Найти цитируемый пост)
обоснуй

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

Цитата(MAKCim @  6.11.2007,  12:22 Найти цитируемый пост)
GCC, к примеру, генерирует вот такой код (для вызова виртуального метода)

Чем строить голые теории, лучше просто замерить время, затрачиваемое на сравнение по typeid и на сравнение по id, возвращённому виртуальной функцией.

Вот грубый замер:

Код

#include <iomanip>
#include <iostream>
#include <windows.h>

typedef void (*TypeId)();

template <class T>
    struct TypeInfo
{
    static void Id() {}
};

struct Base
{
    virtual ~Base() {}
    virtual TypeId GetTypeId() { return &TypeInfo<Base>::Id; }
};

struct Derived : Base
{
    virtual TypeId GetTypeId() { return &TypeInfo<Derived>::Id; }
};

int main()
{
    const long n = 2000000000;

    DWORD time, t1, t2, drift;

    Derived derived;
    Base &base = derived;

    time = GetTickCount();
    for (long i=0; i<n; ++i)
    {
        if (typeid(base)!=typeid(Derived))
            return 0; // never return
    }
    t1 = GetTickCount() - time;

    time = GetTickCount();
    for (long i=0; i<n; ++i)
    {
        if (base.GetTypeId()!=&TypeInfo<Derived>::Id)
            return 0; // never return
    }
    t2 = GetTickCount() - time;

    time = GetTickCount();
    for (long i=0; i<n; ++i);
    drift = GetTickCount() - time;
    if (drift<10)
        std::cout << "the drift was not eliminated" << std::endl;

    // во сколько раз сравнение через виртуальный вызов быстрее сравнения через typeid
    std::cout << std::setprecision(2) << double(t1-drift)/(t2-drift) << std::endl;
}

У меня выводится 0.92 smile


Это сообщение отредактировал(а) UnrealMan - 6.11.2007, 21:10
PM MAIL   Вверх
archimed7592
Дата 6.11.2007, 21:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Ыыы, Alek86, ты в теме в которой грозишься создать другую тему предупреждай, если создаёшь smile.

Цитата(MAKCim @  6.11.2007,  10:17 Найти цитируемый пост)
в IPart описать метод, который возвращает уникальное число, идентифицирующее класс объекта
в Channel вызывать его и сравнивать результат с числом, идентифицирующим нужный класс
думаю, будет эффективнее 

Один фиг, что dynamic_cast, что это число smile. Только dynamic_cast будет работать стабильно а возвратить число можно "забыть"(или ещё как-нибудь закосячить) smile.


По теме:
1. возвращать "плохое" время в случае, если это мусор.
2. добавить возможность(если её нет) редактирования(исправления ошибок) не только мусора, но и нормальных событий(человек может написать нормально оформленный файл, но ошибиться в имени фильма, к примеру).

Тогда надобность в интерфейсе и, соответственно, в dynamic_cast'ах исчезнет.

Добавлено через 2 минуты и 6 секунд
К слову, мне сейчас много приходится работать с интерфейсами, но dynamic_cast'ами не пользуюсь, ибо, либо интерфейс включает в себя всё необходимое для взаимодействия с объектом, либо нужны разные интерфейсы/сущности(либо интерфейсы не нужны вообще).


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
Alek86
Дата 6.11.2007, 22:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



Цитата(archimed7592 @  6.11.2007,  21:50 Найти цитируемый пост)
 ты в теме в которой грозишься создать другую тему предупреждай, если создаёшь

звыняюсь, забылся

дело-то все в том, что эти классы нужны в 2х случаях:

1. показывать ошибки человеку. Для этого надло преобразовывать в строку и кидать в ричэдит

2.
 а) проверять "логику". к примеру, отсортировать события по времени 
 б) преобразовывать то, что он начепятал, в нужный мне формат (бинарный файл)
для этого нужно манипулировать std::string'ами и byte'ами

имхо, самое "естесственное" решение тут - это чтобы 1 класс (Event) хранил в себе данные, а имел 2 интерфейса для отображения в этих 2х случаях...

может, ты подскажешь, как в этом нетрудном примере (3 класса) ты бы спроектировал прогу? хоть на пальцах, чтоб я понял, ато 
Цитата(archimed7592 @  6.11.2007,  21:50 Найти цитируемый пост)
либо интерфейс включает в себя всё необходимое для взаимодействия с объектом, либо нужны разные интерфейсы/сущности(либо интерфейсы не нужны вообще).

уж очень обтекаемо ((


--------------------
user posted image    user posted image
PM MAIL   Вверх
archimed7592
Дата 6.11.2007, 22:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Цитата(Alek86 @  6.11.2007,  22:01 Найти цитируемый пост)
1. показывать ошибки человеку. Для этого надло преобразовывать в строку и кидать в ричэдит

bool hasMistake();

Цитата(Alek86 @  6.11.2007,  22:01 Найти цитируемый пост)
а) проверять "логику". к примеру, отсортировать события по времени 

При сортировке выкидывать те которые has mistake.

Цитата(Alek86 @  6.11.2007,  22:01 Найти цитируемый пост)
б) преобразовывать то, что он начепятал, в нужный мне формат (бинарный файл)
для этого нужно манипулировать std::string'ами и byte'ами

Очень даже вписывается в предыдущие два пункта.


Цитата(Alek86 @  6.11.2007,  22:01 Найти цитируемый пост)
имхо, самое "естесственное" решение тут - это чтобы 1 класс (Event) хранил в себе данные, а имел 2 интерфейса для отображения в этих 2х случаях...

Вопрос дня: а зачем нужны аж два интерфейса? Предполагаются другие реализации этого класса?


Цитата(Alek86 @  6.11.2007,  22:01 Найти цитируемый пост)
может, ты подскажешь, как в этом нетрудном примере (3 класса) ты бы спроектировал прогу?

Опа а 3 класса откуда взялось? smile

Короче говоря, попробуй описать логику более полно, но не особо вдаваяся в ненужные подробности. Думаю ответ до тебя дойдёт сам собой, но, если не осенит, то мы обязательно тебе подскажем smile.


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
Alek86
Дата 6.11.2007, 22:33 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



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

к примеру
Цитата(archimed7592 @  6.11.2007,  22:18 Найти цитируемый пост)
bool hasMistake();


не выйдет, так как пользователю инфа выдается в ричэдите, где ошибки выделены красным. а само событие "в реале" состоит их времени и имени, причем в запись времени также может вкрасться ошибка ("25:34")тогда красным выделится только "25". и так далее. то есть нужно из класса получать строку и какую-то структуру с указанием, в каких местах в этой строке ошибки, а не просто "ошибка есть".


Цитата(archimed7592 @  6.11.2007,  22:18 Найти цитируемый пост)
 а зачем нужны аж два интерфейса? Предполагаются другие реализации этого класса?

не в том дело. дело в том, что в реале и сам Channel является релизацией интерфейса IPart, поскольку есть еще и список каналов smile


Цитата(archimed7592 @  6.11.2007,  22:18 Найти цитируемый пост)
Опа а 3 класса откуда взялось?

Код

class Event : public IPart;
class Garbage : public IPart;
class Channel;



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


--------------------
user posted image    user posted image
PM MAIL   Вверх
archimed7592
Дата 6.11.2007, 22:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Архимед
****


Профиль
Группа: Завсегдатай
Сообщений: 2531
Регистрация: 12.6.2004
Где: Moscow

Репутация: 58
Всего: 93



Цитата(Alek86 @  6.11.2007,  22:33 Найти цитируемый пост)
не выйдет, так как пользователю инфа выдается в ричэдите

Цитата(Alek86 @  6.11.2007,  22:33 Найти цитируемый пост)
то есть нужно из класса получать строку и какую-то структуру с указанием, в каких местах в этой строке ошибки, а не просто "ошибка есть".

А нельзя сразу вытягивать отформатированную строку(с указаниями ошибок, если нужно)?


Цитата(Alek86 @  6.11.2007,  22:33 Найти цитируемый пост)
не в том дело. дело в том, что в реале и сам Channel является релизацией интерфейса IPart, поскольку есть еще и список каналов smile

Нее, что-то тут не ладно... Ты не по тому признаку обобщал smile.

Цитата(Alek86 @  6.11.2007,  22:33 Найти цитируемый пост)
в общем, итог, по-видимому, таков. если я опишу всю проблему, даже без мелочей, то проект для ее решения будет очень немелкий. smileтак что не стОит smile. спасибо за труды smile 

Дам последнее напутствие.

В том виде в каком это у тебя есть сейчас(все являются наследниками IPart) - это паттерн Композиция(если немного видоизменить). По сути, к нему можно очень просто прикрутить Визитора, но там как-раз таки dynamic_cast'ы повсюду smile.

В общем, решай сам. Либо у тебя будут перенасыщенные интерфейсы, либо тебе придётся применять dynamic_cast, либо тебе придётся перепроектировать.


зы. Неужели так много телепрограмм, что падает производительность из-за применения shared_ptr/dynamic_cast? 0_o


--------------------
If you have an apple and I have an apple and we exchange apples then you and I will still each have one apple. But if you have an idea and I have an idea and we exchange these ideas, then each of us will have two ideas.
© George Bernard Shaw
PM Jabber   Вверх
MAKCim
Дата 6.11.2007, 22:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Воін дZэна
****


Профиль
Группа: Экс. модератор
Сообщений: 5644
Регистрация: 10.12.2005
Где: Менск, РБ

Репутация: 52
Всего: 207



UnrealMan, 
а если упростить код?
Код

struct Base
{
    virtual ~Base() {}
    virtual int GetTypeId() { return 0; }
};
struct Derived : Base
{
    virtual int GetTypeId() { return 1; }
};
...
for (long i=0; i<n; ++i)
    {
        if (base.GetTypeId() != 1)
            return 0; // never return
    }



--------------------
Ах, у елі, ах, у ёлкі, ах, у елі злыя волкі ©

PM MAIL   Вверх
Alek86
Дата 7.11.2007, 00:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1299
Регистрация: 30.1.2007
Где: Киев

Репутация: 21
Всего: 25



Цитата(archimed7592 @  6.11.2007,  22:44 Найти цитируемый пост)
Неужели так много телепрограмм, что падает производительность из-за применения shared_ptr/dynamic_cast


не так уж и много... пока месть... вообще вопрос про падение производительности я задал не имея в виду именно этот случай. хотелось просто узнать, является ли динамик каст чем-то таким, чем не рекомендуется пользовать из-за падения производительности. А общий указатель приплюсовался в качестве довеска. а к этому случаю в том обсуждении само как-то пришло... smile

Цитата(archimed7592 @  6.11.2007,  22:44 Найти цитируемый пост)
Нее, что-то тут не ладно... Ты не по тому признаку обобщал

потому я и "закрыл" тему, поскольку хрен я смогу объяснить что именно по тому признаку, что нужно smile слишком много для этого рассказывать, а смысла в этом мало. главное, что убедился, что ничего криминального в проекте нету
так что спасибо всем за ответы

Это сообщение отредактировал(а) Alek86 - 7.11.2007, 00:03


--------------------
user posted image    user posted image
PM MAIL   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0664 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.