Для создания "неконвертирующего" конструктора используйте спецификатор explicit.
В C++ определено ключевое слово explicit
, которое применяется для обработки специальных ситуаций, когда используются конструкторы определенных типов. Чтобы понять назначение спецификатора explicit, рассмотрим следующую программу.
#include
using namespace std;
class myclass {
int a;
public:
myclass(int x) { a = x; }
int geta() { return a; }
};
int main()
{
myclass ob(4);
cout << ob.geta();
return 0;
}
Здесь конструктор класса myclass
принимает один параметр. Обратите внимание на то, как объявлен объект ob в функции main(). Значение 4, заданное в круглых скобках после имени ob, представляет собой аргумент, который передается параметру x конструктора myclass(), а параметр x в свою очередь используется для инициализации члена a. Именно таким способом мы инициализируем члены класса с начала этой книги. Однако существует и альтернативный вариант инициализации. Например, при выполнении следующей инструкции член a также получит значение 4.
myclass ob = 4; /* Этот формат инициализации автоматически преобразуется в формат myclass(4). */
Как отмечено в комментарии, этот формат инициализации автоматически преобразуется в вызов конструктора класса myclass
, а число 4 используется в качестве аргумента. Другими словами, предыдущая инструкция обрабатывается компилятором так, как если бы она была записана:
myclass ob(4);
В общем случае всегда, когда у вас есть конструктор, который принимает только один аргумент, для инициализации объекта можно использовать любой из форматов: либо ob(х)
, либо ob=х. Дело в том, что при создании конструктора класса с одним аргументом вами неявно создается преобразование из типа аргумента в тип этого класса.Если вам не нужно, чтобы такое неявное преобразование имело место, можно предотвратить его с помощью спецификатора explicit
. Ключевое слово explicit применяется только к конструкторам. Конструктор, определенный с помощью спецификатора explicit, будет задействован только в том случае, если для инициализации членов класса используется обычный синтаксис конструктора. Никаких автоматических преобразований выполнено не будет. Например, объявляя конструктор класса myclass с использованием спецификатора explicit, мы тем самым отменяем поддержку автоматического преобразования типов. В этом варианте определения класса функция myclass() объявляется как explicit-конструктор.
#include
using namespace std;
class myclass {
int a;
public:
explicit myclass(int x) { a = x; }
int geta() { return a; }
};
Теперь будут разрешены к применению только конструкторы, заданные в таком формате.
myclass ob(110);
Чем интересно неявное преобразование конструктора
Автоматическое преобразование из типа аргумента конструктора в вызов конструктора само по себе имеет интересные последствия. Рассмотрим, например, следующий код.
#include
using namespace std;
class myclass {
int num;
public:
myclass(int i) { num = i; }
int getnum() { return num; }
};
int main()
{
myclass о(10);
cout << o.getnum() << endl; // отображает 10
/* Теперь используем неявное преобразование для присвоения нового значения. */
о = 1000;
cout << o.getnum() << endl; // отображает 1000
return 0;
}
Обратите внимание на то, что новое значение присваивается объекту о
с помощью такой инструкции:
о = 1000;
Использование данного формата возможно благодаря неявному преобразованию из типа int
в тип myclass, которое создается конструктором myclass(). Конечно же, если бы конструктор myclass() был объявлен с помощью спецификатора explicit, то предыдущая инструкция не могла бы выполниться.Синтаксис инициализации членов класса
В примерах программ из предыдущих глав члены данных получали начальные значения в конструкторах своих классов. Например, следующая программа содержит класс myclass
, который включает два члена данных numA и numB. Эти члены инициализируются в конструкторе myclass().
#include
using namespace std;
class myclass {
int numA;
int numB;
public: