Конструкторы. Конструктор по умолчанию Конструкторы, параметризированные аргументами переменной длины

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

Тут нам как раз сможет помочь конструктор класса. Кстати, конструктор (от слова construct — создавать) – это специальный метод класса, который предназначен для инициализации элементов класса некоторыми начальными значениями.

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

Важно запомнить:

  1. конструктор и деструктор, мы всегда объявляем в разделе public ;
  2. при объявлении конструктора, тип данных возвращаемого значения не указывается, в том числе — void !!!;
  3. у деструктора также нет типа данных для возвращаемого значения, к тому же деструктору нельзя передавать никаких параметров;
  4. имя класса и конструктора должно быть идентично;
  5. имя деструктора идентично имени конструктора, но с приставкой ~ ;
  6. В классе допустимо создавать несколько конструкторов, если это необходимо. Имена, согласно пункту 2 нашего списка, будут одинаковыми. Компилятор будет их различать по передаваемым параметрам (как при перегрузке функций). Если мы не передаем в конструктор параметры, он считается конструктором по умолчанию;
  7. Обратите внимание на то, что в классе может быть объявлен только один деструктор;

Сразу хочу привести пример, который доступно покажет, как работает конструктор:

# include using namespace std; class AB //класс { private: int a; int b; public: AB() //это конструктор: 1) у конструктора нет типа возвращаемого значения! в том числе void!!! // 2) имя должно быть таким как и у класса (в нашем случае AB) { a = 0;//присвоим начальные значения переменным b = 0; cout << "Работа конструктора при создании нового объекта: " << endl;//и здесь же их отобразим на экран cout << "a = " << a << endl; cout << "b = " << b << endl << endl; } void setAB() // с помощью этого метода изменим начальные значения заданные конструктором { cout << "Введите целое число а: "; cin >> a; cout << "Введите целое число b: "; cin >> b; } void getAB() //выведем на экран измененные значения { cout << "a = " << a << endl; cout << "b = " << b << endl << endl; } }; int main() { setlocale(LC_ALL, "rus"); AB obj1; //конструктор сработает на данном этапе (во время создания объекта класса) obj1.setAB(); //присвоим новые значения переменным obj1.getAB(); //и выведем их на экран AB obj2; //конструктор сработает на данном этапе (во время создания 2-го объекта класса) return 0; }

Результат работы программы:

Работа конструктора при создании нового объекта: a = 0 b = 0 Введите целое число а: 34 Введите целое число b: 67 a = 34 b = 67 Работа конструктора при создании нового объекта: a = 0 b = 0

Как видно из результата работы программы, конструктор срабатывает сразу, при создании объектов класса, поэтому, явно вызывать конструктор не нужно, он сам «приходит»:)

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

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

# include using namespace std; class AB //класс { private: int a; int b; public: AB(int A, int B) //эти параметры мы передадим при создании объекта в main { a = A;//присвоим нашим элементам класса значения параметров b = B; cout << "Тут сработал конструктор, который принимает параметры: " << endl;//и здесь же их отобразим на экран cout << "a = " << a << endl; cout << "b = " << b << endl << endl; } void setAB() { cout << "Введите целое число а: "; cin >> a; cout << "Введите целое число b: "; cin >> b; } void getAB() { cout << "a = " << a << endl; cout << "b = " << b << endl << endl; } ~AB() // это деструктор. не будем заставлять его чистить память, пусть просто покажет где он сработал { cout << "Тут сработал деструктор" << endl; } }; int main() { setlocale(LC_ALL, "rus"); AB obj1(100, 100); //передаем конструктору параметры obj1.setAB(); //присвоим новые значения переменным obj1.getAB(); //и выведем их на экран AB obj2(200, 200); //передаем конструктору параметры }

Смотрим результат работы программы :

Тут сработал конструктор, который принимает параметры: a = 100 b = 100 Введите целое число а: 333 Введите целое число b: 333 a = 333 b = 333 Тут сработал конструктор, который принимает параметры: a = 200 b = 200 Тут сработал деструктор Тут сработал деструктор

Деструктор срабатывает в тот момент, когда завершается работа программы и уничтожаются все данные. Мы его не вызывали – он сработал сам. Как видно, он сработал 2 раза, так как и конструктор. Уже от себя добавлю, что, в первую очередь, он удалил второй созданный объект (где a = 200, b = 200), а затем первый (где a = 100, b = 100). «Последним пришёл - первым вышел».

Дело в том, что:

1. Если Вы создаете класс и в нем определяете конструктор с аргументами (класс AClass, у которого только один конструктор, который принимает int i), то компилятор уже не создаст конструктор по умолчанию. Потому что это нарушило бы контракт класса AClass, который не может быть инициализирован без аргументов. Если Вы хотите еще иметь и конструктор по умолчанию, задавайте теперь его явно.

Иначе нельзя было бы запретить создание конструктора по умолчанию, что было бы плохо.

2. При создании конструкторов класса BClass, который наследуется от другого класса, компилятор требует, чтобы первой строкой конструктора был вызов другого конструктора (унаследованного или в этом классе).

Почему? Потому что раз Вы наследуетесь от какого-то класса, Вы хотите повторно использовать его логику. Конструктор приводит экземпляр класса в какое-то начальное целостное состояние. В Вашем случае для инициализации AClass требует аргумент, без которого JVM не знает, как инициализировать экземпляр класса.

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

Public class AClass1 { }

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

Это эквивалентно такому определению:

Public class AClass1 { public AClass1() { } }

Теперь посмотрим на BClass1:

Public class BClass1 extends AClass1 { }

Здесь тоже явно конструкторы не определены, и компилятор пытается создать конструктор по умолчанию. Поскольку в классе AClass1 есть конструктор по умолчанию, он создаст конструктор по умолчанию, который будет вызывать конструктор AClass1. Этот код эквивалентен такому:

Public class BClass1 extends AClass1 { public BClass1() { super(); } }

В Вашем случае создается класс БЕЗ конструктора по умолчанию:

Public AClass { public AClass(int i) { } }

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

AClass a = new AClass(); // не работает

нужно что-то вроде

AClass a = new AClass(1);

Соответственно, любой конструктор BClass будет требовать вызова какого-либо конструктора AClass или BClass. При таком описании компилятор будет ругаться:

Public BClass extends AClass { }

Потому что будет попытка вызова конструкора по умолчанию класса AClass, который не определен:

