Инструменты пользователя

Инструменты сайта


examination:oop:question34

Вызов конструктора: назначение, способы реализации, задание аргументов. Явный и автоматический вызовы: ситуации использования, рекомендации по применению

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

Поскольку такая функция конструирует значение данного типа, она называется конструктором. Эту функцию легко распознать - она имеет то же имя, что и ее класс:

    class date { 
    // ... 
    date(int, int, int); 
    }; 

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

    date today = date(23,6,1983); 
    date xmas(25,12,0); // краткая форма 
    date my_birthday; // неправильно, нужен инициализатор 

Часто бывает удобно указать несколько способов инициализации объекта. Для этого нужно описать несколько конструкторов:

    class date { 
    int month, day, year; 
    public: 
    // ... 
    date(int, int, int); // день, месяц, год 
    date(int, int); // день, месяц и текущий год 
    date(int); // день и текущие год и месяц 
    date(); // стандартное значение: текущая дата 
    date(const char*); // дата в строковом представлении 
    }; 

Параметры конструкторов подчиняются тем же правилам о типах параметров, что и все остальные функции. Пока конструкторы достаточно различаются по типам своих параметров, транслятор способен правильно выбрать конструктор:

    date today(4); 
    date july4("July 4, 1983"); 
    date guy("5 Nov"); 
    date now; // инициализация стандартным значением 

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

В примере с date для каждого параметра можно задать стандартное значение, что означает: «взять значение из текущей даты».

    class date { 
    int month, day, year; 
    public: 
    // ... 
    date(int d =0, int m =0, y=0); 
    // ... 
    }; 
    date::date(int d, int m, int y) 
    { 
    day = d ? d : today.day; 
    month = m ? m : today.month; 
    year = y ? y : today.year; 
    // проверка правильности даты 
    // ... 
    } 

Когда используется стандартное значение параметра, оно должно отличаться от всех допустимых значений параметра. В случае месяца и дня очевидно, что при значении нуль - это так, но неочевидно, что нуль подходит для значения года. К счастью, в европейском календаре нет нулевого года, т.к. сразу после 1 г. до р.х.(year==-1) идет 1 г. р.х. (year==1). Однако для обычной программы это, возможно, слишком тонкий момент.

Объект класса без конструктора может инициализироваться присваиванием ему другого объекта этого же класса. Это незапрещено и в том случае, когда конструкторы описаны:

    date d = today; // инициализация присваиванием 

Автоматический и явный вызов конструктора

Если нет явным образом опредёленных конструкторов в классе, то компилятор использует конструктор по умолчанию, опредёленный неявным способом, который аналогичен «чистому» конструктору по умолчанию. Поэтому, класс не гарантирует наличия конструктора по умолчанию (то есть когда программист явным образом определяет только конструктор, который не по умолчанию). Некоторые программисты явным образом задают конструктор по умолчанию по привычке, чтобы не забыть в дальнейшем, но это не обязательно. В C++ только массивы имеют конструкторы по умолчанию, которые создают каждый элемент при помощи конструктора по умолчанию для их типа.

Если производный класс не вызывает явным образом конструктор базового класса, то конструктор по умолчанию вызывается неявно. Если базовый класс не имеет конструктора по умолчанию, то это считается ошибкой. В C++ если поле экземпляра класса явным образом не инициализировано в списке, то вызывается конструктор по умолчанию для инициализации этого поля. Если такой тип не имеет конструктора по умолчанию, то это также считается ошибкой.

examination/oop/question34.txt · Последние изменения: 2014/01/15 08:22 (внешнее изменение)