Что означают ключевые слова default и delete в конструкторах и методах?
Создаю собственный класс unique ptr, и при поиске информации заметил, что нужно писать некоторые методы и конструкторы вот так:
UniquePtr() = default; UniquePtr &operator=(const UniquePtr &object) = delete;
Как в данном случае работают ключевые слова default и delete?
Отслеживать
задан 24 мар 2022 в 15:24
yarik test yarik test
1 1 1 бронзовый знак
конструируется по умолчанию и лишен возможности присваивания(удаленный оператор)
24 мар 2022 в 15:47
default говорит компилятору, что Вы хотите, то бы он написал реализацию по умолчанию. Иногда это нужно явно, что бы он гарантированно добавил нужную функцию. delete говорит, что такой функции не будет/не нужно генерировать. Раньше делали приватную функцию без тела, но ошибка была в процессе линковки и это приводило к разнообразным странных ошибкам. Эта штука полезна при написании синглтонов или некопируемых объектов.
24 мар 2022 в 16:35
Я просто не понимаю, если мы не хотим использовать метод/функцию, то зачем нам ее в целом объявлять или описывать, чтобы следовать правилу пяти, что конструктор присваивания обязан быть, даже если его функционал не нужен?
24 мар 2022 в 17:08
24 мар 2022 в 23:30
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
Последний ваш комментарий натолкнул меня ответить. Нет, не для того, чтобы лишь бы следовать каким то правилам, а для того, чтобы явно иметь то, что вы хотите иметь.
Бывают ситуации, когда явно нужно указать компилятору, что он должен генерировать конструктор(или другую функцию_член) по умолчанию. Вот простой пример:
class UniquePtr < int* p<>; size_t sz<>; public: UniquePtr(const int* array, const size_t size) : p(array), sz(size) <> //. >;
Мы имеем конструктор с двумя аргументами, и так как мы сами написали конструктор, компилятор самостоятельно не будет генерировать другой конструктор(не имеет право), поэтому мы не сможем создать объект типа UniquePtr без аргументов для конструирования. Но если добавить UniquePtr() = default; , то можно свободно создать UniquePtr ptr
Почему это удобнее и безопаснее, чем старый способ присвоения аргументам каким то значениям по умолчанию(иногда это невозможно(например для константных аргументов) или слишком длинно и является источником путаницы), является другой темой.
UniquePtr &operator=(const UniquePtr &object) = delete;
равносильно заключении функции в приватной зоне, но в некоторых случаях этот способ дает больше гарантии для избежании от неявных ошибок(смотри комментарий от KoVadim ) , делает интерфейс более наглядным.
Default c что это
Конструкция switch-case позволяет сравнить некоторое выражение с набором значений. Она имеет следующую форму:
switch(выражение)
После ключевого слова switch в скобках идет сравниваемое выражение. Значение этого выражения последовательно сравнивается со значениями после оператора сase . И если совпадение будет найдено, то будет выполняться определенный блок сase .
Стоит отметить, что сравниваемое выражение в switch должно представлять один из целочисленных или символьных типов или перечисление (рассматриваются далее).
В конце конструкции switch может стоять блок default . Он необязателен и выполняется в том случае, если значение после switch не соответствует ни одному из операторов case. Например:
#include int main() < int x ; switch(x) < case 1: std::cout >
Чтобы избежать выполнения последующих блоков case/default, в конце каждого блока ставится оператор break . То есть в данном случае будет выполняться оператор
case 2: std::coutПосле выполнения оператора break произойдет выход из конструкции switch..case, и остальные операторы case будут проигнорированы. Поэтому на консоль будет выведена следующая строка
x = 2Стоит отметить важность использования оператора break . Если мы его не укажем в блоке case , то после этого блока выполнение перейдет к следующему блоку case. Например, уберем из предыдущего примера все операторы break:
#include int main() < int x ; switch(x) < case 1: std::cout >В этом случае опять же будет выполняться оператор case 2: , так как переменная x=2. Однако так как этот блок case не завершается оператором break, то после его завершения будет выполняться набор инструкций после case 3: даже несмотря на то, что переменная x по прежнему равна 2. В итоге мы получим следующий консольный вывод:
x = 2 x = 3 x is undefinedСовмещение условий
Можно определять для нескольких меток case один набор инструкций:
#include int main() < int x ; switch(x) < case 1: case 2: std::cout >Переменные в блоках case
Определение переменных в блоках case , возможно, встречается нечасто. Однако может вызвать затруднения. Так, если переменная определяется в блоке case, то все инструкции блока помещаются в фигурные скобки (для блока default это не требуется):
#include int main() < int x ; switch(x) < case 1: < int a; std::cout case 2: < int b; std::cout default: int c; std::cout >Блок switch с инициализацией переменной
Иногда в конструкции switch для различных промежуточных вычислений необходимо определить переменную. Для этой цели начиная со стандарта C++17 язык С++ поддерживает особую форму конструкции switch :
switch(инициализация; выражение) < // . >Подобная форма также принимает выражение, значение которого сравнивается с константами после операторов case . Но теперь перед выражением еще может идти определение и инициализация переменной. Например:
#include int main() < char op = '+'; int n = 10; switch(int k; op) < case '+': std::cout >В данном случае в конструкции switch определяется переменная k , которая доступна только в рамках этой конструкции switch . В качестве выражения используется значение переменной op , которая представляет знак операции. И в зависимости от этого значения, выполняем определенную операцию с переменными n и k.
Что означают ключевые слова default, delete и зачем они нужны
Собственно сабж.
Часто встречаю что методу можно присвоить какое то значение, например virtual void method() = 0 означает что этот метод должен быть реализован наследником и у него нет тела в момент объявления.Но что означает default и delete тогда когда они вместо нуля после функции?
Искал в тырнете, но плохо понял
Прошу пояснить кто знает, хочу знать где этим можно и даже нужно пользоватьсяИ ещё куда происходит присвоение? Метод же это не переменная что бы писать method() = 0
Где то под капотом есть указатель на этот метод и присвоение этого значения происходит именно этому указателю?Добавлено через 1 минуту
Заголовок у меня плохой, модераторы, поправьте пожалуйста
Что означают ключевые слова default, delete в описании функции и зачем они нужны
Думаю так лучшеЛучшие ответы ( 1 )
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
Ответы с готовыми решениями:Что за векторы и зачем они нужны
Читал книгу по программированию на С++ и дошел до раздела векторы. Вот хотел у вас спросить за чем.
Что такое атрибуты и зачем они нужны?
Нужен человек, который может объяснить, что такое атрибуты и зачем они нужны, на как можно более.Что такое классы и зачем они нужны?
Здравствуйте! Объясните ,что такое классы и зачем они нужны? Я прочитал кучу всего про классы, но.Что такое комплекты инициализации и зачем они нужны?
Что такое комплекты инициализации и зачем они нужны? Например комплект инициализации к Xerox.Форумчанин
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
Сообщение от sys_beginner
virtual void method() = 0
Называется чисто виртуальная функция.
Сообщение от sys_beginner
Присвоить реализацию по умолчанию.
Сообщение от sys_beginner
Пометить функцию как удалённую. Любое обращение к ней будет вызывать ошибку компиляции. Делаем это явно, а не костылим как в С++98, запихнув определение в Private секцию.
850 / 438 / 89
Регистрация: 10.06.2014
Сообщений: 2,611
Сообщение от MrGluck
Присвоить реализацию по умолчанию.
Читал такое и не понял. Компилятор же сам добавляет реализацию по умолчанию зачем это писать?
Сообщение от MrGluck
Пометить функцию как удалённую.
Правильно ли я понимаю это нужно использовать что бы:
1. Предотвратить обращение к методу использование которого не предусмотрено для объектов этого класса
2. Что бы компилятор не добавлял реализацию по умолчанию и исходный код стал меньше?
3. Это касается только тех методов которые компилятор генерирует по умолчанию?Форумчанин
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
Сообщение от sys_beginner
этим можно и даже нужно пользоваться
Пример с default:
Мы определяем явно какой-нибудь конструктор с параметрами. Но при этом хотим оставить конструктор по умолчанию, при этом нас устраивает стандартная его реализация. Мы можем объявить его, добавив на конце = default и всё, тело не нужно описывать явно, вдобавок это повышает вероятность, что читавший поймёт наши намерения.
Другой пример. Как нам известно, деструктор, генерируемый компилятором по умолчанию не виртуальный. Но если класс предполагает наследников, нам нужно сделать его виртуальным для правильного полиморфного удаления объекта. В классе не используется динамическая память и нас устраивает то, что компилятор сгенерирует по умолчанию. Мы объявляем деструктор явно, указав что он виртуальный и добавляем на конец = default, подчёркивая тем самым, что единственная причина определения явно - добавление виртуальности.850 / 438 / 89
Регистрация: 10.06.2014
Сообщений: 2,611
И есть ли ещё ключевые слова для таких вещей кроме как delete default и 0?
Форумчанин
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
Сообщение от sys_beginner
delete default
const override final
8737 / 4315 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
Сообщение от sys_beginner
означает что этот метод должен быть реализован наследником и у него нет тела в момент объявления.
оно может не быть. а может и быть.
никто не запрещает написать тело для чисто-виртуальной функции.1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20#include struct base { // как известно, все без исключения объекты // обязаны иметь деструктор virtual ~base() = 0; }; base::~base() { std::cout "base::base\n"; } struct der: base{}; int main() { der d; }
Сообщение от sys_beginner
указание компилятору,
что бы он сам создал реализацию по дефолту
Сообщение от sys_beginner
что реализации нет.
например, если нужно запретить конструктор копии.
попытка сделать копию будет приводить к ошибке компиляции.
Сообщение от sys_beginner
И ещё куда происходит присвоение?
это не присвоение.
просто такой способ обозначить,
что функция - чисто-виртуальная.
Форумчанин
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
Сообщение от sys_beginner
не ключевое слово, а способ пометить виртуальную функцию как чисто виртуальную. Это вообще отношения не имеет к теме keyword.
Добавлено через 1 минуту
Сообщение от sys_beginner
Компилятор же сам добавляет реализацию по умолчанию зачем это писать?
Есть случаи, когда компилятор не генерирует уже реализацию по умолчанию или нас не устраивает сигнатура, а реализация подходит. Примеры я указал выше.
850 / 438 / 89
Регистрация: 10.06.2014
Сообщений: 2,611
Сообщение от MrGluck
const override final
Это же вроде без присвоения пишется. Имелось ввиду именно там где между ключевым словом и функцией нет оператора присваивания
MrGluck,
Про default это всмысле когда мы создаем конструктор явно, конструктор по умолчанию не добавляется
Но если он нужен просто пишем defaultConstructor() = default и без описания тела просим компилятор его добавить
Так?
Сообщение от MrGluck
не ключевое слово, а способ пометить виртуальную функцию как чисто виртуальную. Это вообще отношения не имеет к теме keyword.
Ага. Просто для простоты изложения мысли обобщил
Сообщение от MrGluck
Есть случаи, когда компилятор не генерирует уже реализацию по умолчанию
А, понял. Это может произойти только в определенных ситуациях а не так что бы "может быть может не быть, зависит от погоды на марсе". понял спасибо
Добавлено через 1 минуту
Сообщение от hoggy
никто не запрещает написать тело для чисто-виртуальной функции.
Тогда наверное и смысла нет отмечать её как виртуальную если нет наследников
Добавлено через 29 секунд
Сообщение от hoggy
попытка сделать копию будет приводить к ошибке компиляции
И исходного кода меньше будет, да?
Форумчанин
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
Сообщение от sys_beginner
Имелось ввиду именно там где между ключевым словом и функцией нет оператора присваивания
Я привёл в пример ключевые слова. Если вы про возможные конструкции, которые могут идти после символа = при объявлении специального метода, то кроме приведённых трёх вариантов (default, delete, 0) я более не знаю. Хотя повторюсь, неправильно было бы ставить ноль с ключевыми словами в один ряд.
Добавлено через 24 секунды
Сообщение от sys_beginner
Но если он нужен просто пишем defaultConstructor() = default и без описания тела просим компилятор его добавить
Так?Добавлено через 2 минуты
Сообщение от sys_beginner
смысла нет отмечать её как виртуальную если нет наследников
Функцию помечают как виртуальную если она потенциально может иметь наследников.
Но там говорилось про другое. Чисто виртуальная функция - эта не просто функция, которая не имеет реализацию (как некоторые ошибочно полагают).850 / 438 / 89
Регистрация: 10.06.2014
Сообщений: 2,611MrGluck,
Спасибо что объяснили.
Сообщение от MrGluck
Хотя повторюсь, неправильно было бы ставить ноль с ключевыми словами в один ряд.
Согласен)) Просто так проще выразиться, а народ здесь подкованный, сразу понимает о чем речь
Добавлено через 33 секунды
Сообщение от MrGluck
Но там говорилось про другое. Чисто виртуальная функция - эта не просто функция, которая не имеет реализацию (как некоторые ошибочно полагают).
Добавлено через 37 секунд
Так а кода все таки меньше генерируется если использовать delete?Форумчанин
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
Касаемо ситуации с виртуальным деструктором (на всякий случай хочу разъяснить).1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18#include struct base { //virtual ~base() = default; }; struct der: base { ~der() { std::cout "der::der\n"; } }; int main() { base *d = new der; delete d; }Для вызова деструктора производного класса при удалении объекта производного класса размещённого динамически через указатель на базовый класс, необходимо раскомментировать 5 строку.
Добавлено через 1 минуту
Сообщение от sys_beginner
Так а кода все таки меньше генерируется если использовать delete?
Учитывая, что это ключевое слово влияет только на компиляцию - одинаково. То есть есть обращение - delete не даст скомпилировать. Нет обращения - и генерировать нечего.
850 / 438 / 89
Регистрация: 10.06.2014
Сообщений: 2,611
Сообщение от MrGluck
~base() = default;
А разве не нужно писать ключевое слово virtual перед ~?
8737 / 4315 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
Сообщение от sys_beginner
Тогда наверное и смысла нет отмечать её как виртуальную если нет наследников
разумеется.
виртуальные функции пишутся виртуальными именно в расчете на то,
что наследники будут.
Сообщение от sys_beginner
И исходного кода меньше будет, да?
даже не знаю, как отвечать на такой нелогичный вопрос.
исходного кода будет ровно столько,
сколько вы сами его напишите.Форумчанин
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
Сообщение от sys_beginner
А разве не нужно писать ключевое слово virtual перед ~?
В примере демонстрируется что будет если его не написать. Как бы ключевое слово специально поставлено в комментариях.
850 / 438 / 89
Регистрация: 10.06.2014
Сообщений: 2,611
Сообщение от hoggy
исходного кода будет ровно столько,
сколько вы сами его напишите.Имелось ввиду исполняемый код
Читал в разных местах что компилятор может выбрасывать то что не нужно
Вот и подумал если реализация по умолчанию объявляется delete
То выбросит ли компилятор (или просто не сгенерирует) код который генерировал по умолчанию?Добавлено через 2 минуты
Сообщение от MrGluck
В примере демонстрируется что будет если его не написать.
))) Понял. Об этом читал ещё где то пол годика назад. Но за пример все равно спасибо
Память освежаю
8737 / 4315 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
Сообщение от sys_beginner
Вот и подумал если реализация по умолчанию объявляется delete
То выбросит ли компилятор (или просто не сгенерирует) код который генерировал по умолчанию?конечно выбросит.
850 / 438 / 89
Регистрация: 10.06.2014
Сообщений: 2,611MrGluck, hoggy,
Подскажите пожауйлста, где можно посмотреть какие методы компилятор генерирует автоматически и их сигнатуры что бы смотреть на список и исключать то что не нужно c помощью delete?Например для классов которые содержат только простые типы насколько понимаю не нужен конструктор перемещения
и хотелось бы не полагаться на то что "компилятор может понять что не нужно его генерировать или не понять" а явно удалить так же и остальными автоматически генерируемыми методами и так понятнее будет выглядеть код
8737 / 4315 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
Сообщение от sys_beginner
Подскажите пожауйлста, где можно посмотреть какие методы компилятор генерирует автоматически и их сигнатуры
в стандарте языка
Сообщение от sys_beginner
и исключать то что не нужно c помощью delete?
исключать нужно лишь то, что способно нарушить работу.
все остальное - проблемы компилятора.
Форумчанин
8215 / 5045 / 1437
Регистрация: 29.11.2010
Сообщений: 13,453
Сообщение было отмечено Undisputed как решение
Решение
Сообщение от sys_beginner
где можно посмотреть какие методы компилятор генерирует автоматически и их сигнатуры что бы смотреть на список и исключать то что не нужно c помощью delete?
В стандарте. Глава 12 Special member functions
Есть, например, правило трёх (начиная с С++11 некоторые ещё определяют правило пяти, с версиями rvalue):
Если в классе идёт работа с динамической памятью, в нём необходимо явно определить конструктор копий, оператор присваиваний и деструктор.
Для того, чтобы понять нужно ли описывать специальные методы класса явно или хватит реализации по умолчанию, необходимо хорошо понять как устроена реализация по умолчанию. Это и принципы генерации (при каком условии что генерируется, а что нет), указано в стандарте.Добавлено через 7 минут
Выдержка из стандарта насчёт генерации специальных методов классаКонструктор по умолчанию:
12.1 Constructors
4. A default constructor for a class X is a constructor of class X that can be called without an argument. If
there is no user-declared constructor for class X, a constructor having no parameters is implicitly declared
as defaulted (8.4). An implicitly-declared default constructor is an inline public member of its class. A
defaulted default constructor for class X is defined as deleted if:
— X is a union-like class that has a variant member with a non-trivial default constructor,
— any non-static data member with no brace-or-equal-initializer is of reference type,
— any non-variant non-static data member of const-qualified type (or array thereof) with no brace-or
equal-initializer does not have a user-provided default constructor,
— X is a union and all of its variant members are of const-qualified type (or array thereof),
— X is a non-union class and all members of any anonymous union member are of const-qualified type
(or array thereof),
— any direct or virtual base class, or non-static data member with no brace-or-equal-initializer , has class
type M (or array thereof) and either M has no default constructor or overload resolution (13.3) as applied
to M’s default constructor results in an ambiguity or in a function that is deleted or inaccessible from
the defaulted default constructor, or
— any direct or virtual base class or non-static data member has a type with a destructor that is deleted
or inaccessible from the defaulted default constructor.5. A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr
used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration.Ключевые слова default , delete . Примеры использования
Ключевое слово default введено в C++ 11. Его использование указывает компилятору самостоятельно генерировать (использовать) соответствующую функцию класса, если таковая не объявлена в классе.
Как известно, компилятор автоматически генерирует ряд конструкторов класса и деструктор. Указание ключевого слова default для этих функций дает следующие взаимосвязанные преимущества:
- программист получает понятную информацию об отсутствии реализации отдельных функций в классе. Используються компиляторные версии этих функций;
- упрощается восприятие информации об особенностях использования тех или иных функций класса. Вместо того чтобы вспоминать правила программист указывает то, что хочет получить.
Общая форма использования ключевого слова default для конструкторов класса следующая:
class ClassName < // . ClassName(parameters) = default; // . >;
- ClassName – имя класса, в котором использовано ключевое слово default ;
- ClassName(parameters) – один из конструкторов класса, которые автоматически генерируются компилятором;
- parameters – список параметров, который принимает специальная функция класса, которая генерируется автоматически. Список параметров может отсутствовать (конструктор по умолчанию).
Общая форма использования ключевого слова default для деструктора класса
class ClassName < // . ~ClassName() = default; // . >;
2. К каким специальным функциям класса может быть применено ключевое слово default ?
Ключевое слово default может применяться только к специальным функциям класса, которые при объявлении класса генерируются компилятором автоматически. К таким функциям относятся:
- конструктор по умолчанию (default constructor);
- конструктор копирования (copy constructor);
- конструктор перемещения (move constructor);
- оператор присваивания копированием (copy assignment operator);
- оператор присваивания перемещением (move assignment operator);
- деструктор (destructor).
3. Пример использования ключевого слова default для специальных функций класса, которые генерируются компилятором автоматически
Ниже продемонстрировано использование ключевого слова default для всех специальных функций класса, которые генерируются автоматически.
Объявляется класс Float , реализующий вещественное число.
В классе объявляются:
- внутренняя скрытая ( private ) переменная x ;
- default-конструктор по умолчанию;
- default-конструктор копирования;
- default-конструктор перемещения;
- default-оператор присваивания, выполняющий копирование;
- default-оператор присваивания, выполняющий перемещение;
- default-деструктор;
- методы доступа Get() , Set() .
// класс Float-демонстрация ключевого слова default class Float < private: float x; public: // Конструктор по умолчанию // ключевое слово default указывает компилятору самостоятельно формировать // соответствующий конструктор, если такой не объявлен в классе Float() = default; // конструктор с 1 параметром - не может быть применено default Float(float _x) :x(_x) < >// конструктор копирования - передача прав компилятору на формирование этого конструктора Float(const Float&) = default; // конструктор перемещения Float(Float&&) = default; // оператор присваивания копированием Float& operator=(const Float&) = default; // оператор присваивания перемещением Float& operator=(Float&&) = default; // деструктор ~Float() = default; // методы доступа float Get() < return x; > void Set(float _x) < x = _x; >>; int main() < // default - конструктор Float f1(7); Float f2 = f1; cout "f2.x color: #800000;">"f3.x color: #333300;">⇑4. Назначение ключевого слова delete. Общая форма объявления конструктора и метода класса с ключевым словом delete
Ключевое слово delete используется в случаях, когда нужно запретить автоматическое приведение типов в конструкторах и методах класса.
Общая форма объявления конструктора класса с ключевым словом delete
class ClassName < // . // конструкторы, которые запрещено использовать ClassName(parameters1) = delete; ClassName(parameters2) = delete; // . ClassName(parametersN) = delete; // . >;
- parametes1 , parameters2 , …, parametersN – список параметров соответствующего конструктора класса.
Параметры могут отсутствовать. Если параметры конструктора отсутствуют, то запрещено использовать конструктор по умолчанию. В этом случае при объявлении
ClassName obj1;
компилятор будет выдавать ошибку
The default constructor of "ClassName" cannot be referenced – it is a deleted function
Ключевое слово delete может быть запрещено также и в методах. В этом случае, для метода с именем Func() общая форма объявления будет следующая
class ClassName < // . return_type Func(parameters) = delete; // . >;
- Func() – имя функции которую нужно запретить использовать в классе;
- parameters – параметры функции;
- return_type – тип, возвращаемый функцией.
5. Пример использования ключевого слова delete в классе
Задан класс Point реализующий точку на плоскости. В классе объявляются следующие элементы:
-
- внутренние скрытые ( private ) переменные с именами x , y – координаты точки;
- конструктор по умолчанию Point() , обозначенный ключевым словом default . Ключевое слово default указывает, что должен выполняться неявный конструктор по умолчанию, который автоматически генерируется компилятором;
- конструктор Point(int) с одним параметром типа int ;
- конструктор с двумя параметрами Point(int, int) ;
- методы доступа GetX() , GetY() , SetX() , SetY() ;
- операторная функция operator+() , перегружающая бинарный оператор + ;
- операторная функция operator-() , перегружающая унарный оператор – .
В классе запрещается использовать конструктор с одним параметром Point(double) , принимающий параметр типа double . Этот конструктор обозначен ключевым словом delete . Однако, конструктор с параметром типа int разрешено использовать в классе.
Также запрещается использовать некоторые функции:
- функцию SetX(double) с параметром типа double . Однако, Set(int) с параметром типа int разрешается использовать;
- функцию SetXY(int, int) с двумя параметрами типа int .
Текст класса Point следующий:
#include using namespace std; // Класс, реализующий точку на координатной плоскости // в классе иследуются ключевые слова default и delete class Point < private: int x = 0; // координаты точки int y = 0; public: // default-конструктор, доверить реализацию компилятору Point() = default; // конструктор с одним параметром типа double - запрещено использовать Point(double value) = delete; // конструктор с одним параметром типа int - разрешено использовать Point(int value) < x = y = value; > // конструктор с 2 параметрами Point(int nx, int ny) < x = nx; y = ny; > // методы доступа к членам класса int GetX(void) < return x; > int GetY(void) < return y; > // функции SetX(), SetY() c параметром типа int void SetX(int nx) < x = nx; >void SetY(int ny) < y = ny; > // запретить вызов функции SetX(), SetY() с параметром типа double void SetX(double) = delete; // информация для компилятора, что запрещено использовать // метод SetXY() с двумя параметрами int void SetXY(int, int) = delete; // сам метод SetXY - ненужен, компилятор выдает ошибку /* void SetXY(int nx, int ny) x = nx; y = ny; > */ // перегруженный бинарный оператор '+' Point operator+(Point& pt) < // p - временный объект, который создается с помощью конструктора без параметров Point p; p.x = x + pt.x; p.y = y + pt.y; return p; > // перегруженный унарный оператор '-' Point operator-(void) < Point p; p.x = -x; p.y = -y; return p; > void Show(const char* objName) < cout ":" "x color: #800000;">"; y color: #0000ff;">void main() < // 1. Объявление объекта с использованием конструктора с 1 параметром // 1.1. Ошибка компилятора //Point p1(5.5); //конструктор с 1 параметром типа double запрещен // 1.2. Разрешено использовать конструктор с 1 параметром типа int Point p1(5); p1.Show("p1"); // 1.3. Запрещено использовать метод SetX() с параметром типа double // p1.SetX(5.5); p1.SetY(3.8); // а метод SetY() можно использовать p1.Show("p1"); // 2. Объявление объекта без параметров - вызывается default-конструктор Point p3; // вызывается default-конструктор компилятора p3.Show("p3"); // Объявление объекта с помощью конструктора с 2 параметрами Point p4(7, 8); p4.Show("p4"); >
Объясним некоторые фрагменты кода. Если в функции main() указать
Point p1(5.5);то компилятор выдаст ошибку
(double)(5.5) Function "Point::Point(double value)" declared at line (18) cannot be referenced - it is a deleted function
Это означает, что запрещено использовать конструктор с 1 параметром типа double . Однако, разрешено использовать конструктор с 1 параметром типа int , так как этот конструктор указан без ключевого слова delete .
В классе Point ключевое слово delete также применяется к функции
void SetX(double) = delete;
Это означает, что запрещено вызывать функцию SetX() с параметром типа double . Однако класс содержит другую функцию SetX() с параметром типа int
void SetX(int nx)
которую разрешено вызывать. Таким образом в функции SetX() запрещается автоматическое приведение из типа double в тип int . По подобному примеру можно запретить автоматическое приведение типов для любых функций классов.
В демонстрационных целях показано, что в классе Point запрещено использовать функцию SetXY() с двумя параметрами
void SetXY(int, int) = delete;
Хотя, другой реализации данной функции в классе нет. Подобные запреты не реализованных функций в классе нормально воспринимаются компилятором.
Связанные темы

