Войти
ПрограммированиеФорумОбщее

С++ баг!! стандартный или MS-specific ? (4 стр)

Advanced: Тема повышенной сложности или важная.

Страницы: 1 2 3 4 5 6 7 Следующая »
#45
2:45, 9 фев. 2010

San
> У меня по умолчанию стоит 4-й уровень. Ни одного варнинга. ЧЯДНТ? :)
все правильно делаешь. я уже почистил 1/20 часть проекта от ворнингов, стоко тебя догоню =))


#46
8:44, 9 фев. 2010

San
> У меня по умолчанию стоит 4-й уровень. Ни одного варнинга. ЧЯДНТ? :)
Иначе и быть не должно.

#47
12:52, 9 фев. 2010

Kloun
> ИМХО в таком случае на этапе компиляции должна создаваться промежуточная
> функция, в которой результат приводится, и ссылка на нее указыватся в таблицу
> методов для базавого класса. гцц наверно так и делает, раз у него все работает.
да, так можно реализовать, правда пенальти получается очень приличный

Kloun
> > если вы поменяете порядок наследования,
> всмысле? наследовать базовый класс от дочернего? порядок наследования
> определяется архитектурой.
в смысле наследоваться сначала от ObjectImp, а потом от IObjectModel

Kloun
> ashujon
> > Советую такой подход выбросить, проектирование объектов, их разделение на
> > бессмысленные части лишь бы не повторить одну строчку дважды - так делать
> > нельзя
> 0й пост читал? там по коду по-моему очевидно для чего такая структура
> наследования. если не понятно спроси конкретней, если есть альтернативный
> вариант - с удовльствием выслушаю.
мне тоже не совсем понятно, зачем нужен интерфейс IObjectModel. не лучше ли было
бы сделать интерфейс IModel и всех тех, кто наследовался от IObjectModel, наследовать
от IObject и IModel? заодно и от виртуального наследования избавились бы, что в вашем
случае привело бы и к более эффективному коду.

#48
13:18, 9 фев. 2010

Дмитрий Ясенев
> мне тоже не совсем понятно, зачем нужен интерфейс IObjectModel

Объясню (в проекте чуть по-другому, там еще дополнительные заморочки)
1) Есть базовый ILocationObject - объект, который располагается налокации (для него есть операции - перемещение\вращение, копирование, получение\установка игровых свойств)
2) Есть три основных типа объектов, котоыре располагаются на локации - это обычная статика (IObjectModel), частицы (IObjectParticle), источник света (IObjectLight).
3) Из "внешней", по отношению к движку (двиг - dll), программы, при клике мышкой, например, мы получаем ссылку на ILocationObject. также можем получить список всех объектов на локации (опятьже ввиде ILocationObject). и с этой ссылкой мы работаем при перемещении объекта, назначении\чтении игровых свойств и т.п.
4) Также из "внешней" программы для нас иногда возникает необходимость получить доступ к специфическим полям\методам модели\частиц\источника света. например получить имя файла модели, подменить файл модели (есть массовая замена одних моделей на другие), установить тип источника света (точечный\spot-light и т. д.). для этого IObjectModel, IObjectParticle, IObjectLight наследуются от ILocationObject (ILocationObject содержит методы ConvertTo* вместо звездочки Model\Particle\Light, которые переопределяются в соотвествующих реализациях)
факт наследования во внешней программе используется вроде только для биндинга этих объектов в луа. можно конечно от этого избавится, но получится, что всякий раз, имея ссылку на IObjectModel (например), мы не сможем обращаться к методам ILocationObject, без дополнительной конвертации. (хрен с ним с дополнительными 6-ю методами перевода указатель из IObject* в ILocationObject - главное использовать не так удобно)

внешней программе мы предоставляем иерархию ILocationObject->IObject*
в двиге есть реализация класса ILocationObject - LocationObjectImp. А также реализации для IObject* - Object*Imp. Очевидно, что LocationObjectImp наследуется от ILocationObject, а ObjectModelImp от IObjectModel и от LocationObjectImp. получается ObjectModelImp наследуется от ILocationObject дважды - через IObjectModel и через LocationObjectImp - вот по этому и виртуальное неследование.

#49
13:19, 9 фев. 2010

Дмитрий Ясенев
> и всех тех, кто наследовался от IObjectModel, наследовать
> от IObject и IModel?
Ага. и каждый раз повторять реализацию IObject ? а там не три строчки. да и дублирование кода - это куда страшнее грабли чем виртуальное наследование

#50
14:05, 9 фев. 2010

Kloun
> Дмитрий Ясенев
> > и всех тех, кто наследовался от IObjectModel, наследовать
> > от IObject и IModel?
> Ага. и каждый раз повторять реализацию IObject ? а там не три строчки. да и
> дублирование кода - это куда страшнее грабли чем виртуальное наследование
я предполагал, что IObject и IModel - интерфейсы, в таком случае дублирования кода не происходит

Updated: или вы имеете в виду, что IObjectModel не является интерфейсом и реализует часть методов IObject?

#51
14:38, 9 фев. 2010

