1373 / 596 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
1

Conversion by constructor , нужны пояснения

29.04.2017, 04:11. Показов 2089. Ответов 17
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте.
Смотрю я, что пишут об этом Conversion by constructor, вижу одно:
Конструктор C++, который принимает один аргумент, определяет преобразование типа аргумента в тип класса.
Вот, думаю, сейчас как заставлю компилятор обломаться при компиляции:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
 
class MyClass {
    int a;
public:
  MyClass(int i):a(i) { };
  int get() const { return a; }
};
 
 
int main() {
  MyClass obj1(100); //int должен привестись к MyClass
 
  //Но в int нельзя присваивать объекты типа MyClass
  //Что не мешает уходящему int приходить в параметр
 
}
В аргументе тип int, который, по некоторой логике, происходящей из утверждений, подобных в приведённой цитате, преобразуется в тип MyClass, но тут возникает вопрос, а почему же пример работает? Ведь нельзя в этом коде присвоить в int объект типа MyClass.

______________
Просьба расставить все точки над Иъ и немного исправить моё искажённое восприятие такого конструктора.

Ещё бы мне не помешал маленький и простой пример, где такое преобразование, которое запрещается explicit, оказывается не к месту.
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
29.04.2017, 04:11
Ответы с готовыми решениями:

Expected constructor, destructor, or type conversion before '.' token
struct Gf3 { GLfloat x; GLfloat y; GLfloat z; } p1,p2,p3,t; t.x = 0.0; t.y =...

Ошибка expected constructor, destructor, or type conversion before '(' toke
Возникает ошибка expected constructor, destructor, or type conversion before '(' toke в 7 и 16...

Ошибка expected constructor, destructor, or type conversion before ';' token
выдает ошибку expected constructor, destructor, or type conversion before ';' token с 61-90...

Ошибка "expected constructor, destructor, or type conversion"
//ourfunc.cpp - îïðåäåëÿåò âàøó ñîáñòâåííóþ ôóíêöèþ #include &lt;iostream&gt; using namespace std;...

17
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
29.04.2017, 04:13 2
Цитата Сообщение от daslex Посмотреть сообщение
MyClass obj1(100); //int должен привестись к MyClass
вы ошибаетесь.
здесь нет преобразований типов.


преобразования - конструкции вида:
C++
1
MyClass obj1 = 100;
1
1373 / 596 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
29.04.2017, 04:18  [ТС] 3
Цитата Сообщение от daslex Посмотреть сообщение
определяет преобразование типа аргумента в тип класса.
А это о чём? Переведите на русский, пожалуйста.

Добавлено через 1 минуту

Не по теме:

То, что я ошибаюсь - это и мне понятно, я же не писал обратного, а прошу помощи в деинсталляции ошибки из моей головы.

0
nd2
3437 / 2816 / 1249
Регистрация: 29.01.2016
Сообщений: 9,426
29.04.2017, 04:25 4
Цитата Сообщение от daslex Посмотреть сообщение
А это о чём?
Цитата Сообщение от hoggy Посмотреть сообщение
MyClass obj1 = 100;
О том, что при таком преобразовании будет использован конструктор с одним аргументом, которому будет передано число 100.
1
1373 / 596 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
29.04.2017, 04:32  [ТС] 5
MyClass obj1(100);

MyClass obj1 = 100; //Так я и хотел, не доглядел, не доправил...
Но это суть не меняет. Ошибка из другого леса.

Добавлено через 6 минут
Цитата Сообщение от nd2 Посмотреть сообщение
О том, что при таком преобразовании
А ещё о чём? На таких условиях жёсткого требования таким конструкторам явно указывать explicit едва ли достаточно.

И не при таком преобразовании, а всё-таки при таком конструкторе, тут как бы порядок имеет значение, полагаю.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
29.04.2017, 04:34 6
http://rextester.com/UULKO63674

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <iostream>
 
class MyClass {
    int a;
public:
    
  // умеет построиться из int
  MyClass(int i):a(i) {};
    
    
  // умеет привестись к int  
  operator int()const { return a; }
};
 
 
int main() 
{
  MyClass obj = 100;
 
  std::cout << "неявное приведение MyClass к int: " 
      << obj << std::endl;
 
}
1
1373 / 596 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
29.04.2017, 04:41  [ТС] 7
Не то. Меня интересует только конструктор. То, что он умеет построится из int я знаю, о conversion function я тоже знаю, и она явно не конструктор.

