Конструктор по умолчанию c пример. Структуры и конструкторы по умолчанию. Пример конструктора при наследовании класса

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

Вот простой пример, как вы ответите на следующий вопрос: сколько значимых типов из. NET Framework содержит конструкторы по умолчанию? Интуитивным ответом кажется "все ", и будете не правы, поскольку на самом деле, ни один из значимых типов. NET Framework не содержит конструктора по умолчанию .

Работа с массивами – это не единственное место, когда существующий конструктор значимого типа вызван не будет. Следующая таблица дает понять, когда такой конструктор будет вызван, а когда нет.
// Вызывается var cvt = new CustomValueType(); // Вызывается var cvt = Activator.CreateInstance(typeof(CustomValueType)); // Не вызывется var cvt = default(CustomValueType); static T CreateAsDefault() { return default(T); } // Не вызывается CustomValueType cvt = CreateAsDefault(); static T CreateWithNew() where T: new() { return new T(); } // Не вызывается!! CustomValueType cvt = CreateWithNew(); // Не вызывается var array = new CustomValueType;

Хочу обратить внимание на рассогласованность поведения в следующем случае: известно, что создания экземпляра обобщенного (generic) параметра происходит с помощью Activator.CreateInstance , именно поэтому при возникновении исключения в конструкторе пользователь обобщенного метода получит его не в чистом виде, а в виде TargetInvocationException . Однако при создании экземпляра типа CustomValueType с помощью Activator .CreateInstance наш конструктор по умолчанию будет вызван, а при вызове метода CreateWithNew и создания экземпляра значимого типа с помощью new T () – нет.

Заключение

Итак, мы выяснили следующее:
  1. Конструктором по умолчанию в языке C# называется инструкция обнуления значения объекта.
  2. С точки зрения CLR конструкторы по умолчанию существуют и язык C# даже умеет их вызывать.
  3. Язык C# не позволяет создавать пользовательские конструкторы по умолчанию для структур, поскольку это привело бы к падению производительности при работе с массивами и существенной путанице.
  4. Работая на языках, поддерживающих создание конструкторов по умолчанию, их объявлять все равно не стоит по тем же причинам, по которым они запрещены в большинстве языков платформы.NET.
  5. Значимые типы не так просты как кажется: помимо проблем с изменяемостью (мутабельностью) у значимых типов даже с конструкторами по умолчанию и то не все просто.

Начнем с того, что когда мы создаем элементы (переменные) класса, мы не можем присвоить им значения в самом определении класса. Компилятор выдаст ошибку. Поэтому нам необходимо создавать отдельный метод (так называемую 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). «Последним пришёл - первым вышел».

Понятие «Конструктор» (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 вызывается автоматически, причем до конструктора экземпляра. Из этого следует, что статический конструктор должен выполняться до любого конструктора экземпляра. У статических конструкторов отсутствуют модификаторы доступа - они пользуются доступом по умолчанию, а следовательно, их нельзя вызывать из программы.

ВЫВОД

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

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

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); } }

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

Если нет явным образом опредёленных конструкторов в классе , то компилятор использует конструктор по умолчанию, опредёленный неявным способом, который аналогичен «чистому» [уточнить ] конструктору по умолчанию. Поэтому, класс не гарантирует наличия конструктора по умолчанию (то есть когда программист явным образом определяет только конструктор, который не по умолчанию). Некоторые программисты явным образом задают конструктор по умолчанию по привычке, чтобы не забыть в дальнейшем, но это не обязательно. В 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. Новый стандарт включает дополнения в ядре… … Википедия