Форум программистов, компьютерный форум CyberForum.ru
Наши страницы

С++ для начинающих

Войти
Регистрация
Восстановить пароль
 
Рейтинг: Рейтинг темы: голосов - 47, средняя оценка - 4.79
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
#1

explicit и последствия. - C++

20.12.2011, 06:52. Просмотров 6775. Ответов 11
Метки нет (Все метки)

Здравствуйте. Как я узнал, в С++ есть ключевое слово explicit, применяемое к конструкторам с одним параметром ( или, как я понял, большим числом параметров при условии, что все, кроме первого, имеют значения по умолчанию ) для избежания неявных преобразований типов. Возникла небольшая проблема, или скорее вопрос. Как теперь можно сделать доступной инициализацию такого вида на примере моего класса:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class hugeInt {
    friend std::ostream &operator<<( std::ostream &, const hugeInt & );
    friend std::istream &operator>>( std::istream &, hugeInt & );
 
public:
    explicit hugeInt();
    explicit hugeInt( const long long );
    explicit hugeInt( const char * );
    ~hugeInt();
 
    bool operator!() const;
    bool operator==( const hugeInt & ) const;
    hugeInt operator=( const hugeInt & );
    hugeInt operator=( const long long & );
 
private:
    int *numberPtr;
    size_t size;
 
    int charToDigit( const char & );
    size_t digitsInInt( const long long & );
 
    void setNum( const long long & );
    void setNum( const char * );
};
При таком объявлении и инициализации:
C++
1
2
3
4
5
6
int main()
{
    hugeInt a = 100;
 
    return 0;
}
выскакивает ошибка компиляции:
...\practice\practice\main.cpp(8): error C2440: инициализация: невозможно преобразовать "int" в "hugeInt"
1> Конструктор для class "hugeInt" объявлен как "explicit"

Подскажите, пожалуйста, можно ли при использовании explicit-конструкторов сделать возможным использования такой инициализации при объявлении? Оператор '=' перегрузил, но не помогло.
0
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
20.12.2011, 06:52
Здравствуйте! Я подобрал для вас темы с ответами на вопрос explicit и последствия. (C++):

Explicit в конструкторе - C++
Ключевое слово explicit перед конструктором служит лишь для того чтобы не запутаться и передавать аргумент в конструктор явно? Например: ...

неоднозначность, explicit - C++
Добрый вечер. написал такой шаблонный класс: template &lt;class T&gt; class Container { private: ...... public: ...

inline explicit - C++
Почему ошибка? #include &lt;iostream&gt; class A { int i; public: explicit A(int x = 0); void show() {std::cout &lt;&lt; &quot;i = &quot;...

Когда писать explicit - C++
Зачем нужен explicit разобрался. Но, возник вопрос: зачем его писать? когда Вы его пишете? вроде я как-то обходился без него

Целевой explicit конструктор - C++
Добрый день. Есть код struct Foo { explicit Foo() { }

Explicit и его назначение - C++
Собственно, полазив по гуглу и по учебнику так и не понял всей сущности explicit. Как я понял: class lessons { int intVar; ...

Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
taras atavin
Ушёл с форума.
3569 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
20.12.2011, 07:07 #2
Цитата Сообщение от Toshkarik Посмотреть сообщение
hugeInt a = 100;
Ты же сам это запретил эксплеситом. Вызывай его явно
C++
1
hugeInt a(100);
и ни каких гвоздёв.
0
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
20.12.2011, 07:09  [ТС] #3
Ответ нашел на http://publib.boulder.ibm.com, похоже, что никак.

PS: Увидел только что, что создалась 2 тема, хотя у меня при первом создании темы выдало ошибку, что сервер перегружен.
0
taras atavin
Ушёл с форума.
3569 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
20.12.2011, 07:43 #4
эксплисит не защищает от неявного приведения, он блокирует именно неявный вызов конструктора.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
clas B;
class A
{
 ...
 public:
  explicit A (B &x)
  {
   ...
  }
  explicit A (B *x)
  {
   ...
  }
};
class B
{
  ...
 public:
  operator A()
  {
    ...
  }
};
B b;
A a=b; // Так нельзя
A c; // А так
c=b; // можно.
Добавлено через 5 минут
Назначение - гарантировать, что в 30-й строке не будет неоднозначности в виде возможности приведения типа конструктором временного объекта типа A с последующим присваиванием уже его объекту c. Для приведения предназначены только операторы приведения, но компиляторы не всегда это понимают. Этот оператор здесь и будет вызван, но приведение именно неявное. При декларации же самого объекта получаешь лишь синтаксическую мелочь в виде скобок вместо равенства, но инитить можно. Скобки, кстати, можно юзить и без эксплисита. А по поводу перегрузосервачнодубля темы жалуйся администрации. Для этого на форуме есть специальная тема.
0
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
20.12.2011, 07:48  [ТС] #5
Цитирую из книги - "explicit позволяет подавить неявные преобразования посредством конструкторов с одним аргументом, когда такие преобразования не должны допускаться." Основной смысл работы я, в принципе, понял.
0
taras atavin
Ушёл с форума.
3569 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
20.12.2011, 08:04 #6
Вот именно
Цитата Сообщение от Toshkarik Посмотреть сообщение
explicit позволяет подавить неявные преобразования посредством конструкторов
От неявного приведения оператором приведения он не защищает.
0
LosAngeles
Заблокирован
20.12.2011, 08:26 #7
12.3.1 Conversion by constructor
1) A constructor declared without the function-specifier explicit specifies a conversion from the types of its
parameters to the type of its class. Such a constructor is called a converting constructor.
C++
1
2
3
4
5
6
7
8
9
10
struct X {
X(int);
X(const char*, int =0);
};
void f(X arg) {
X a = 1; // a = X(1)
X b = "Jessie"; // b = X("Jessie",0)
a = 2; // a = X(2)
f(3); // f(X(3))
}
2) An explicit constructor constructs objects just like non-explicit constructors, but does so only where the
direct-initialization syntax (8.5) or where casts (5.2.9, 5.4) are explicitly used. A default constructor
may be an explicit constructor; such a constructor will be used to perform default-initialization or valueinitialization
C++
1
2
3
4
5
6
7
8
9
10
11
struct Z {
explicit Z();
explicit Z(int);
};
Z a; // OK: default-initialization performed
Z a1 = 1; // error: no implicit conversion
Z a3 = Z(1); // OK: direct initialization syntax used
Z a2(1); // OK: direct initialization syntax used
Z* p = new Z(1); // OK: direct initialization syntax used
Z a4 = (Z)1; // OK: explicit cast used
Z a5 = static_cast<Z>(1); // OK: explicit cast used
3) A non-explicit copy/move constructor (12.8) is a converting constructor. An implicitly-declared copy/move
constructor is not an explicit constructor; it may be called for implicit type conversions.
0
Nick Alte
Эксперт С++
1637 / 1009 / 119
Регистрация: 27.09.2009
Сообщений: 1,945
Завершенные тесты: 1
20.12.2011, 08:36 #8
C++
1
        explicit hugeInt();