Добавлено через 1 минуту
Что обозначает определить преобразование типа аргумента в тип класса - не понимаю.
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
29.04.2017, 04:42 8
Цитата Сообщение от daslex Посмотреть сообщение
Что обозначает определить преобразование типа аргумента в тип класса - не понимаю.
создать объект класса, проинициализированный конструктором с параметром.
1
1373 / 596 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
29.04.2017, 04:52  [ТС] 9
Пример попроще, когда это преобразование оказывается вредным, можно?
0
Эксперт С++
8739 / 4317 / 960
Регистрация: 15.11.2014
Сообщений: 9,760
29.04.2017, 04:56 10
Цитата Сообщение от daslex Посмотреть сообщение
Пример попроще, когда это преобразование оказывается вредным, можно?
http://rextester.com/YWKHU74133

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include <iostream>
using namespace std;
 
 
struct foo {}; //<--- не умеет выводится в поток
 
struct bar  //<--- умеет выводится в поток
{
    template<class T> using Stream = ::std::basic_ostream<T>;
    
    template<class T> friend
        Stream<T>& operator<<(Stream<T>& os, const bar& obj ) { return os<<"bar"; }
    
    bar(){}
    bar(const foo&){} //<--- и может построится на основании foo, 
    //который не умеет выводится в поток
};
 
 
 
int main()
{
    std::cout << "Hello, world!\n";
    
    const foo f;
    const bar b;
    
    cout << b << endl;  //<--- здесь все нормально и предсказуемо
    
    
    cout << f << endl; //<--- а вот здесь лажа
    
    //компилятор гцц почему то считает, что раз foo не умеет выводиться в поток,
    //значит можно взять любую перегрузку, аргумент которой может построится из foo
    //и использовать её
    
    //по итогу получаем сюрприз: строительство временного объекта
    //                           и вывод в поток совершенно не того типа, 
    //                           который по смыслу нужно было выводить
    
}
0
1373 / 596 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
29.04.2017, 17:43  [ТС] 11
Вряд ли этот пример можно назвать примером попроще. К тому же ни один из домашних моих компиляторов его не осилил.

Добавлено через 12 часов 41 минуту
Вопрос не решён.
0
18833 / 9835 / 2404
Регистрация: 30.01.2014
Сообщений: 17,273
29.04.2017, 19:12 12
Цитата Сообщение от daslex Посмотреть сообщение
Ещё бы мне не помешал маленький и простой пример, где такое преобразование, которое запрещается explicit, оказывается не к месту.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class C
{
public:
    C(bool a) {}
};
 
void foo(C const & x)
{
}
 
int main()
{
    int * ptr = 0;
    foo(ptr);
}
По вызову создается впечатление, что в функцию передается указатель. Хотя на самом деле будет неявное преобразование к С через конструктор c bool (любой указатель неявно приводится к bool, как мы все знаем). В общем, это может быть совсем не тем, что мы в итоге ожидаем.
1
132 / 158 / 87
Регистрация: 06.04.2016
Сообщений: 992
29.04.2017, 19:24 13
Цитата Сообщение от daslex Посмотреть сообщение
В аргументе тип int, который, по некоторой логике, происходящей из утверждений, подобных в приведённой цитате, преобразуется в тип MyClass, но тут возникает вопрос, а почему же пример работает? Ведь нельзя в этом коде присвоить в int объект типа MyClass.
- Вы уж извините, бред какой-то пишите, сами написали в параметре конструктора тип int, потом передаете целое число 100(что правильно) и при чем тут преобразование int-to-MyClass и ошибка компилятора. Ему неначем ошибаться. Вы там уже перезанимались по-моему.

Добавлено через 3 минуты
Цитата Сообщение от DrOffset Посмотреть сообщение
любой указатель неявно приводится к bool
- первый раз слышу.
0
1373 / 596 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
29.04.2017, 20:10  [ТС] 14
Цитата Сообщение от DrOffset Посмотреть сообщение
В общем, это может быть совсем не тем, что мы в итоге ожидаем.
Увы, но я не вижу ответа.

Если указатель умеет приводиться к bool, то этот пример мало отличается от такого:
C++
1
2
3
4
5
6
7
void foo(int x){}
 
int main()
{
    double a = 100;
    foo(a);
}
Конструктор тут ни при чём, наверное.
0
18833 / 9835 / 2404
Регистрация: 30.01.2014
Сообщений: 17,273
29.04.2017, 20:43 15
Цитата Сообщение от daslex Посмотреть сообщение
то этот пример мало отличается от такого
Нет, сильно отличается.
Я этот пример привел не от балды. Это было реальной проблемой в реальном проекте.
Тут в твоем примере только одно преобразование. А в моем - два. И это в добавок к тому, что мы получаем совсем другое поведение, совершенно отличное от внешне ожидаемого: у нас же нет конструктора для указателя.

