Форум программистов «Весельчак У»
  *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

  • Рекомендуем проверить настройки временной зоны в вашем профиле (страница "Внешний вид форума", пункт "Часовой пояс:").
  • У нас больше нет рассылок. Если вам приходят письма от наших бывших рассылок mail.ru и subscribe.ru, то знайте, что это не мы рассылаем.
   Начало  
Наши сайты
Помощь Поиск Календарь Почта Войти Регистрация  
 
Страниц: 1 2 3 [Все]   Вниз
  Печать  
Автор Тема: Организация общих данных в модуле  (Прочитано 47812 раз)
0 Пользователей и 1 Гость смотрят эту тему.
ezus
Опытный

il
Offline Offline

« : 18-05-2010 07:47 » 

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

Итак имеем
1. Структуру системного вектора, содержащего указатели на отдельные модули системы
Код:
struct ZSysVector
{
ZGui*  _gui;
ZReports*  _reports;
....
AProject*  _prj;
}
Главной идеей системного вектора - локализация описания среды исполнения кода.
Польза: унификация инициализации модулей, сокращение числа передоваемых параметров, сокращение числа интерфейсных прозрачных функций в головных модулях, нет необходимости в многочисленных мелких изменениях при изменении среды.
Недостаток: Отсутствие явного указания в коде программы связей между модулями.

Есть еще один фактор - дань личным традициям.

2. Необходимо разработать новую подсистему (Simulation), которой требуется добавить к системному вектору пару переменных.

Раньше я просто бы добавил эти переменные в системный вектор, но:
а) в больших системах системный вектор разрастается до неприятных размеров
б) есть очень красивое понятие инкапсуляция, и не хотелсь бы от него отказываться.
Поэтому мне показалось естественным использовать наследование
Код:
struct ZSysVectorSimulation : public ZSysVector
{
SRand*  _rand;
SMainTree*  _tree;
}
В этом случае мы унифицируем обращение к внешним модулям из внутреннего кода, и внутри модуля нам нет необходимости знать структуру всей программы.

В чем здесь ошибка, и где нарушение логики дизайна?

3. Возможны и другие варианты
Например
Проще некуда
struct Sb
{
   Sa aa;
   int ib;
};
или
создать отдельный вектор для каждого модуля
или
...
Но все известные мне варианты не соответствуют отмеченным выше критериям.

4. Естественно при инициализации новой структуры ZSysVectorSimulation и возникла проблемы, вынесенная в заголовок данной темы.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #1 : 18-05-2010 07:51 » 

инициализировать можно через список инициализации конструктора

Код:
struct ZSysVectorSimulation : public ZSysVector
{
SRand*  _rand;
SMainTree*  _tree;

ZSysVectorSimulation():ZSysVector(...параметры для передачи в конструктор ZSysVector...)//,_rand(0),_tree(0)
{
}
}


« Последнее редактирование: 18-05-2010 07:52 от Алексей1153++ » Записан

Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #2 : 18-05-2010 08:09 » 

Главной идеей системного вектора - локализация описания среды исполнения кода.
Слишком много существительных Улыбаюсь Можно поподробнее, для чего это делается? Если модули независимые - то зачем их держать в какой-то одной структуре? Если кто-то внешний управляет их временем жизни - почему бы этого кого-то не инкапсулировать в объект - менеджер модулей?
Или, может быть, это все модули знают про такую структуру, и через неё обращаются к другим модулям?

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

Цитата
б) есть очень красивое понятие инкапсуляция, и не хотелсь бы от него отказываться.
Поэтому мне показалось естественным использовать наследование
Где здесь инкапсуляция? struct - это, прошу прощения за тавтологию, открытая структура, здесь ничто никуда не прячется.
« Последнее редактирование: 18-05-2010 08:10 от Вад » Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #3 : 18-05-2010 10:05 » 

Цитата: ezus
Главной идеей системного вектора - локализация описания среды исполнения кода.
Ну пусть - компромисс между локальными и глобальными переменными.

Цитата: ezus
Польза: унификация инициализации модулей, сокращение числа передоваемых параметров, сокращение числа интерфейсных прозрачных функций в головных модулях, нет необходимости в многочисленных мелких изменениях при изменении среды.
Вот это уже не вполне соответствует действительности. Для унификации должна быть унифицированная сущность. Например, некая структура Module, и единый код, работающий с разными экземплярами этой сущности. В противном случае вся эта "унификация" на самом деле не унификация, а набор системных функций - по отдельной функции на каждую возможную конфигурацию.

Цитата: ezus
Раньше я просто бы добавил эти переменные в системный вектор, но:
а) в больших системах системный вектор разрастается до неприятных размеров
б) есть очень красивое понятие инкапсуляция, и не хотелсь бы от него отказываться.
Поэтому мне показалось естественным использовать наследование
Про инкапсуляцию Вад уже сказал. Остальное понятно в том смысле, что такие решения именно с такими родовыми травмами встречаются и нередко; но непонятно, зачем каково конечное назначение этих решений.

Я правильно понимаю, что разные части программы нуждаются в разных подмножествах модулей из этого вектора?

Но пусть даже так. Теперь вот это:
Цитата: ezus
Естественно при инициализации новой структуры ZSysVectorSimulation и возникла проблемы, вынесенная в заголовок данной темы.
Потому что наследование используется не по назначению. Именно вариант с агрегацией (вложенной структурой) в данном случае является самым адекватным. Поскольку позволяет как раз добиться инкапсуляции. Внутри твоего нового модуля может использоваться новая структура, а вне модуля должна использоваться только старая (которая вложенная) структура, поскольку все внешние части системы про твою новую структуру не знают и умеют работать только со старой структурой. И если всё аккуратно расписать, никогда не возникнет ошибки, про которую я написал выше - когда поля структуры-потомка при операциях копирования пропускаются, теряются, не инициализируются, и в них оказывается мусор.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #4 : 18-05-2010 10:25 » 

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

Код: (C++)
#include <cstdlib>
#include <cstdio>

namespace OldSystem
{

    // C-style solution.

    struct Session
    {
        int id;
    };
   
    Session *openNewSession()
    {
        Session *session = (Session *)malloc(sizeof(Session));
        if(session != NULL)
        {
            session->id = rand();
        }
        return session;
    }
   
    void action(Session *session)
    {
        if(session != NULL)
        {
            printf("%i\n", session->id);
        }
    }
   
    void closeSession(Session *session)
    {
        if(session != NULL)
        {
            free(session);
        }
    }
}

namespace NewSystem
{
    // C-style solution.
   
    struct Session
    {
        OldSystem::Session *base;
        int userID;
    };
   
    Session *openNewSession()
    {
        Session *session = NULL;
        OldSystem::Session *base = OldSystem::openNewSession();
        if(base != NULL)
        {
            session = (Session *)malloc(sizeof(Session));
            if(session != NULL)
            {
                session->base = base;
                session->userID = rand();
            }
        }
        return session;
    }
   
    void action(Session *session)
    {
        if(session != NULL)
        {
            OldSystem::action(session->base);
            printf("%i\n", session->userID);
        }
    }
   
    void closeSession(Session *session)
    {
        if(session != NULL)
        {
            OldSystem::closeSession(session->base);
            free(session);
        }
    }
}

int main()
{
    NewSystem::Session *session = NewSystem::openNewSession();
    if(session != NULL)
    {
        NewSystem::action(session);
        NewSystem::closeSession(session);
    }
    return 0;
}
« Последнее редактирование: 18-05-2010 10:30 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #5 : 18-05-2010 13:02 » 

Все замечания очень похожи, и это говорить скорее о Вашей правоте, чем о моей.
Но....
Я сторонник ИДЕЙ ООП, но не самого ООП, особенно в исполнении С++. Поэтому аргументы типа "так принято в ООП" для меня не аргументы.

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

Теперь подробнее:
инициализировать можно через список инициализации конструктора
Код:
struct ZSysVectorSimulation : public ZSysVector
{
SRand*  _rand;
SMainTree*  _tree;

ZSysVectorSimulation():ZSysVector(...параметры для передачи в конструктор ZSysVector...)//,_rand(0),_tree(0)
{
}
}
На моменте создания ZSysVectorSimulation основной ZSysVector уже существует, и мне хотелось минимальными усилиями скопировать содержимое ZSysVector в новый ZSysVectorSimulation. При этом я не хочу знать, что в ZSysVector входит - все что там есть, давай сюда. В этом случае будующие пополнения ZSysVector меня не интересуют, они будут скопированы автоматически. Поэтому данное предложение мне не подходит.

Слишком много существительных Улыбаюсь Можно поподробнее, для чего это делается? Если модули независимые - то зачем их держать в какой-то одной структуре? Если кто-то внешний управляет их временем жизни - почему бы этого кого-то не инкапсулировать в объект - менеджер модулей?
Как я уже сказал, модули рождаются в разных местах и по разным поводам, и поэтому обединение процедур их создания в единую фабрику не кажется мне чем-то хорошим.
Цитата
Или, может быть, это все модули знают про такую структуру, и через неё обращаются к другим модулям?
Да, именно в этом идея системного вектора.
Цитата
В связи с первым вопросом, непонятно также, для чего Simulation такая структура, требующая доступ к экземплярам всех модулей. Simulation как-то расширяет имеющуюся функциональность? Делает что-то специфическое с каждым модулем?
На это я вроде ответил выше.
Цитата
Где здесь инкапсуляция? struct - это, прошу прощения за тавтологию, открытая структура, здесь ничто никуда не прячется.
Почему же? В С++ struct - это тот же класс, только с открытыми членами. Хотя согласен, что термин "инкапсуляция" здесь не совсем уместен. Здесь это скорее не сокрытие от других, а удобное средство суперпозиции данных.

Ну пусть - компромисс между локальными и глобальными переменными.
Да, согласен.

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

Цитата
Остальное понятно в том смысле, что такие решения именно с такими родовыми травмами встречаются и нередко; но непонятно, зачем каково конечное назначение этих решений.
Я все еще не ответил?

Цитата
Я правильно понимаю, что разные части программы нуждаются в разных подмножествах модулей из этого вектора?
Да. Но я не вижу, чем могут помешать лишние данные. Кроме того. если в дальнейшем потребуется обратиться к ранее неиспользованному модулю, то ни каких дополнительных телодвижений не потребуется.
Цитата
Потому что наследование используется не по назначению.

ПОЧЕМУ?

Цитата
Именно вариант с агрегацией (вложенной структурой) в данном случае является самым адекватным. Поскольку позволяет как раз добиться инкапсуляции.
Про инкапсуляцию я уже извинился, а вариант с агрегацией меня не устраивает, потому что каждый конкретный раз я должен знать откуда модуль - из ZSysVectorSimulation или из ZSysVector.
А именно этот излишек требование к знанию я и хочу избежать.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #6 : 18-05-2010 14:13 » 

Цитата
На моменте создания ZSysVectorSimulation основной ZSysVector уже существует, и мне хотелось минимальными усилиями скопировать содержимое ZSysVector в новый ZSysVectorSimulation. При этом я не хочу знать, что в ZSysVector входит - все что там есть, давай сюда. В этом случае будующие пополнения ZSysVector меня не интересуют, они будут скопированы автоматически. Поэтому данное предложение мне не подходит.
не понимаю. Если у тебя ZSysVectorSimulation паблик от  ZSysVector (читай: содержит в начале себя структуру  ZSysVector ), то всё равно тебе туда копировать извне. Какая разница как? Оператор ли "=", конструктор ли, memmove, чёрт побери ))

Зациклился ты на мелочи, как её решить уже много способов сказано. А тебе, видишь ли, ООП нравится, но ты его не применяешь. Ты пишешь на С++ ? Ну так используй его на всю катушку!
Записан

Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #7 : 18-05-2010 14:39 » 

Цитата: ezus
Я сторонник ИДЕЙ ООП, но не самого ООП, особенно в исполнении С++. Поэтому аргументы типа "так принято в ООП" для меня не аргументы.
И я сторонник идей ООП. Идея классов и логического отношения род-вид между ними описана в работе Аристотеля "Категории". Надеюсь, Аристотеля ты не подозреваешь в симпатиях к самому ООП, реализованному в C++? Улыбаюсь

Цитата: ezus
В этом случае будующие пополнения ZSysVector меня не интересуют, они будут скопированы автоматически. Поэтому данное предложение мне не подходит.
Ты хочешь ослабить типизацию и добиться того, чтобы во всяком месте копировалась вся структура, как бы она ни была устроена. В пределе это задача копирования произвольного по размеру куска памяти, спрятанного за void *. Для этого тебе как минимум нужно знать размер структуры. В случае присваивания типизированных переменных размер известен благодаря типу. Ты же от типа отказываешься - тогда храни размер вручную (либо в самой структуре, либо заведи идентификаторы типов и создай хэш из пар тип-размер), полиморфизм объектов в ООП в подавляющем большинстве языков реализуется именно так, только для этого задействуется RTTI, и вся работа перекладывается на компилятор.

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

Цитата: ezus
Здесь это скорее не сокрытие от других, а удобное средство суперпозиции данных.
Нет, в C++ - это не "средство суперпозиции данных". Упомянутые средства имеются в других языках программирования и называются примесями - отдалённым их аналогом является импорт пространств имён. Но наследование служит для специализации, перехода по дедукции от общего к частному, а не для "подцепления вагонов к поезду". И именно поэтому у тебя оно не работает так, как тебе хочется.

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

Цитата: ezus
В моем случае это унификация использования сервисных модулей.
В твоём случае это называется архитектурой. Соглашением о том, что модули будут организованы так-то, и все разработчики обязаны это учитывать.

Цитата: ezus
Да. Но я не вижу, чем могут помешать лишние данные. Кроме того. если в дальнейшем потребуется обратиться к ранее неиспользованному модулю, то ни каких дополнительных телодвижений не потребуется.
Раз они не мешают, тогда добавь их в исходную структуру - и дело с концом. Ты же весь огород городить начал именно из-за того, что они чем-то мешали.

Цитата: ezus
потому что каждый конкретный раз я должен знать откуда модуль - из ZSysVectorSimulation или из ZSysVector.
А именно этот излишек требование к знанию я и хочу избежать.
НЕТ! Если ты внимательно посмотришь мой пример, то OldSystem знает только про свой вариант Session, и другие варианты просто не примет. Это значит, что когда NewSession обращается наружу к OldSession, она гарантирует при вызовах передачу только вложенной структуры. А вот внутри NewSession работает со своим новым вариантом структуры. Аккуратное соблюдение типизации (если заметил, у меня нет ни одной операции приведения типов, кроме вызова malloc) является достаточным элементом контроля. Соответствие типов аргументов при вызове функции является предусловием исполнения функции, и в случае несоответствия ошибка возникнет ещё на этапе компиляции.
« Последнее редактирование: 18-05-2010 14:53 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #8 : 18-05-2010 16:20 » 

Слишком много существительных Улыбаюсь Можно поподробнее, для чего это делается? Если модули независимые - то зачем их держать в какой-то одной структуре? Если кто-то внешний управляет их временем жизни - почему бы этого кого-то не инкапсулировать в объект - менеджер модулей?
Как я уже сказал, модули рождаются в разных местах и по разным поводам, и поэтому обединение процедур их создания в единую фабрику не кажется мне чем-то хорошим.

Если они рождаются в разных местах и по разным поводам - то к чему централизация вообще? Пытаясь централизовать данные о модулях, ты получаешь загрязнение пространства имён, потому что каждый модуль вынужден неумышленно знать про все-все другие, если ему понадобится хотя бы один из них. Я уже не говорю о том, что в случае структуры указателей ты должен откуда-то извне строго следить за правильным порядком инициализации модулей и разруливать зависимости.

Я не говорю про фабрику. Коль уж модули - сингельтоны, то можно использовать фабричные методы у самих этих модулей для получения экземпляра. Тогда каждому модулю достаточно знать интерфейс нужных ему, чтобы получить указатель на существующий экземпляр и работать с ним спокойно (тут же можно реализовать и подсчёт ссылок, если потребуется).

Если модуль то является сингельтоном (разделяем несколькими модулями), то нет, или просто неохота "портить шкуру" - добавлять статический фабричный метод в интерфейс - то можно сделать сингельтон-посредник, который де-факто будет иметь статический экземпляр модуля и отдавать его всем желающим.
« Последнее редактирование: 18-05-2010 16:23 от Вад » Записан
sss
Специалист