Вот тут explicit вообще не нужен.

C++
1
        hugeInt a = 100;
рассматривается как такая конструкция:
C++
1
        hugeInt a(hugeInt(100));
то есть, находится подходящий конструктор для инициализирующего литерала, затем - копирование (как бы, на самом деле всё вусмерть оптимизируется потом). Вот на вызове конструктора для создания безымянного временного объекта нам explicit и обламывает процесс.
1
LosAngeles
Заблокирован
20.12.2011, 08:56 #9
Цитата Сообщение от Nick Alte Посмотреть сообщение
C++
1
        hugeInt a = 100;
рассматривается как такая конструкция:
C++
1
        hugeInt a(hugeInt(100));
то есть, находится подходящий конструктор для инициализирующего литерала, затем - копирование
нет, hugeInt a = 100; равносильно hugeInt a(100); а не hugeInt a(hugeInt(100)), копирования не происходит

Добавлено через 12 минут
хотя нет, я не прав, у Nick Alte всё правильно, хотя тогда получается visual studio 2010 работает не по стандарту
0
Nick Alte
Эксперт С++
1637 / 1009 / 119
Регистрация: 27.09.2009
Сообщений: 1,945
Завершенные тесты: 1
20.12.2011, 08:56 #10
Оно было бы равносильно, если бы тип литерала совпадал. А так - извините, сначала попытка неявного преобразования через соответствующий конструктор, затем копирование. Отсюда и описанная топикстартером ошибка компиляции: подходящий конструктор есть, но использовать его неявно запрещено ключевым словом explicit. Разумеется, если бы не было ограничения, потом все эти танцы с бубном всё равно оптимизировались бы в ноль до банального
C++
1
hugeInt a(100);
0
Toshkarik
1141 / 858 / 51
Регистрация: 03.08.2011
Сообщений: 2,384
Завершенные тесты: 1
20.12.2011, 08:58  [ТС] #11
Цитата Сообщение от Nick Alte Посмотреть сообщение
Вот тут explicit вообще не нужен.
, да, спасибо, это по не внимательности, просто разом ко всем конструкторам приписал для проверки.
0
taras atavin
Ушёл с форума.
3569 / 1753 / 91
Регистрация: 24.11.2009
Сообщений: 27,619
20.12.2011, 09:46 #12
Цитата Сообщение от LosAngeles Посмотреть сообщение
нет, hugeInt a = 100; равносильно hugeInt a(100); а не hugeInt a(hugeInt(100)), копирования не происходит
Это здесь. Но
C++
1
2
3
hugeInt a;
a=100; //Вот здесь будет a= hugeInt(100);
// То есть вызывается сначала конструктор безымянного временного объекта, потом копирующее присваивания, а потом ещё и деструктор безымянного временного объекта. Вот чтоб гарантировать вызов вместо всего этого оператора присваивания с преобраованием (hugeInt operatro = (int x); - это присваивание именно с преобразованием) используется эксплисит. А при наличии оператора приведения в исходном типе к целевому отработает он, а потом копирующее присваивание, в обоих случаях не будет вызван ни конструктор, ни деструктор
0
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
20.12.2011, 09:46
Привет! Вот еще темы с ответами:

explicit конструктор и перегрузки в классе - C++
class Test { public: Test () { printf(&quot;Simple constructor\n&quot;); } Test (long) {...

Возникнут ли последствия с динамическим массивом? - C++
Если в программе не задается размер массива (строка) и пользователю не подается запрос на размерность можно ли его задать (не имея...

Динамические массивы. Последствия выхода за пределы - C++
int main(int argc, char* argv) { int x1=0,x2=0; int num=3; int* p1=new int ; int* p2=new int ; p1=0; p1=1; p1=2; p1=3;

При потсроении пишет что конструктор либо недоступен либо объявлен как explicit - C++
/*Все обьекты содержимые в контейнерах без проблем выводятся через потоковые итераторы и алгоритм copy. Но когда речь идет о собственных...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
Yandex
Объявления
20.12.2011, 09:46
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2017, vBulletin Solutions, Inc.
Рейтинг@Mail.ru