Зачем вообще нужен explicit? Простой ответ - чтобы запретить неявное преобразование. Но зачем может быть нужно запрещать неявное преобразование? Чтобы подчеркнуть смысловое различие используемых сущностей.
Иными словами, если мы пишем:
C++
1
String str(2);
мы понимаем, что это строка, размером 2.
А если мы пишем
C++
1
String str = 2;
то как бы получается, что наша строка - это 2.
И, естественно, вызывая функцию с параметром String
C++
1
void foo(String const &)
мы бы наверняка не хотели, чтобы такое компилировалсь:
C++
1
foo(2);
потому что это противоречит заданному нами смыслу для класса String. Стоял бы у конструктора с целочисленным аргументом explicit - компилятор не допустил бы такое использование. С другой стороны, вот такая запись:
C++
1
String str = "12345";
не противоречит назначению класса String, а значит конструктор для char const * делать explicit нет смысла.
3
1373 / 596 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
29.04.2017, 21:21  [ТС] 16
Я всё равно не понимаю.
Меня интересует сейчас только одна часть текущей темы: неожиданные преобразования.

Все о них говорят, но никто не показывает такую неожиданность в действии.
Я не вижу другого поведения, что я должен был ожидать? Кроме того, что можно ожидать, что программа компилироваться не должна, мне ничего в голову не приходит.

Как засветить проблему?

Кроме того, что можно сказать: "я не знаю, почему это работает", мне и сказать нечего. (если я не знаю о конвертирующем конструкторе, конечно).
0
18833 / 9835 / 2404
Регистрация: 30.01.2014
Сообщений: 17,273
29.04.2017, 22:10 17
Лучший ответ Сообщение было отмечено daslex как решение

Решение

Цитата Сообщение от daslex Посмотреть сообщение
Я всё равно не понимаю.
Ну я попробую последний раз с другой стороны. Если что, уж не обессудьте

Представим, что у нас есть большой С++ проект, в котором есть такой класс:
C++
1
2
3
4
5
6
7
class String
{
public:
    String(size_t count, char ch = '\0');
 
    //... остальное
};
Далее допустим, что у нас есть функции:
C++
1
2
void do_something(String const & x);
void do_something(int);
И они много раз вызываются в коде проекта. До этих пор все вроде бы хорошо.
Далее, представим, что на каком-то этапе развития проекта решили провести рефакторинг и заменить функцию
C++
1
void do_something(int);
на
C++
1
void do_something_with_int(int);
На что теперь следует обратить внимание? На то, что вызовы
C++
1
do_something(int_number);
везде по коду продолжат компилироваться без проблем. И если кто-то по каким-либо причинам не поменяет все такие вызовы на
C++
1
do_something_with_int(int_number);
,
то поведение кода изменится, и вполне возможно, что заметить это удастся уже слишком поздно.
Понятно, что пример несколько утрированный, но по сути своей обычно все именно так и происходит: что-то меняется, код продолжает компилироваться, ошибка маскируется. explicit - это средство, позволяющее переложить часть контроля за кодом на плечи компилятора, облегчив тем самым работу программиста. За этим же в С++11 добавили возможность указывать explicit в user-defined conversion operator. В его отсутствие в некоторых случаях вынуждены были выдумывать вот такие обходные костыли: safe bool idiom.
2
1373 / 596 / 199
Регистрация: 02.08.2011
Сообщений: 2,882
30.04.2017, 23:04  [ТС] 18
DrOffset, Ваш последний ответ замечателен.
Спасибо.
0
30.04.2017, 23:04
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
30.04.2017, 23:04
Помогаю со студенческими работами здесь

Нужны пояснения
Читаю &quot;С++ руководство для начинающих&quot; Герберта Шилдта. Дочитал до &quot;передача аргументов командной...

Нужны некоторые пояснения
При выполнении программы есть область 20 на 20. 1) Почему при движении вправо или влево, после...

Нужны пояснения по вложенным классам
задался вот таким вопросом, почему не получается объявить вложенный класс следующим образом?...

Синглтон Мейерса, нужны некоторые пояснения
class Singleton{ public: static Singleton&amp; init() { static Singleton Object; ...

Реализация связанного списка - нужны пояснения
#include &lt;iostream&gt; using namespace std; class cool { public: int number;...

Нужны пояснения насчет компиляторов для разных ОС
Всем привет ребят! Есть несколько вопросов: 1) Существуют различные компиляторы (к примеру на...


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

Или воспользуйтесь поиском по форуму:
18
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru