Избежание неявного преобразования в конструкторе: ключевое слово 'explicit' здесь не помогает
Задача заключается в том, чтобы запретить создание объекта класса A
при передаче параметра типа double
, даже если конструктор помечен как explicit
. Я хочу, чтобы объекты класса A
могли создаваться только при передаче целочисленного параметра, например, A a1 = A(10);
.
Вот мой код:
#include <iostream>
class A
{
public:
explicit A(int a)
{
num = a;
}
int num;
};
int main()
{
A a1 = A(10.0);
std::cout << a1.num;
return 0;
}
В текущей реализации я могу инициализировать объект A
, используя двойное значение A(20.2)
или даже A(10.0)
, что не соответствует желаемому поведению. Как я могу изменить класс A
, чтобы запретить создание объектов с параметрами, отличными от целых чисел?
5 ответ(ов)
Ваша ошибка происходит из-за использования удаленного конструктора в структуре A
. Давайте разберемся с вашим кодом и объясним, почему это происходит.
В структуре A
вы определили явный конструктор A(int a)
, который принимает целое число. Также вы добавили шаблонный конструктор A(T)
и пометили его как удаленный с помощью = delete;
. Это значит, что любой вызов конструктора с типом, отличным от int
, будет приводить к ошибке компиляции.
В вашем коде есть две строки, которые создают объекты класса A
:
//A a1 = A(10.0); // ошибка
A a2 = A(10); // нормально
Первая строка закомментирована и вызывает ошибку, так как вы пытаетесь создать объект A
с типом double
(вызов A(10.0)
), что приводит к активации удаленного конструктора A(T)
. Таким образом, компилятор генерирует ошибку, сообщая, что вы пытаетесь использовать удаленную функцию.
Вторая строка A a2 = A(10);
компилируется успешно, так как вы передаете целочисленное значение 10
, которое подходит для явного конструктора A(int)
.
Если вам нужно запретить использование других типов, кроме int
, такой подход совершенно корректен. Ваше использование explicit
и = delete;
для шаблонного конструктора позволяет точно ограничить доступные типы при создании экземпляров A
.
Таким образом, если вам нужно создать объект A
, просто убедитесь, что вы используете целочисленные типы, как это сделано в случае A(10)
.
Если у вас есть еще вопросы или нужно больше объяснений, не стесняйтесь задавать их!
Чтобы достичь этого, вам нужно добавить другой конструктор, который будет лучше соответствовать вашему случаю, а затем удалить
его, чтобы получить ошибку при попытке создания объекта. Для вашего класса добавьте следующее:
template <typename T>
A(T) = delete;
Это предотвратит создание экземпляров класса из любых типов, кроме int
.
Вы можете добавить, что A(double) = delete
— это новшество, введенное в C++11
.
Если по каким-то причинам вы не можете использовать этот относительно новый конструктив, вы можете просто объявить конструктор как private
, как показано ниже:
class A {
public:
A(int);
private:
A(double);
};
Таким образом, конструктор A(double)
будет недоступен для создания объектов этого класса вне его определения.
Чтобы явно удалить конструктор для типа double
, вы можете использовать следующий синтаксис:
A(double) = delete;
Это запрещает создание объектов класса A
с параметром типа double
. Если вам нужно добавить конструктор для типа float
, вы можете сделать это следующим образом:
A(float) {
// Реализация конструктора для типа float
}
Таким образом, вы ограничите использование конструктора только для типов float
и всех остальных, кроме double
. Не забудьте уточнить, если у вас есть другие требования или ограничения для вашего класса.
Вы можете использовать флаг -Wconversion компилятора gcc, который будет генерировать предупреждение при неявном преобразовании значения типа float
в int
. Также добавьте флаг -Werror, чтобы преобразовать это предупреждение (а также все остальные) в ошибку компиляции. Это поможет вам избежать потенциальных проблем с потерей данных при таких преобразованиях.
Когда действительно стоит использовать noexcept?
Возможно ли вывести тип переменной в стандартном C++?
Почему `std::initializer_list` не поддерживает оператор подиндексации?
Можно ли вручную определить преобразование для класса enum?
Стоит ли игнорировать предупреждение "-Wmissing-braces" от gcc/clang?