Public BClass extends AClass { public BClass() { super(); // ошибка; в классе AClass нет такого конструктора } }

Тем не менее, можно создать класс BClass с конструктором по умолчанию, задав какое-то значение для конструктора AClass:

Public class BClass extends AClass { public BClass() { super(1); } }

Это будет компилироваться.

Понятие «Конструктор» (constructor) неотделимо от понятия класса. Конструкторы — это специальные функции, вызываемые автоматически при инициализации объектов. Их имена совпадают с именами классов, которым они принадлежат, и они не имеют типа возврата. У одного класса может быть более одного конструктора, различающихся сигнатурами. Конструкторы полезны для инициализации полей класса. Интересно, что компилятор создает конструктор по умолчанию без параметров, он устанавливает поля в 0, false или null (для объектов).

Рассмотрим пример. Создадим класс «Треугольник» с тремя полями и одним методом, вычисляющим его периметр.

Using System; namespace Конструктор { class Triangle { int a; int b; int c; public int perimeter() { return a + b + c; } } class Program { static void Main(string args) { Triangle tr = new Triangle(); // создаем объект Console.WriteLine("периметр = " + tr.perimeter()); Console.ReadKey(); } } }

периметр = 0

АНАЛИЗ

В окне ошибок первый раз появляются 3 предупреждения (но не ошибки!):
Полю «Конструктор.Triangle.c» нигде не присваивается значение, поэтому оно всегда будет иметь значение по умолчанию 0 (тоже для полей a и b ).

Так как сработал конструктор без параметров Triangle(), то всем сторонам треугольника был присвоен 0. Добавим в определение класса строку: Triangle(); и запустим программу. Получим сообщение об ошибке:
Тип «Конструктор.Triangle» уже определяет член «Triangle» с такими же типами параметров.
Это подтверждает тот факт, что конструктор с нулем параметров уже был создан. Теперь добавим в описание класса конструктор с тремя параметрами:

Public Triangle(int a, int b, int c) { this.a = a; this.b = b; this.c = c; }

А в метод Main() первую строку заменим на:

Triangle tr = new Triangle(3,4,5);

Результат выполнения программы: периметр = 12

То есть, мы выполнили инициализацию полей (a, b, c ) объекта tr , на что указывает ключевое слово this в операторах конструктора. Иначе нам бы пришлось указывать разные имена: a = d; где d был бы тогда первым элементом в списке параметров. Оператор типа a = a оставит значение поля a=0, а компилятор выдаст предупреждение:
Проведено присвоение той же переменной; действительно выполнить такое назначение, а не иное?

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

Напомним, что так как по умолчанию поля класса являются закрытыми (private), то их нельзя изменить непосредственно в программе, например:
tr.c = 7;
В этом случае получим сообщение об ошибке:
«Конструктор.Triangle.c» недоступен из-за его уровня защиты.

Ошибка устранится, если к описанию поля с добавим модификатор public:
public int c;
Однако это не является хорошим тоном в ООП, поле перестает быть защищенным.

В отличие от структур классы относятся к ссылочным (reference) типам данных, их экземпляры (объекты) “живут” в куче (heap). Поэтому при создании объекта резервируется для полей место в куче, и в зависимости от конструктора полям задаются значения 0, false или null (для конструктора по умолчанию), либо соответствующие значения (для конструктора с параметрами).

Проверьте на практике правильность следующих утверждений:

1) Можно ли создать конструктор по умолчанию? — Да.
2) Если создается свой конструктор, будет ли компилятор генерировать конструктор по умолчанию? — Нет.
3) Если в своём конструкторе не будут инициализированы некоторые поля, будут ли они автоматически инициализированы компилятором? — Да.
4) Разрешается ли инициализировать переменные там, где их объявляют? — Да.

Пример конструктора при наследовании класса

Воспользуемся готовым классом Random из библиотеки System. Создадим дочерний класс RwName («Random with Name»), добавим в него поле s и два метода, а также модифицируем конструктор класса:

Using System; namespace Конструктор { class RwName: Random { public string s; public RwName(string s) { this.s = s; } public double NextD() { return this.NextDouble(); } public void Rezult() { Console.WriteLine(this.s + this.NextDouble()); } } class Program { static void Main(string args) { RwName r = new RwName("Вещественное число: "); Console.WriteLine(r.NextD()); r.Rezult(); Console.ReadKey(); } } }

Теперь объект класса получит наименование через конструктор, а два метода класса стали более специфичными. Даже если вы не указали в объявлении класса имя «родителя», он все равно будет наследовать конструктор класса Object.

Статический конструктор

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

Using System; namespace Конструктор { class StatClass { public static int q; public int p; // Статический конструктор static StatClass() { q = 33; } // Обычный конструктор public StatClass() { p = 44; } } class Program { static void Main(string args) { StatClass ob = new StatClass(); Console.WriteLine("Доступ к полю p экземпляра: " + ob.p); Console.WriteLine("Доступ к полю q: " + StatClass.q); Console.ReadLine(); } } }

Важно, что конструктор типа static вызывается автоматически, причем до конструктора экземпляра. Из этого следует, что статический конструктор должен выполняться до любого конструктора экземпляра. У статических конструкторов отсутствуют модификаторы доступа - они пользуются доступом по умолчанию, а следовательно, их нельзя вызывать из программы.

ВЫВОД

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

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

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


Wikimedia Foundation . 2010 .

Смотреть что такое "Конструктор по умолчанию" в других словарях:

    Конструктор - получить на Академике рабочий купон на скидку Ашан или выгодно конструктор купить с бесплатной доставкой на распродаже в Ашан

    конструктор по умолчанию - Конструктор, создаваемый компилятором при отсутствии конструктора класса. [ГОСТ Р 54456 2011] Тематики телевидение, радиовещание, видео EN default constructor … Справочник технического переводчика

    У этого термина существуют и другие значения, см. Конструктор. В объектно ориентированном программировании конструктор класса (от англ. constructor, иногда сокращают ctor) специальный блок инструкций, вызываемый при создании объекта.… … Википедия

    В объектно ориентированном программировании конструктор класса (от англ. constructor, иногда сокращают ctor) специальный блок инструкций, вызываемый при создании объекта, причём или при его объявлении (располагаясь в стеке или в статической… … Википедия

    Конструктором копирования (в англоязычной литературе используется термин copy constructor) называется специальный конструктор в языке программирования C++, применяемый для создания нового объекта как копии уже существующего. Такой конструктор… … Википедия

    В компьютерном программировании нуль арным конструктором (в англ. языке используется термин nullary constructor) называют конструктор, не принимающий аргументы. Содержание 1 Объектно ориентированные конструкторы 1.1 … Википедия

    C++0x будущая версия стандарта языка C++, вместо ныне существующего ISO/IEC 14882:2003. Новый стандарт будет включать дополнения в ядре языка и расширение STL, включая большую часть TR1 кроме, вероятно, библиотеки специальных… … Википедия

    Стандартная библиотека языка программирования C++ fstream iomanip ios iostream sstream Стандартная библиотека шаблонов … Википедия

    Стандартная библиотека шаблонов (STL) (англ. Standard Template Library) набор согласованных обобщенных алгоритмов, контейнеров, средств доступа к их содержимому и различных вспомогательных функций. Стандартная библиотека шаблонов до включения в… … Википедия

    C++11 или ISO/IEC 14882:2011 (в процессе работы над стандартом носил условное наименование C++0x) новая версия стандарта языка C++, вместо ранее действовавшего ISO/IEC 14882:2003. Новый стандарт включает дополнения в ядре… … Википедия

Конструкторы

Перегруженные функции

В С#, как впрочем, и в других объектно-ориентированных языках программирования, можно объявить несколько функций с одинаковыми именами. Функции должны отличаться списком принимаемых параметров. Список может отличаться либо количеством, либо типом либо порядком следования параметров. Тип возвращаемого значения функции роли не играет. Термин перегрузка относится к имени функции. При вызове функций транслятор по списку параметров определяет, какая именно функция среди одноименных, должна быть вызвана. Примером перегрузки функций может служить определение в классе нескольких конструкторов.

Конструктор – это специальная функция класса, предназначенная для инициализации полей класса в момент создания объекта этого класса.

Имя конструктора всегда совпадает с именем класса.

Конструкторов в классе может быть несколько или ни одного.

На конструкторы накладываются следующие ограничения:

1. Конструктор не может иметь возвращаемого значения даже void

2. Как следствие 1 нельзя использовать оператор return

3. Конструкторы нельзя объявлять виртуальными.

Конструкторы, в отличие от C++ в C# можно объявлять со спецификациями public, private и protected. Конструктор со спецификацией public автоматически (не явно) вызывается на этапе компиляции при создании экземпляра данного класса. Попытка вызвать конструктор явным образом вызовет ошибку компиляции. Конструкторы со спецификацией private и protected могут быть вызваны только с помощью других конструкторов, объявленных со спецификацией public. Различают следующие типы конструкторов:

1. Конструктор по умолчанию

2. Конструктор с аргументами

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

Если в классе программистом не определен конструктор по умолчанию, то, в отсутствии других конструкторов, компилятор создает его сам. Конструктор по умолчанию, созданный компилятором, инициализирует все поля класса следующим образом – числовым значениям – ноль, булевским переменным – false, для строк значение пустой ссылки – null.

namespace ConsoleApplication15

class CA // В классе СА нет явно объявленных конструкторов

public int x,y,z;

static void Main(string args)

CA obj=new CA();

Console.WriteLine("x ={0,2} y ={1,2} z ={2,2}",obj.x,obj.y,obj.z);

Результат работы программы:

x = 0 y = 0 z = 0

Добавим в определение класса СА конструктор по умолчанию и проследим, как изменится результат работы приложения:


public int x,y,z;

public CA()

Результат работы программы:

x = 3 y = 2 z = 5

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

1. Какие способы передачи параметров методам определены в C#?

2. Чем отличается передача параметров методам с помощью модификатора ref от передачи параметров методам с помощью модификатора out?

3. Можно ли с помощью оператора return вернуть из метода ссылку на объект?

4. Можно ли с помощью оператора return вернуть из метода массив?

5. Как организовать передачу методам переменного количества параметров?

6. Чем отличается обращение к статическим методам класса от обращения к не статическим методам?

7. К каким членам класса могут обращаться статические функции класса?

8. К каким членам класса могут обращаться не статические функции класса?

9. Что такое перегрузка функции?

10. Являются ли функции, заголовок которых отличается только типом возвращаемого значения, перегруженными?

11. Как отличить конструктор класса от других функций класса?

12. Для чего используются конструкторы?

13. В каком случае компилятор сам создает конструктор по умолчанию?

14. Сколько в классе может быть объявлено не статических конструкторов по умолчанию?