Собственные методы класса



Собственные методы класса

Работая с классом, производным от класса MFC, разработчик не только вводит в него реакции на сообщения и переопределяет виртуальные функции. Он также вносит в класс свою собственную функциональность, вводя в него вспомогательные методы (helper functions). Сейчас мы создадим несколько таких функций. Новый метод ReadErrors будет заниматься поиском, чтением и анализом файла WinError.h.

  1. Переведите фокус мыши на узел CLookDlg в дереве классов Class View, вызовите контекстное меню и дайте команду Add > Add Function.
  2. В окне мастера Add Member Function Wizard заполните следующие поля:
    • Return type: bool,
    • Function name: ReadErrors.
    • В поле Access: задайте тип доступа — public.
    • В поле Comment: введите комментарий Search and read errors (моя версия Studio.Net не позволяет пользоваться русским языком в этом диалоге).


    Просмотрите изменения в классе CLookDlg, которые произвел мастер. Комментарий он помещает в файл заголовков (интерфейс класса). Введите следующий код в тело новой функции:

    bool CLookDlg: :ReadErrors ()

    {

    //==== Поиск и чтение информации об ошибках

    //==== Пытаемся найти путь в реестре

    string sPath = GetPathFromRegistry ( ) ;

    //==== В случае неудачи пытаемся узнать у пользователя

    if (sPath. empty () )

    sPath = GetPathFromUser О ; if (sPath.emptyO)

    return false; // При отказе уходим

    //==== Пытаемся открыть файл

    if stream is (sPath. c_str () ) ;

    if (!is) {

    MessageBox ("He могу найти WinError.h", "Выход") ;

    return false;

    //====== Последовательно ищем все ошибки

    while (GetNextErrorCode (is) )

    {

    //==== Создаем новый объект типа ErrorType и

    //==== помещаем его в контейнер

    m_Vector.push_back (ErrorType (gCode, gsID, gsMsg) ) ;

    }

    is. closet);

    // Закрываем файл

    //====== Запоминаем размер контейнера

    m_nltems = m_Vector . size () ;

    return bool (m_nltems != 0) ;

    }

    Здесь мы вызываем функции (Getxxx), которых еще нет. Это является типичной практикой разработки многомодульных приложений. Мы определяем прототипы функций так, как того требует логика алгоритма, а тела будут созданы позже. Вы должны обратить внимание на объявление объекта is класса ifstream, который определен в STL. Поставьте курсор на имя класса ifstream и воспользуйтесь окном Dynamic Help, для того чтобы получить справку об этом классе. Из нее вы мало что узнаете, так как, к сожалению, все справки по библиотеке STL в разделе Reference слишком краткие, но если использовать поиск, то в MSDN можно получить достаточно подробную информацию о потоковом вводе-выводе.

    В рассматриваемом коде мы вызываем конструктор класса ifstream, который создает поток ввода, связывает его с буфером и пытается открыть файл, путь к которому задан в параметре (sPath.c_str()). Вы помните, что вызов c_str() дает возможность пользоваться строкой в стиле языка с (то есть const char*), которая прячется в строке типа string. Операция "!", переопределенная в классе ifstream, сообщает нам о неудаче при открытии файла. Переменные gCode, gsio, gsMsg — это глобальные переменные, которые мы собираемся завести для временного хранения параметров ошибки (кода, индекса и сообщения).

    Примечание 1
    Примечание 1

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

    В начало файла LookDlg.cpp (после директивы #endif) введите определения глобальных данных, которые будут использованы как в методах класса, так и в глобальных функциях:

    //=== Текущие значения кода, индекса и текста сообщения

    string gCode, gsID, gsMsg;

    //====== Количество категорий (групп) ошибок

    const int N_FACILITIES = 23;

    //====== Имена категорий ошибок

    TCHAR *gsFacilities[N_FACILITIES + 1] = {

    "NULL", "RFC", "Dispatch",

    "Storage", "Interface", "Unknown",

    "Unknown", "Win32", "Windows",

    "SSPI", "Control", "Cert",

    "Internet", "MediaServer", "MSMQ",

    "SetupAPI", "Smart Card", "COM+",

    "AAF", "URT", "ACS",

    "DPlay", "UMI", "SXS" };

    Категории ошибок принято обозначать аббревиатурами, смысл которых можно выяснить в разделе Glossary MSDN. Например, аббревиатура RFC (Remote Procedure Call) обозначает категорию ошибок, связанных с обращением к процедурам, которые размещены на других процессорах сети.

    Повторите последовательность действий по введению в класс вспомогательной функции и создайте функцию Getlnfo. Она выбирает из контейнера структуру, которая соответствует ошибке с индексом nPos, и присваивает переменным, связанным с элементами управления в окне диалога, значения, которые характеризуют ошибку (атрибуты ошибки). После такой операции можно проводить обмен данными (UpdateData(FALSE)) с дочерними окнами диалога и они «высветят» ошибку.

    1. Переведите фокус мыши на узел CLookDlg в дереве классов Class View, вызовите контекстное меню и дайте команду Add > Add Function.
    2. В окне мастера Add Member Function Wizard заполните следующие поля: Return type: void, Function name: Getlnfo, Parameter type: int, Parameter name: nPos.
    3. Нажмите кнопку Add.
    4. В поле Access: задайте тип доступа public:

    void CLookDlg::GetInfo(int nPos)

    {

    // ======= Текущая позиция

    m_CurPos.Format("%d",nPos);

    if (nPos >= m_nltems)

    return;

    //======= Выбираем поля структуры

    m_Code = m_Vector[nPos].Code.c_str();

    m_Msg = m_Vector[nPos].Message.c_str() ;

    m_ID= m_Vector[nPos].Identifier.c_str();

    //====== Преобразование кода в целое число

    DWORD dw = strtoul(LPCTSTR(m_Code),0,0);

    //====== Выделяем старший бит (Severity)

    m_Severity = dw & 0x80000000 ? "Fail" : "Success";

    //=== СОМ-коды это НЕХ-коды, длина которых > 8 символов

    //=== В этой ветви мы обрабатываем Win32-ошибки

    if (m_Code.GetLength() < 8)

    {

    if (dw)

    {

    //====== Вставляем поля facility и severity

    dw = 0x80000000 | (0x7 << 16) | (dw f, OxFFFF) ;

    m_Severity = "Error";

    }

    }

    //====== Выделяем поле facility

    UINT f = (dw»16) & 0xlFFF;

    //====== Выбираем нужную аббревиатуру

    m_Facility = f <= N_FACILITIES |gsFacilities[f) : "Unknown";

    }

    Так как коды \Ут32-ошибок не имеют полей facility и severity (эти атрибуты появились позже), то их надо синтезировать. Таким же образом поступает макроподстановка HRESULT_FROM_wiN32, и ее можно использовать в этом месте, но мы (с учебной целью) вставили ее код. Если вы хотите опробовать макрос, то замените строку

    dw = 0x80000000 | (0x7 << 16) | (dw & 0xFFFF);

    на

    dw = HRESULT_FROM_WIN32(dw);

    Далее мы выделяем поле facility и выбираем из массива gsFacilities аббревиатуру, которая более информативна, чем число f, кодирующее facility.



    Содержание раздела