ru
Offline Offline

« Ответ #9 : 19-05-2010 01:31 » 

Цитата: А.Дюма
Д'Артаньян не в силах был продолжать этот разговор, он чувствовал, что сходит с ума. Он уронил голову на руки и притворился, будто спит. ...
« Последнее редактирование: 19-05-2010 01:33 от sss » Записан

while (8==8)
ezus
Опытный

il
Offline Offline

« Ответ #10 : 19-05-2010 08:35 » 

Ты хочешь ослабить типизацию и добиться того, чтобы во всяком месте копировалась вся структура, как бы она ни была устроена. В пределе это задача копирования произвольного по размеру куска памяти, спрятанного за void *. Для этого тебе как минимум нужно знать размер структуры. В случае присваивания типизированных переменных размер известен благодаря типу. Ты же от типа отказываешься ...
Где я "ослабляю типизацию"? Причем тут "void *" и "произвольный по размеру куска памяти"? От чего я отказался?
У меня есть ПОЛНОСТЬЮ определенная базовая структура, у меня есть ПОЛНОСТЬЮ определенная дочерняя структура. Я всего лишь хочу перенести значение одной базовой структуры в БАЗОВУЮ же часть дочерней. В чем здесь криминал? Какие принципы ООП я нарушил?

Цитата
Другое дело, что ты иерархию типов переворачиваешь с ног на голову. Это всё равно, что пытаться всякое дерево назвать берёзой (поместить в переменную) и потом требовать от него берёзовых свойств.
Где я требую от дерева березовых свойств? Вы мне приписываете что-то непонятное. У меня есть береза. Эта береза, как ни странно, является еще и деревом. Я хочу при создании объекта "береза" переписать в нее ту часть, которая касается ее как дерева. И буду в дальнейшем требовать от этой части только свойств березы как ДЕРЕВА. Что\где я здесь перевернул?
Пришел товар; я о нем знаю только, что он пришел, от кого и по какой цене. В этом месте я работаю с ним как с ТОВАРОМ. Затем я узнаю, что это жидкость - мне приходится перейти к  объекту другого типа, который наследует все свойства товара плюс объем. И наконец, я узнаю, что это пиво - и полностью теряю интерес к программирования Улыбаюсь А если серьезно, то где ошибка в только-что изложенном?

Цитата
Но наследование служит для специализации, перехода по дедукции от общего к частному, а не для "подцепления вагонов к поезду". И именно поэтому у тебя оно не работает так, как тебе хочется.Здесь поможет только, как говорится, изучение матчасти - того, как именно и для чего именно так работают механизмы ООП в языке.
Не буду оспаривать "подцепления вагонов к поезду", хотя для меня путь от общего к частному как раз и представлялся путем последовательного уточнения свойств общего, которое чаще всего связанно с расширением списка этих свойств.  Так и моем случае: есть самая общая среда выполнения программа, а отдельные блоки могут иметь свою среду, которая обладает только ей присущими свойствами, при этом общая среда программы никуда не делась.
Где я здесь пошел против "матчасти"? Какие "механизмы ООП" и не должны обслуживать мои потребности?

Цитата
Цитата: ezus
В моем случае это унификация использования сервисных модулей.
В твоём случае это называется архитектурой. Соглашением о том, что модули будут организованы так-то, и все разработчики обязаны это учитывать.
И чем это плохо? А в Ваших системах это не так?
Цитата
Цитата: ezus
Да. Но я не вижу, чем могут помешать лишние данные. Кроме того. если в дальнейшем потребуется обратиться к ранее неиспользованному модулю, то ни каких дополнительных телодвижений не потребуется.
Раз они не мешают, тогда добавь их в исходную структуру - и дело с концом. Ты же весь огород городить начал именно из-за того, что они чем-то мешали.
Но в других частях программы они просто не имеют смысла. Так можно договориться до: наследование нам нужно только ради полиморфизма и, если такого-го нет - вали все в кучу. Я надеюсь, Вы не это имели ввиду?

Цитата
Цитата: ezus
потому что каждый конкретный раз я должен знать откуда модуль - из ZSysVectorSimulation или из ZSysVector.
А именно этот излишек требование к знанию я и хочу избежать.
НЕТ! Если ты внимательно посмотришь мой пример, то OldSystem знает .......
Прекрасно!
Но часто ли Вы используете данный стиль в своих последних разработках?
Мне же надо тоже самое только в С++.
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #11 : 19-05-2010 09:11 » 

Так можно договориться до: наследование нам нужно только ради полиморфизма и, если такого-го нет - вали все в кучу. Я надеюсь, Вы не это имели ввиду?

ezus, можно вопрос по ходу дискуссии?

Мне по небольшому опыту программирования на C++ известны два основных применения наследования:

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

Какой из двух вариантов предполагалось использовать в данной задаче? Или, возможно, какой-то третий вариант, который я не учел?

P.S. Прошу прощения, если об этом уже говорилось выше. Тема интересная, но диалог ведется параллельно в слишком многих плоскостях - от античной философии до хакерства на уровне "а что там на самом деле творится в стеке?". В условиях ограниченного времени трудно проследить основную нить, стек переполняется.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
ezus
Опытный

il
Offline Offline

« Ответ #12 : 19-05-2010 09:17 » 

Если они рождаются в разных местах и по разным поводам - то к чему централизация вообще?
А как мне в произвольном месте программы иметь возможность использовать произвольный сервисный модуль?

Мне известны всего несколько способов(не по важности или глупости, а только как пришли в голову):
1. Глобальные переменные - в настоящий момент преданные жуткой анафеме, хотя я их и не считаю, таким уж ЖУТКИМ грехом.
2. Синглтоны - классная вещь, на мой взгляд один из лучших неочевидных паттернов. Но далеко не все модули могут быть так оформлены.
3. Передаваемые параметры - в функции или при инициализации. Во-первых их может быть много, что неудобно. Во- вторых: передавать все - глупо, а иначе любая новая потребность порождает изменения по все цепочке вызовов.
4. Цепочки сред. При создании объекта ему передается обратный указатель на создателя. Так двигаясь в обратном порядке можно добраться до любого модуля в программе (конечно, если весь путь public). Требует знание структуры всей программы.
5. Локальный. Каждый модуль сам себе порождает сервисные модули. К сожалению не все модули можно так породить.
6. Сервисный центр. Некий модуль, который предоставляет доступ к сервисным модулям. Хорош для на общесистемном уровне. Но трудно покрывает локальные среды.
7. Системный вектор - чем-то схож с Сервисным центром, но более прост и мобилен. О недостатках не говорю, т.к. они подробно уже разобраны не мной.

Наверняка есть еще что-нибудь. Буду рад пополнить свою коллекцию.

Цитата
Пытаясь централизовать данные о модулях, ты получаешь загрязнение пространства имён, потому что каждый модуль вынужден неумышленно знать про все-все другие, если ему понадобится хотя бы один из них. Я уже не говорю о том, что в случае структуры указателей ты должен откуда-то извне строго следить за правильным порядком инициализации модулей и разруливать зависимости.
Согласен. Но нет идеальных решений. Хотя в С++, к счастью - слава создателям Класс!) в данном случае "ЗНАТЬ" слишком сильно сказано - я знаю только указатель на какой-то там модуль и больше ничего. И если он мне не интересен, то описание
Код:
class ququ;
не связывает их даже на этапе компиляции.

Цитата
  Коль уж модули - сингельтоны,
Далеко не все.
Цитата

Тогда каждому модулю достаточно знать интерфейс нужных ему, чтобы получить указатель на существующий экземпляр и работать с ним спокойно .
  А в моем случае и этого знать не надо.
Записан
ezus
Опытный

il
Offline Offline

« Ответ #13 : 19-05-2010 09:18 » 

Цитата: А.Дюма
Д'Артаньян не в силах был продолжать этот разговор, он чувствовал, что сходит с ума. Он уронил голову на руки и притворился, будто спит. ...
Сочувствую. Я и сам себя так ощущаю.
Записан
ezus
Опытный

il
Offline Offline

« Ответ #14 : 19-05-2010 09:42 » 

Мне по небольшому опыту программирования на C++ известны два основных применения наследования:

  • Наследование интерфейса (открытое наследование от класса-предка). Потомок берется выполнять все обязательства базового класса, так что клиент в идеале не должен обнаружить различия.
  • Наследование реализации (закрытое наследование от класса-предка). Потомок представляется как некая новая сущность с собственным поведением, пользуясь для своих нужд средствами предка.
Мне кажется здесь 2 ортогональных измерения:
одно - интерфейс \ реализация
другой - функциональность.
Во втором случае возможно как усечение возможностей - базовый класс используется только для своих нужд, так и расширение возможностей - предоставление клиенту кроме базовых еще и дополнительные возможности. Пример: цепочка наследования в окнах MFC

Цитата
Какой из двух вариантов предполагалось использовать в данной задаче? Или, возможно, какой-то третий вариант, который я не учел?
В данном случае предполагается второе уточнение второго варианта.
Записан
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #15 : 19-05-2010 09:42 » 

2. Синглтоны - классная вещь, на мой взгляд один из лучших неочевидных паттернов. Но далеко не все модули могут быть так оформлены.
Не все, но многие? Кроме того, я говорил о сингельтоне-посреднике как частном решении. Если же модуль используется в нескольких экземплярах - твой вариант со структурой тоже не подходит.

Цитата
Цитата
Пытаясь централизовать данные о модулях, ты получаешь загрязнение пространства имён, потому что каждый модуль вынужден неумышленно знать про все-все другие, если ему понадобится хотя бы один из них. Я уже не говорю о том, что в случае структуры указателей ты должен откуда-то извне строго следить за правильным порядком инициализации модулей и разруливать зависимости.
Согласен. Но нет идеальных решений. Хотя в С++, к счастью - слава создателям Класс!) в данном случае "ЗНАТЬ" слишком сильно сказано - я знаю только указатель на какой-то там модуль и больше ничего. И если он мне не интересен, то описание
Код:
class ququ;
не связывает их даже на этапе компиляции.
Ну да. Под "знать" я подразумевал, что все модули знают о единой структуре ("векторе"), вынуждены её поддерживать и имеют в своём пространстве имён набор деклараций типов.

Цитата
Цитата

Тогда каждому модулю достаточно знать интерфейс нужных ему, чтобы получить указатель на существующий экземпляр и работать с ним спокойно .
  А в моем случае и этого знать не надо.
А чтобы работать с модулем - тоже не надо интерфейс? Улыбаюсь
Записан
ezus
Опытный

il
Offline Offline

« Ответ #16 : 19-05-2010 09:55 » 

Если же модуль используется в нескольких экземплярах - твой вариант со структурой тоже не подходит.
Почему не подходит? В среде каждого конкретного модуля должен быть только один экземпляр, но самих модулей может быть несколько. Пример: есть 2-3-4 окна, в каждом из которых мы работаем со своей базой данных.

Цитата
Ну да. Под "знать" я подразумевал, что все модули знают о единой структуре ("векторе"), вынуждены её поддерживать и имеют в своём пространстве имён набор деклараций типов.
Да - о векторе и НЕТ о типах. Надо поддерживать только типы используемых модулей, а это надо делать в любом случае. А если модуль не используется, то необходим единственный стандартный тип void*

Цитата
Цитата
Цитата
Тогда каждому модулю достаточно знать интерфейс нужных ему, чтобы получить указатель на существующий экземпляр и работать с ним спокойно .
  А в моем случае и этого знать не надо.
А чтобы работать с модулем - тоже не надо интерфейс? Улыбаюсь
Надо, но только для использования, а не порождения.
Хотя Вы правы - это не такое уж принципиальное отличие.
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #17 : 19-05-2010 11:03 » 

Мне кажется здесь 2 ортогональных измерения:
одно - интерфейс \ реализация
другой - функциональность.
Во втором случае возможно как усечение возможностей - базовый класс используется только для своих нужд, так и расширение возможностей - предоставление клиенту кроме базовых еще и дополнительные возможности.
...
В данном случае предполагается второе уточнение второго варианта.

Спасибо. Если я правильно понял конструкцию, потомок должен уметь все то же самое, что и предок, и плюс кое-что дополнительно? В таком случае структурой в стиле старого доброго C мы вряд ли обойдемся. Придется писать на C++, а значит, определять копирующий конструктор и/или операторы присваивания/преобразования типов и т.п.

Пример: цепочка наследования в окнах MFC

Если мы говорим о хорошем стиле ООП (а я надеюсь, что это так и есть), нам лучше все же не брать MFC в качестве образца для подражания.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #18 : 19-05-2010 11:37 » 

Цитата: ezus
Где я "ослабляю типизацию"? Причем тут "void *" и "произвольный по размеру куска памяти"? От чего я отказался?
У меня есть ПОЛНОСТЬЮ определенная базовая структура, у меня есть ПОЛНОСТЬЮ определенная дочерняя структура. Я всего лишь хочу перенести значение одной базовой структуры в БАЗОВУЮ же часть дочерней. В чем здесь криминал? Какие принципы ООП я нарушил?
У тебя нет "базовой части" переменной - вот в этом и криминал. "Базовая часть" бывает только у значения. Поэтому я и говорил, что введение вложенной структуры может решить твои затруднения.

А ослабление типизации происходит в том случае, когда из значения производного типа извлекают "базовую часть". К операции записи в переменную это не относится. Но ты это попытался скомбинировать, что показывает непонимание "матчасти".

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

Цитата: ezus
Где я требую от дерева березовых свойств? Вы мне приписываете что-то непонятное. У меня есть береза. Эта береза, как ни странно, является еще и деревом. Я хочу при создании объекта "береза" переписать в нее ту часть, которая касается ее как дерева. И буду в дальнейшем требовать от этой части только свойств березы как ДЕРЕВА. Что\где я здесь перевернул?
Пришел товар; я о нем знаю только, что он пришел, от кого и по какой цене. В этом месте я работаю с ним как с ТОВАРОМ. Затем я узнаю, что это жидкость - мне приходится перейти к  объекту другого типа, который наследует все свойства товара плюс объем. И наконец, я узнаю, что это пиво - и полностью теряю интерес к программирования  А если серьезно, то где ошибка в только-что изложенном?
Здесь ошибки нет, но это не соответствует тому, что у тебя написано в коде. Выражение
Код: (C++)
(A)b = a;
означает, что у тебя есть дерево (а не берёза) - значение в переменной a. И ты хочешь это дерево засунуть в берёзу - переменную b. То, что ты берёзу собираешься использовать лишь как дерево, компилятор не знает - не телепат, поэтому он старается обеспечить наличие в переменной b значения типа B (именно берёзы, а не чего-то там другого). Приведение к A - это уже из области "ловкости рук" при впаривании просроченной тухлятины под видом свежего товара. Если тебе нужны только свойства дерева, тогда и объявляй переменную типа A.

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

Цитата: ezus
И чем это плохо? А в Ваших системах это не так?
Ничем. Я просто уточнил, что речь идёт не об унификации, а об архитектуре.

Цитата: ezus
Но в других частях программы они просто не имеют смысла. Так можно договориться до: наследование нам нужно только ради полиморфизма и, если такого-го нет - вали все в кучу. Я надеюсь, Вы не это имели ввиду?
Самое главное - это инкапсуляция и достигаемая с её помощью возможность абстрагироваться от несущественных деталей. Без неё обсуждение наследования и полиморфизма смысла не имеет. По крайней мере у тебя в наследовании никакого смысла нет.

Поскольку на самом деле наследование (inheritance) наряду с делегированием с прототипами - это лишь языковые реализации чисто логического отношения обобщения (generalization), только первое используется в типизированных языках, а второе в нетипизированных, лично я могу добиться полиморфизма и без наследования, если мне так приспичит Улыбаюсь

Цитата: ezus
Прекрасно!
Но часто ли Вы используете данный стиль в своих последних разработках?
Мне же надо тоже самое только в С++.
В C++ нужно структуру "растянуть" на всё пространство имён и включить в неё функции, убрав их параметр типа структуры. Это всё. Принципы ООП не зависят от языка реализации. Я могу и на чистом C реализовать и объекты, и их инкапсуляцию, и наследование с полиморфизмом, и без всяких издевательств над компилятором. Когда хорошо понимаешь принципы и возможные способы их "физической" реализации, язык программирования значения не имеет.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #19 : 19-05-2010 11:40 » 

Цитата: Dale
Придется писать на C++, а значит, определять копирующий конструктор и/или операторы присваивания/преобразования типов и т.п.
Эта здравая мысль звучала и раньше, но почему-то не нравится зачинщику обсуждения.

Цитата: Dale
Если мы говорим о хорошем стиле ООП (а я надеюсь, что это так и есть), нам лучше все же не брать MFC в качестве образца для подражания.
Категорически согласен Улыбаюсь
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #20 : 19-05-2010 11:46 » 

Здесь ошибки нет, но это не соответствует тому, что у тебя написано в коде. Выражение
Код: (C++)
(A)b = a;
означает, что у тебя есть дерево (а не берёза) - значение в переменной a. И ты хочешь это дерево засунуть в берёзу - переменную b. То, что ты берёзу собираешься использовать лишь как дерево, компилятор не знает - не телепат, поэтому он старается обеспечить наличие в переменной b значения типа B (именно берёзы, а не чего-то там другого). Приведение к A - это уже из области "ловкости рук" при впаривании просроченной тухлятины под видом свежего товара. Если тебе нужны только свойства дерева, тогда и объявляй переменную типа A.

я бы рассматривал эту строку иначе (если убрать из неё изначальную ошибку)
Код:
void DataCopy(A * dst, A * src)
{
  *dst = *src;
}
.............
B b; // B унаследован от A
A a;
DataCopy(&b, &a);
Думаю тут все согласятся, что подобное приведение является верным и вполне себе классическим примером использования наследования, т.е. я не пытаюсь базовый тип привести к наследнику, а наследника привожу к базовому.

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

Записан

Странно всё это....
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #21 : 19-05-2010 12:11 » 

LogRus, вот поэтому ему и говорили написать оператор присваивания или копирующий конструктор. Но не хочет.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #22 : 19-05-2010 12:14 » 

Dimka, копирующий конструктор это конечно круто, НО это некоим образом не объясняет почему приведённая конструкция не работает
Записан

Странно всё это....
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #23 : 19-05-2010 12:28 » 

Код: (C++)
(A)b = a;
...
Приведение к A - это уже из области "ловкости рук" при впаривании просроченной тухлятины под видом свежего товара.

И в довершение картины - ловкий продавец при этом еще и старается говорить не на языке покупателя, чтобы еще больше запутать. Поскольку процитированный фрагмент написан не на C++.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #24 : 19-05-2010 13:11 » 

LogRus, твоя конструкция тоже не объясняет, почему не работает его выражение. Скорее наоборот, твой работающий пример способен навести на мысль, что и его конструкция должна работать.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
ezus
Опытный

il
Offline Offline

« Ответ #25 : 20-05-2010 06:23 » 

Прошу прощения у LogRus.
Конструкция
Код:
 (A&)b=a; 
прекрасно работает.
Огромное спасибо. Ты вернул мне веру в себя, в ООП, и даже в С++.

Конструкция (А)b=a; не работает по чисто компиляторским причинам. Например обратные  a=(A)b;  и даже a=b; прекрасно хаваются и исполняются. Правда, побочные последствия я не исследовал, возможно они и существуют, а будет жаль.

Записан
ezus
Опытный

il
Offline Offline

« Ответ #26 : 20-05-2010 06:26 » 

LogRus, вот поэтому ему и говорили написать оператор присваивания или копирующий конструктор. Но не хочет.
Вы можете привести мне примеры предложенных приемов без использования поэлементного присвоения?
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #27 : 20-05-2010 06:34 » 

ezus,
Конструкция (А)b=a; не работает по чисто компиляторским причинам. Например обратные  a=(A)b;  и даже a=b; прекрасно хаваются и исполняются. Правда, побочные последствия я не исследовал, возможно они и существуют, а будет жаль.

1)(А)b=a; -  можно расписать так:
Код:
A& ra=A();
ra=b;
ra=a;
//присвоения b=... нету.

2)a=(A)b;  -  можно расписать так:
Код:
A& ra=A(b);
a=ra;

3) a=b; - вызывается копирование по умолчанию , то есть так:
Код:
a=(A&)b;
Записан

ezus
Опытный

il
Offline Offline

« Ответ #28 : 20-05-2010 07:04 » 

Код: (C++)
(A)b = a;
...
Приведение к A - это уже из области "ловкости рук" при впаривании просроченной тухлятины под видом свежего товара.

И в довершение картины - ловкий продавец при этом еще и старается говорить не на языке покупателя, чтобы еще больше запутать. Поскольку процитированный фрагмент написан не на C++.

На "ловкость рук" и "просроченную тухлятину" я не ответил в свое время во-первых у меня не было работающего примера, а во-вторых на грубость, тем более необоснованную, вообще не отвечаю.

Но сейчас я убедился в своей правоте и попробую спокойно отреагировать на приведенную цитату.

Чем
Код:
(A)b = a;
не C++? Только тем, что Вы его не используете?(Пардон не удержался Улыбаюсь )

С точки зрения языка:
Моя ошибка заключалась в незнании особенностей КОНКРЕТНОГО компилятора и в наследии пресловутой Java. Компилятор получил всю необходимую информацию для исполнения того, что я хочу. Я просто не знал о временной переменной. В Java конструкция (A) не оператор как здесь, а только указание интерпретатору на приведении типов.
Поэтому работает (A&)b = a;.

Хотя и конструкция (A)b тоже имеет смысл. Например: ((A)b).ff(); для доступа к функции ff класса А.

С точки зрения ООП или "тухлятины":
Разве береза перестала быть деревом только потому что она береза?
Разве ее нельзя рассматривать как дерево?
Что в конструкции "(A&)b = a" я впариваю как тухлятиню? Что я здесь продаю на другом языке?
Записан
ezus
Опытный

il
Offline Offline

« Ответ #29 : 20-05-2010 07:09 » 

Алексей1153++
Спасибо. Полезно.
А о своей ошибке я уже сказал в предыдущем посте.
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #30 : 20-05-2010 07:14 » 

Конструкция
Код:
 (A&)b=a; 
прекрасно работает.
Огромное спасибо. Ты вернул мне веру в себя, в ООП, и даже в С++.

Простите, но ведь тут и ООП, и C++ и близко не лежали, насколько я вижу. Обычный C, использованный типично по-сишному: ссылка указывает на один тип, а притворяется при этом ссылкой на другой. Низкоуровневый хак, который отстоит от идей ООП, примерно как северный полюс от южного - на максимально возможном удалении.

Оно понятно, что истинная вера не требует и не признает аргументов, но все же...
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
ezus
Опытный

il
Offline Offline

« Ответ #31 : 20-05-2010 07:16 » 

Опять путаница.
Начиная с №19 - это копирование.
Может лучше перенести эти посты в ветку копирования, оставив здесь только дизайн?
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #32 : 20-05-2010 07:29 » 

Чем
Код:
(A)b = a;
не C++? Только тем, что Вы его не используете?(Пардон не удержался Улыбаюсь )

Да я-то тут при чем? Хоть разок полистайте Страуструпа, что ли... Он это тоже не использует, и другим настоятельно не советует. Или он тоже не указ?
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
ezus
Опытный

il
Offline Offline

« Ответ #33 : 20-05-2010 07:40 » 

Конструкция
Код:
 (A&)b=a; 
прекрасно работает.
Простите, но ведь тут и ООП, и C++ и близко не лежали, насколько я вижу. Обычный C, использованный типично по-сишному: ссылка указывает на один тип, а притворяется при этом ссылкой на другой. Низкоуровневый хак, который отстоит от идей ООП, примерно как северный полюс от южного - на максимально возможном удалении.
Опять одни эмоции и география.
Цитата
Оно понятно, что истинная вера не требует и не признает аргументов, но все же...
Так дайте, дайте аргументы. Аргументы на сцену. А эмоции пусть будут в зале.

По делу. Снова:
Есть дерево, есть береза, и есть осина.
Когда я пилю обычной деревенской пилой (оставим в стороне профессиональный подход к заточке пилы) мне все-равно что это - береза или осина - я пилю ДЕРЕВО, а не железо или воду. Разница будет важна только когда я буду заталкивать поленья в печь.
И что? Один и тот же кусок я не могу рассматривать в одном случае как ДЕРЕВО, а в другом как БЕРЕЗА?
Если Вы действительно утверждаете это, то мы, так и да, понимаем ООП по разному.
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #34 : 20-05-2010 07:41 » 

Раскрываем книгу: Бьерн Страуструп, "Язык программирования C++. Специальное издание".

Читаем.

Стр. 49: "Знание C не является обязательным для изучения C++. Программирование на С поощряет многие технические трюки, которые становятся ненужными благодаря С++. Например, явное преобразование типов в С++используется реже, чем в С ($1.6.1)".

Стр 50: "Чем лучше вы знаете С, тем труднее вам будет избежать программирования на С++ в стиле С, теряя при этом потенциальные преимущества С++.
...
Вот некоторые вещи, с которыми С++ справляется лучше, чем С:
...
[4] Пытайтесь избегать void*, арифметических операций над указателями, объединений и приведений типов, за исключением разве что глубоко спрятанных в реализацию функций или классов. В большинстве случаев приведение типа означает ошибку на этапе проектирования." (выделение мое - Dale).

Не аргумент?
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #35 : 20-05-2010 07:48 » 

ezus, непонятно, на что ты оскорбляешься. Даже не учитывая того, что Dale даже и не пытался оскорблять Улыбаюсь
Записан

ezus
Опытный

il
Offline Offline

« Ответ #36 : 20-05-2010 07:55 » 

Да я-то тут при чем? Хоть разок полистайте Страуструпа, что ли... Он это тоже не использует, и другим настоятельно не советует. Или он тоже не указ?
Вообще-то да, не указ.
Может быть потому что принцип декомпозиции, основанный на понятии структура объекта появился в моей практике, а затем и коллекции немножко раньше выхода известной книжки в свет. Но я не гордый - и поэтому это не главная причина.

Я придерживаюсь взгляда, что детальное ЗНАНИЕ матчасти и строгое ей следование относится только к ИНСТРУМЕНТУ. Что же касается МЕТОДИКИ, то тут важно ПОНИМАНИЕ и вполне допустимы интерпретации и эксперименты. А просто ссылки на ... очень напоминают мне требование "Знать первоисточник" - 23 строка на 78 странице 17 тома Полного Собрания Сочинений товарища ....

Вы мне можете просто объяснить - чем плоха конструкция (A)b? Если можно, то с учетом моих замечание про березу и осину.
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #37 : 20-05-2010 07:59 » 

Цитата
Вы мне можете просто объяснить - чем плоха конструкция (A)b? Если можно, то с учетом моих замечание про березу и осину.

Извольте. "Продолжаем разговор" (С)

Там же, стр. 172:
"С++ унаследовал от С форму записи (T)e, означающую любое преобразование, которое может быть выражено комбинацией static_cast, reinterpret_cast и const_cast, для получения значения типа T из выражения e($Б.2.3). Такой стиль намного опаснее, чем именованные операторы преобразования, потому чтоприведенную форму записи сложнее отслеживать в большой программе и вид преобразования, который имел в виду программист, не очевиден. Ведь (T)e можетосуществлять и переносимое преобразование между близкими типами, и непереносимое преобразование между несвязанными типами, и, наконец, аннулировать действие модификатора const для указателя."

Хотя действительно, что он понимает в ООП и С++, этот щенок Страуструп... И откуда у него истинная вера.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
ezus
Опытный

il
Offline Offline

« Ответ #38 : 20-05-2010 07:59 » 

В большинстве случаев приведение типа означает ошибку на этапе проектирования." (выделение мое - Dale).

Не аргумент?
Принимаю как аргумент.

И все-таки. Вы отрицаете необходимость в ряде случаев представлять порожденный класс как базовый?
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #39 : 20-05-2010 08:12 » 

И все-таки. Вы отрицаете необходимость в ряде случаев представлять порожденный класс как базовый?

Это апофеоз, тут даже не сразу найдешь, что сказать...

Цитата
- Знаете ли, профессор,  -  заговорила девушка, тяжело вздохнув, - если бы  вы  не  были европейским светилом, и  за вас  не  заступались  бы  самым возмутительным   образом  (блондин  дернул   ее  за   край  куртки,  но  она отмахнулась) лица,  которых,  я уверена, мы еще разьясним,  вас следовало бы арестовать.
- А за что? - с любопытством спросил Филипп Филиппович.
- Вы ненавистник пролетариата! - гордо сказала женщина.

В свое оправдание могу лишь сказать, что я НЕ отрицаю необходимость в ряде случаев представлять порожденный класс как базовый (если бы отрицал, меня действительно следовало бы арестовать). По крайней мере, не был в этом замечен. По крайней мере, на этом форуме. Но какое отношение это имеет к нашему случаю? Нет здесь никакого базового класса. И никогда не будет, судя по всему. Есть структура C, не более того.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #40 : 20-05-2010 08:21 » 

ezus, непонятно, на что ты оскорбляешься. Даже не учитывая того, что Dale даже и не пытался оскорблять Улыбаюсь

Алексей, тут никакой реальной обиды нет. Это обычный ораторский прием: когда убедительных аргументов нет, всегда можно придумать зацепку для обиды. Ведь далеко не каждый может сказать: да, ребята, теорию не почитал, программу не продумал, спасибо, что подсказали, в каком направлении двигаться дальше. Проще упереться на своем, каким бы оно ни было, и парировать: "Зато все вы тут дураки некультурные, о чем с такими хамами вообще говорить!". И пускай потом оправдываются за то, чего не было.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #41 : 20-05-2010 08:25 » 

Да уж, воистину непонятны действия товарисча ezus. Хотя, в принципе, он не складывал о себе мнения как о тупом. Но ТАКИЕ странности могут даже до увольнения с работы довести (если есть работа) Улыбаюсь
Записан

Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #42 : 20-05-2010 08:43 » 

ТАКИЕ странности могут даже до увольнения с работы довести (если есть работа) Улыбаюсь

Ошибаетесь, коллега.

У меня совсем недавно начальник отдела IT одной очень крупной организации потребовал некоторые данные, которые я, вообще говоря, обязан отправить по требованию. Я отправил их в формате XML (мы их именно в этом виде обрабатываем). Через некоторое время раздался возмущенный звонок:

- Что вы нам прислали?
- Запрошенные файлы.
- Но файлов не было, пришли отчеты!

Затем по телефону мне был преподан краткий курс информатики, после чего я наконец-то понял, что XML - это отчет, CSV - это файл, а DBF - это база данных. Занавес.

А вы говорите - увольнение... Да мы как раз первыми и вылетим. За то, что не знаем, чем файл от базы и отчета отличается, то есть полную профнепригодность.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #43 : 20-05-2010 08:47 » 

Конструкция
Код:
 (A&)b=a; 
прекрасно работает.
Огромное спасибо. Ты вернул мне веру в себя, в ООП, и даже в С++.

Простите, но ведь тут и ООП, и C++ и близко не лежали, насколько я вижу. Обычный C, использованный типично по-сишному: ссылка указывает на один тип, а притворяется при этом ссылкой на другой. Низкоуровневый хак, который отстоит от идей ООП, примерно как северный полюс от южного - на максимально возможном удалении.
Какой же это Си? В Си ссылок никогда не было, разве нет? Про копирование структур тоже сомневаюсь, хотя точно не помню уже. Да и хак не настолько уж низкоуровневый: здесь же тип не к void* приводится, а вверх по иерархии. Контроль соответствия типов в этом случае криминал не даст совершить (присвоить "камню" "дерево")

"С++ унаследовал от С форму записи (T)e, означающую любое преобразование, которое может быть выражено комбинацией static_cast, reinterpret_cast и const_cast, для получения значения типа T из выражения e($Б.2.3). Такой стиль намного опаснее, чем именованные операторы преобразования, потому чтоприведенную форму записи сложнее отслеживать в большой программе и вид преобразования, который имел в виду программист, не очевиден. Ведь (T)e можетосуществлять и переносимое преобразование между близкими типами, и непереносимое преобразование между несвязанными типами, и, наконец, аннулировать действие модификатора const для указателя."
Почти весь криминал (если не весь) связан с преобразованием указателей. Хотя я тоже предпочитаю static_cast, в данном случае он не так чтобы нужен. Ошибка была совсем в другом - в том, что (Т)е является lvalue только для ссылочных типов. В случае работы с указателями это, в общем-то, безразлично, а вот в случае присваивания значений переменным - даёт то, что даёт.
« Последнее редактирование: 20-05-2010 08:52 от Вад » Записан
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #44 : 20-05-2010 09:01 » 

Вад, уже всё сказал, ну не стирать же сообщение Улыбаюсь

Код:
(A)b=a; 
И так что тут происходит? Компилятор всеми силами старается b к типу A для этого он вполне логично делает его копию (для меня это выглядит именно так), далее мы модифицируем временный объект.

Вот цитата из стандарта касающаяся static_cast (который скорее всего и используется)
Цитата
Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_-
cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t (8.5). The
effect of such an explicit conversion is the same as performing the declaration and initialization and then
using the temporary variable as the result of the conversion. The expression e is used as a glvalue if and
only if the initialization uses it as a glvalue.

конструкция
Код:
(A&)b=a; 
приводит нас к ссылке на объект без создания временного объекта, что кстати тоже описано в стандарте
Записан

Странно всё это....
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #45 : 20-05-2010 09:04 » 

Какой же это Си? В Си ссылок никогда не было, разве нет?

И структуру от структуры в чистом C нельзя произвести наследованием, само собой. Компилятор С такую программу не воспримет. Однако такая мелочь не делает приведенный фрагмент объектно-ориентированной программой на С++.

Кстати, вот еще у Страуструпа попалось на глаза:

"Ключевое понятие в С++ - это класс. Класс - это тип, определяемый пользователем. Классы обеспечивают сокрытие информации, гарантированную инициализацию данных, неявное преобразование определяемых пользователем типов, динамическое определение типа, контроль пользователя над управлением памятью и механизм перегрузки операторов".

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

В той же программе на С можно, например, перегрузить определение функции с другими аргументами, после чего она перестанет быть корректной программой на С. Но говорить, что она была переписана на С++, как-то смешно.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #46 : 20-05-2010 09:12 » 

Dale, возможно, кощунственно прозвучит, но C++ - не объектно-ориентированный язык. В пользу этого говорит хотя бы частичная (почти полная) совместимость с С и поддержка процедурно-модульного подхода.
C++ лишь поддерживает ООП-парадигму.

Поэтому в структуре нет ничего такого особенного. А учитывая некоторые сложности с реализацией ООП средствами C++ (нужно заботиться о корректном копировании и вручную управлять всеми динамическими объектами), часто структура является даже более естественным типом. Когда есть только данные, а манипуляции над ними каждый модуль делает свои, и нет ничего такого, что можно было бы выделить в качестве общих методов для этих данных и запихать в класс (кроме геттеров, которые тут становятся скорее помехой)

Например, пакеты протоколов обмена данными порой просто удобнее реализовывать структурами, и часто бывает удобно эти структуры наследовать, просто для сохранения единой глубины вложенности членов. Да, это не ООП-подход, но никакого криминала здесь априори нет. Криминал появляется, когда решения становятся запутанными и неуклюжими.
« Последнее редактирование: 20-05-2010 09:16 от Вад » Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #47 : 20-05-2010 09:19 » 

Dale, возможно, кощунственно прозвучит, но C++ - не объектно-ориентированный язык.

Тут нет кощунства. Если бы он был объектно-ориентированным, он бы просто не позволил подобные выкрутасы в принципе, и данная тема не могла бы возникнуть. Речь как раз о том и идет, что аморфность языка позволяет программирующему на нем пребывать в искреннем заблуждении, что он пишет объектно-ориентированные программы, которые реально таковыми не являются.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Вад
Модератор

ru
Offline Offline
Пол: Мужской

« Ответ #48 : 20-05-2010 09:35 » 

Dale, возможно, кощунственно прозвучит, но C++ - не объектно-ориентированный язык.

Тут нет кощунства. Если бы он был объектно-ориентированным, он бы просто не позволил подобные выкрутасы в принципе, и данная тема не могла бы возникнуть. Речь как раз о том и идет, что аморфность языка позволяет программирующему на нем пребывать в искреннем заблуждении, что он пишет объектно-ориентированные программы, которые реально таковыми не являются.

Согласен. В этом смысле, скажем, Objective C - как расширение Си (и, соответственно, полностью совместимый с ним) оставляет куда меньше шансов на подобные иллюзии.
Но даже заблуждение насчёт объектно-ориентированных программ криминалом само по себе не является Улыбаюсь Другое дело - когда мотивация решения базируется на таких заблуждениях. Собственно, с этим мы тут все и боремся.

Просто я не стал бы говорить, что "это не C++" или что "так нельзя". На C++ - в силу его аморфности - можно программировать множеством способов, и, на мой взгляд, неправильными являются не те, которые используют какие-то хаки, трюки или ещё что-то. А те, которые приводят к малопонятным и плохо поддерживаемым решениям - то есть, дают в целом менее качественный код.

Хак же, если его задокументировать, тоже вполне может быть понятным. Или, если его локализовать, он, по крайней мере, не навредит понятности всей системы. Программам вредят не хаки, а их количество и качество Улыбаюсь
Записан
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #49 : 20-05-2010 09:46 » 

Но даже заблуждение насчёт объектно-ориентированных программ криминалом само по себе не является Улыбаюсь Другое дело - когда мотивация решения базируется на таких заблуждениях.

А тут уже виной моя невнимательность. Я проглядел небольшую, но важную деталь:

Я сторонник ИДЕЙ ООП, но не самого ООП, особенно в исполнении С++. Поэтому аргументы типа "так принято в ООП" для меня не аргументы.

Это автоматически делает все мои предыдущие аргументы несостоятельными.

Вот представьте себе, садитесь вы играть в шахматы. Точнее, это вы думаете, что в шахматы. А противник берет вашего ферзя за фука, а потом идет ладьей по диагонали через всю доску. На ваши робкие потесты отвечает: "А я сторонник идей шахмат, но не самих шахмат, особенно по правилам ФИДЕ. Я экспериментирую, творчески развиваю идею".

Я примерно так же вижу ситуацию. Вроде знакомая доска, знакомые фигуры, а игра, вопреки ожиданиям, идет почему-то в "Чапаева"... Причем вовсе не факт, что я могу претендовать на правоту в данном вопросе, игру каждый волен выбирать себе сам.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #50 : 20-05-2010 10:17 » 

Цитата: ezus
Вы можете привести мне примеры предложенных приемов без использования поэлементного присвоения?
Конечно могу.

Пример со специальным конструктором копирования (по сути аналогичный предложенному LogRus):
Код: (C++)
#include <iostream>

struct A
{
    int a;
    A(): a(0) {}
};

struct B: public A
{
    int b;
    B(): A(), b(0) {}
    B(const A &other): A(other), b(0) {}
};

int main()
{
    A a;
    a.a = 123;
    B b(a);
    std::cout << b.a << " " << b.b << std::endl;
}

Цитата: ezus
Чем
Код:
(A)b = a;
не C++? Только тем, что Вы его не используете?
Во-первых, как уже выяснилось, данное выражение в C++ бессмысленно. Во-вторых, (в третий раз повторяю) сам этот подход является алогичным присваиванием с побочными эффектами - я его не использую именно из-за побочных эффектов, потому что мне не нужны потенциальные источники багов. И ладно я, человек опытный, могу позволить себе такие финты ушами, но если этот код попадёт в сопровождение молодому неопытному разработчику, тот ничтоже сумняшеся станет его применять, совершенно не понимая, что этот код не делает. Поэтому я, как человек опытный, и отвечающий не только за свои результаты, но и молодых разработчиков, себе не позволяю такие приёмы - мне гораздо ленивее тратить день на поиск таинственного бага потери данных или мусора в полях структуры, чем сразу написать надёжные три строчки вместо одной сомнительной.

Цитата: Dale
Низкоуровневый хак, который отстоит от идей ООП, примерно как северный полюс от южного - на максимально возможном удалении.
Совершенно верно! Именно так это и оценивается.

Цитата: ezus
И все-таки. Вы отрицаете необходимость в ряде случаев представлять порожденный класс как базовый?
Никто не отрицает. Только ты делаешь наоборот! Экземпляр базового пытаешься присвоить переменной порождённого со всеми вытекающими.
« Последнее редактирование: 20-05-2010 10:40 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #51 : 20-05-2010 10:28 » 

что докопались до человека, никакого хата, обычный код
привести к базовому и присвоить, совершено штатное поведение, другое дело, что используется C стиль
Записан

Странно всё это....
Dale
Блюзмен
Команда клуба

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #52 : 20-05-2010 10:40 » 

что докопались до человека, никакого хата, обычный код

Не сердитесь, пожалуйста, мы уже поняли, что обычный. Уже публично покаялись, больше не мешаем приводить и присваивать.
Записан

Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.

Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard

Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #53 : 20-05-2010 10:46 » 

Я вообще спокоен Улыбаюсь сижу работаю Улыбаюсь иногда пишу всякую хрень сюда (типа у меня есть мне по любому поводу Улыбаюсь и без )
Записан

Странно всё это....
ezus
Опытный

il
Offline Offline

« Ответ #54 : 20-05-2010 10:48 » 

что докопались до человека, никакого хата, обычный код
привести к базовому и присвоить, совершено штатное поведение, другое дело, что используется C стиль
Спасибо за сочувствие.
При всем моем немалом опыте программирования -  в С++ я новичек - всего 3 года, причем первый был 20 лет назад, а последние 2 приходится работать с системой, которой тоже около 20 лет и в ней С больше чем С++.

Пример со специальным конструктором копирования (по сути аналогичный предложенному LogRus):
Код: (C++)
#include <iostream>

struct A
{
    int a;
    A(): a(0) {}
};

struct B: public A
{
    int b;
    B(): A(), b(0) {}
    B(const A &other): A(other), b(0) {}
};

int main()
{
    A a;
    a.a = 123;
    B b(a);
    std::cout << b.a << " " << b.b << std::endl;
}
Это именно то, что мне более всего подходит. Спасибо.

Цитата
Только ты делаешь наоборот! Экземпляр базового пытаешься присвоить переменной порождённого со всеми вытекающими.
А можно поподробнее о "со всеми вытекающими"? Очень хочется понять.
Записан
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #55 : 20-05-2010 19:44 » 

Цитата: ezus
А можно поподробнее о "со всеми вытекающими"? Очень хочется понять.
Мне уже утомило повторять о последствиях. Что именно подробнее? Трижды я в этой и исходной темах говорил, что в такой операции присваивания не задействуются поля производной структуры. Неочевидным образом заполняется лишь часть полей, и никакой код (будь то метод или оператор присваивания) не контролирует целостность данных.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
sss
Специалист

ru
Offline Offline

« Ответ #56 : 21-05-2010 09:02 » 

ezus, вот пример :
Код:
  DWORD    dw;
  dw = dw | 0xFF;

или

Код:
  WORD      w = 0xFFFF;
  DWORD    dw;
  CopyMemory( &dw, &w, sizeof( w));


Чему равно dw ? 
« Последнее редактирование: 21-05-2010 09:05 от sss » Записан

while (8==8)
ezus
Опытный

il
Offline Offline

« Ответ #57 : 22-05-2010 07:41 » 

вот пример :
Код:
  DWORD    dw;
  dw = dw | 0xFF;
или
Код:
  WORD      w = 0xFFFF;
  DWORD    dw;
  CopyMemory( &dw, &w, sizeof( w));
Чему равно dw ? 
К чему этот пример?
Разве WORD  наследует DWORD,  или наоборот?
Или вы проверяете меня на вшивость - знаю ли я представление данных в разных процессорах? А вы знаете?
Где в этом примере связь с поставленным вопросом?
Записан
ezus
Опытный

il
Offline Offline

« Ответ #58 : 22-05-2010 07:47 » 

При обсуждение данной проблемы со свои сыном он назвал меня  "старым хреном". С таким аргумент трудно было не согласиться. Посему признаю свою тупость или отсталость.
ВСЕМ СПАСИБО за потраченное время.
Записан
Алексей++
глобальный и пушистый
Глобальный модератор

ru
Offline Offline
Сообщений: 13


« Ответ #59 : 22-05-2010 10:32 » 

ezus, сыну - надрать задницу за неуважение!
Записан

Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #60 : 22-05-2010 11:10 » 

Цитата: ezus
Где в этом примере связь с поставленным вопросом?
Дабы не выражаться нецензурно, я лучше промолчу. Тем более, что убедительные аргументы уже нашлись.
Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
RXL
Технический
Администратор

ru
Offline Offline
Пол: Мужской

WWW
« Ответ #61 : 22-05-2010 22:28 » 

ezus, если не секрет, за что ты получил такое звание?
Записан

... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
ezus
Опытный

il
Offline Offline

« Ответ #62 : 23-05-2010 07:24 » 

ezus, если не секрет, за что ты получил такое звание?
А разве оно такое уж высокое?
Стам - осколни имени и фамилии - не более.
Записан
sss
Специалист

ru
Offline Offline

« Ответ #63 : 24-05-2010 01:05 » 

Или вы проверяете меня на вшивость - знаю ли я представление данных в разных процессорах? А вы знаете?
Где в этом примере связь с поставленным вопросом?

Не хорошо отвечать вопросом на вопрос...
А, а все таки, чему равно dw?

Отвечу за вас: я не знаю чему равно значение dw, потому что эта переменная не инициализирована полностью...  Возможно для нее вызывается конструктор по умолчанию, возможно память выделяется тупо в стеке. Теперь есть связь с темой?

Записан

while (8==8)
Антон (LogRus)
Глобальный модератор

ru
Offline Offline
Пол: Мужской
Внимание! Люблю сахар в кубиках!


WWW
« Ответ #64 : 24-05-2010 02:59 » 

Коллеги, ну вы чего, чего?
Тут кругом человеки разумные и то товарищ ezus не показал нам момент инициализации, не означает, что его не было.
для всех, нормальным является передать указатель на потомка в функцию принимающую указатель на предка (она там может дел натворить, таких, что не в сказке сказать, ни пером описать), а видители привести указатель потомка, к указателю на предка и вызвать оператор= предка, это пипец какая трагедия.
Ничего тут страшного нет, человек знает про полиморфизм, наследование, инициализацию данных и т.д. и т.п., чего его лечить от болезней которых нет.
Записан

Странно всё это....
Dimka
Деятель
Команда клуба

ru
Offline Offline
Пол: Мужской

« Ответ #65 : 24-05-2010 10:39 » 

LogRus, отчасти ты прав.

Тем не менее, приведу варианты на мой взгляд правильных решений:

Код: (C++)
b.a = a.a;
т.е. полный перечень всех присваиваемых полей. И не надо оправдываться ленью. Такое описание в коде при прочтении этого кода не оставляет никаких недоразумений по поводу неиницализированных полей. Аналогично в случае вложенных структур.

Вариант с конструктором я приводил выше. Правильно написанный конструктор гарантирует, что все поля будут инициализированы (включая те, которые не заполняются из A). Это снимает с пользователя заботу о неинициализированных значениях переменных. Используется инкапсуляция.

Код: (C++)
struct B: public A
{
   int b;
   void loadFrom(const A &a)
   {
      (A &)(*this) = a;
   }
}
Отдельный метод, который скрывает от пользователя особенности реализации копирования данных из A в B. Этот же метод может содержать код, контролирующий сохранение логической целостности данных и обработку полей, не входящих в A. Опять используется инкапсуляция, а за непродуманность реализации метода отвечает программист-разработчик этой идеи, а не программист-пользователь, который не узнал/не догадался, как нужно правильно записать. В этом же случае полезно делать закрытые поля и предоставлять доступ к ним через аксессоры.

Два последних подхода с точки зрения пользователя записываются в одну строчку, что обеспечивает повторное использование кода копирования по всей системе и одинаковость процесса копирования. При реализации стиле C нужно завести отдельную функцию копирования.
« Последнее редактирование: 24-05-2010 10:42 от Dimka » Записан

Программировать - значит понимать (К. Нюгард)
Невывернутое лучше, чем вправленное (М. Аврелий)
Многие готовы скорее умереть, чем подумать (Б. Рассел)
Страниц: 1 2 3 [Все]   Вверх
  Печать  
 

Powered by SMF 1.1.21 | SMF © 2015, Simple Machines