Дмитрий Ясенев
> я предполагал, что IObject и IModel - интерфейсы, в таком случае дублирования
> кода не происходит
IObject и IObjectModel - интерфейсы. реализация IObject - в ObjectImp, реализация IObjectModel - в ObjectModelImp. Описание классов ObjectImp и ObjectModelImp не могут быть доступны внейшей программе. т.е цепочка IObject <= ObjectImp <= IObjectModel <= ObjectModelImp - тоже не может быть доступна. для внешний програмы цепочка IObject <= IObjectModel. для движка получается такая

IObject       <=       IObjectModel
IObject <= ObjectImp <= IObjectModel <= ObjectModelImp 
дублирование кода произойдет если будет такая цепочка (т.е. несколько цепочек приведено)
IObject <= IObjectModel <=ObjectModelImp
IObject <= IObjectParticle <=ObjectParticleImp
IObject <= IObjectLight <=ObjectLightImp
тут нету виртуального наследования, но ObjectModelImp? ObjectParticleImp, ObjectLightImp - каждый из них должен включать в себя реализацию IObject. либо они должны наследоваться от ObjectImp, но в таком случае выходит первая цепочка (ObjectImp может наследоваться только IObject, она не может одновремено наследоваться от IObjectModel и от IObjectParticle и от IObjectLight)


> Updated: или вы имеете в виду, что IObjectModel не является интерфейсом и
> реализует часть методов IObject?

нет

#52
14:49, 9 фев. 2010

Kloun
Много написал...
Создаётся впечатление, что сам недоволен своей реализацией. Не стоит идти на поводу у проблемы.

Моё видение подобных раскладов следующее:
Вы пытаетесь объединить несколько разнородных сущностей в одну (если бы оно было монолитной сущностью, то было бы реализовано в одном классе). Отсюда потребность в интерфейсах и, ИМО, неудобная иерархия, и, до кучи, много потенциальных проблем, если не сейчас, то при портировании кода (опять же ИМО).

Когда-то давно в недрах цитадели добра Майкрософт раскурили некие мегаумы библиотеку ATL (хотя... я не в курсе кто и где её раскурил). Библиотека спорная, с этим не спорю. Но в ней есть одна из наиболее удачных (на мой взгляд) реализаций аггрегации. Когда композитный объект собирается не множественным наследованием, а включением компонентов. В ATL реализовано несколько православных идиом, типа отложенного конструирования. Есть и пара недостатков. В частности, непортируемо :(. Потому я написал свой лисапед :).

Собственно, моё решение подобной задачи:
  + Тип конечного объекта определяется его составными функциональными частями.
  + Запрос каждой части может быть осуществлён из любой другой части (некоторый пенальти от виртуальных вызовов, полагаю, будет не выше, чем в вашей реализации). Запрос частей у объекта верхнего уровня бесплатный (шаблонный метод -> вызов съедается оптимизацией).
  + Нет множественного наследования.
  + Нет запутанной иерархии классов.
  + Есть огромное разнообразие сочетаний компонентов, из которых можно собрать хоть "чорта лысого" обычным typedef.
  + Есть отложенное конструирование (компонент не создаётся пока не будет запрошен).
  + Минимальная потребность в интерфейсах и виртуальных методах. Компонент может быть уникальным, если это позволяет логика, его использующая.
  + Реально раскурить, чтоб можно было удалять и добавлять компоненты рантайм, меняя поведение всего объекта.
  + Можно безопасно юзать ряд паттернов и идиом (которые тяжело реализовать при множественном наследовании), потомушта запросить объект нужного типа можно где угодно.

Минусы тоже есть:
  - Чутка больше кода. Но он вполне типобезопасен и без граблей множественного наследования.
  - Возможность получить указатель на часть объекта в другой его части порождает некоторое количество небезопасных ситуаций (впрочем, множественное наследование страдает той же проблемой).
  - Если есть взаимозависимые компоненты, то для полноценного их конструирования нужен механизм отложенного связывания. Для множественного наследования вообще нереальная тема, так как порядок вызова конструкторов определяется компилятором.

#53
15:36, 9 фев. 2010

vonrims
> Вы пытаетесь объединить несколько разнородных сущностей в одну
не разнородные они -сущность одна - объект на локации игровой. просто объекты бывают разные - в виде модели, ввиде частиц, ввиде источника света, ввиде черта лысого и т.п.;) это как классический пример наследования из учебников - Shape->(Rectangle, Circle)

ты уже много раз упоминал про производительнось. в даном месте производительность не играет ни какой роли! это интерфейсы управления объектами.

я вкурсе, что всегда виртуальное наследование можно заменить агрекацией - но это не есть красивое решение. и тут надо либо городить дополнительную систему, как сделал ты, либо писать кучу лишнего мелкого дублирующего кода, который в проекте потом хрен вспомнишь где он лежит, если вдруг что-то пофиксить придется.
не очень понимаю я такого подхода - городить монстра, когда есть простые и православные решения. интерфейсы мне нужны, как не крути, так как они являются интерфейсом общения между программой и движком (извините за тавтологию). Более того "черта лысого", мне тоже собирать не надо - IObjectModel - он прсто не существует отдельно, он всегда является объектом локации, и ни как иначе! в ILocationObject содержатся все общие методы работы с объектом, а в дочерних - специфические, и специфический конструктор (т.е. создает он модель или же частицы, или вообще в другую систему освещения добавляет лампочку, но эта лампочка отображается служебным объектом на локации и ее можно также как остальные объекты крутить вертететь и т.п.)
с агрегацией еще наверно вылезет дополнительный класс - контейнер, да и все это лишний код и достаточно объемный, чтобы на нем потерять несколько недель на написание и внедрение и потом переодически вылавливать сопуствующие баги.

#54
15:38, 9 фев. 2010

Kloun
> IObject и IObjectModel - интерфейсы. реализация IObject - в ObjectImp,
> реализация IObjectModel - в ObjectModelImp. Описание классов ObjectImp и
> ObjectModelImp не могут быть доступны внейшей программе. т.е цепочка IObject <=
> ObjectImp <= IObjectModel <= ObjectModelImp - тоже не может быть доступна. для
> внешний програмы цепочка IObject <= IObjectModel. для движка получается такая
теперь стало понятнее :)

а зачем внешней программе знать, что интерфейс IObjectModel наследован от IObject?

даже если это знание необходимо, я бы лично предпочёл следующий вариант:

struct IObject {
    ...
    virtual IModel* get_model() = 0;
};

struct IModel {
    ...
    virtual IObject* get_object() = 0;
};

плюсы:

  • избавились от наследования интерфейсов - каждый интерфейс определяет одну чётко понятную сущность
  • избавились от виртуального наследования
  • иерархия классов стала заметно проще
  • избавились от неэффективного кода
  • минусы:

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

    #55
    15:40, 9 фев. 2010

    От виртуального наследование ИМХО больше мороки чем пользы

    Лучше бы тут сделать специфику отдельными интерфейсами, например
    IModel, ILight, IParticle а в интерфейсе IObject сделать ф-ии доступа до этих частей

    IObject
    {
      virtual IModel   * getModel() = 0;
      virtual ILight     * getLight() = 0;
      virtual IParticle * getParticle() = 0;
    };
    это позволит избавится и от виртуального наследования, и даст возможность реализовать специфику как наследованием так и агрегацией при желании
    class LightImp:public ILight    
    {
    //blablabla
    };
    
    class ObjectLightImp: public ObjectImp, public LightImp
    {
        virtual ILight     * getLight() {return this;}
    }

    #56
    15:41, 9 фев. 2010

    Kloun
    > я вкурсе, что всегда виртуальное наследование можно заменить агрекацией
    на самом деле, нельзя.

    если вам необходимо переопределить виртуальную функцию, то агрегация вам не поможет.
    если вам нужно отношиние Is A, то агрегация вам тоже не поможет.
    если вам необходим доступ к защищённым методам/данным, то агрегация вам по-прежнему не поможет.

    #57
    15:50, 9 фев. 2010

    Kloun
    Что ж. Выбор твой.
    Для меня ценней написать один раз аггрегацию, чем много раз писать множественное наследование.
    Да и монстр не особенно жирный вышел.

    #58
    15:56, 9 фев. 2010

    Дмитрий Ясенев
    > избавились от наследования интерфейсов
    какой в этом плюс? это и есть минус - он у тебя в минусах и записан другими словами.
    >каждый интерфейс определяет одну чётко
    что подразумевается под сущностью? IObject и IObjectModel - это одно сущность! это объект на локации.
    > иерархия классов стала заметно проще
    чем? тем что разорвана одна связь? а классы остались теже самые, просто без виртуального наследвания
    > избавились от неэффективного кода
    где там неэффективный код

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

    пусть даже допустим я перейду на аггрегацию. вот еще: IObject должен конвертится к IObjectModel, IObjectParticle, IObjectLight, ну с ними ладно, от них не избавится, очень не приятно то, что конвертацию к IObject (по сути одинаковую для всех трех объектов) придется писть в трех местах разных (в реализации каждого из этих трех классов). вобщем в данном случае виртуальное наследование явно логинчее чем аггрегация, и вообще один объект я хочу создавть одним new =))

    ps
    думаю разговор стоить завершить. врядли вы придумаете чего-то новое. а дискутировать на тему виртуальное наследование vs аггрегация я не хочу - гдето логнично одно, а где-то другое.

    #59
    15:58, 9 фев. 2010

    Дмитрий Ясенев
    > если вам необходимо переопределить виртуальную функцию, то агрегация вам не
    > поможет.
    Её нужно переопределить у наследника одного из функциональных компонентов. Не надо наследовать весь объект.

    Дмитрий Ясенев
    > если вам нужно отношиние Is A, то агрегация вам тоже не поможет.
    Сможете обойтись без, код будет красивей.

    Дмитрий Ясенев
    > если вам необходим доступ к защищённым методам/данным, то агрегация вам
    > по-прежнему не поможет.
    Что поможет правильно спроектировать каждый компонент. Они же могут существовать независимо. Быть составными частями различных по функционалу объектов.

    Страницы: 1 2 3 4 5 6 7 Следующая »
    ПрограммированиеФорумОбщее

    Тема в архиве.