int x = 9.33; //тип int принимающий, тип double принимаемый, тип double преобразуется к типу int long count = 9; //тип long принимающий, тип int принимаемы, тип int неявно преобразуется к типу long double z = 7; //тип double принимающий, тип int принимаемы, тип int неявно преобразуется к типу double
С++ распознает, что в показанном варианте фигурирующие в выражениях типы представляют собой целые числа. Поскольку С++ поддерживает встроенные правила для преобразования между встроенными типам-числами, происходят такие приведения. Многим из моих читатетелй это уже прекрасно известно.
int *arr = 10; //принимающий тип - (указатель на int), принимаемый тип int, тип int* к типу int неявно не преобразуется
На самом деле компьютер может представлять указатель в виде целого числа, но между указателем и целым числом есть сильное смысловое различие. Как минимум, для указателя возведение в квадрат, взятие квадратного корня, логарифма и многие другие действия, применяемые к численным типам, не нужны. А те действия, которые предусмотрены, работают иначе, чем работают действия с численными типами. В таком случае мы можем говорить о тесной связи типов, и если такая тесная связь существует, то хоть неявно проводить преобразования компилятор не будет, мы можем провести явное преобразование:
int *arr = (int*)10; //явное преобразование в стиле С, int преобразуется к int* (тип числа 10 преобразуется к адресу 10)
// int x = "Hello"; //принимающий тип int, принимаемый тип const char*, неявно не приводится // int x = (int)"Hello"; //принимающий тип int, принимаемый тип const char*, явно не приводится
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
//Листинг #1 clang Преобразования class MyClass{ int x; public: MyClass(){} MyClass(int value){ //конструктор с одним параметром, конвертирующий x = value; } }; int main(){ MyClass x = 10; //Тип MyClass принимающий, тип int принимаемый, тип int неявно преобразуется к типу MyClass int i = x; //Но обратное уже не работает. Тип int принимающий, тип MyClass принимаемый, тип MyClass неявно не преобразуется к типу int int z = (int)x; //Но обратное уже не работает. Тип int принимающий, тип MyClass принимаемый, тип MyClass явно не преобразуется к типу int } |
1 |
operator int(); //int можно менять на другой тип |
1 |
operator string(){return S; //У S тип string} |
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 |
//Листинг #2 Преобразования clang #include <iostream> using std::cout; class MyClass{ int x; public: MyClass (int value):x(value){} //конструктор по умолчанию, он же сейчас конвертирующий конструктор, ибо один параметр принимает и не explicit operator int(); //задаём умение объектам класса MyClass преобразовываться к типу int }; MyClass::operator int(){ return x; } int main(){ MyClass x = 55; //использовали конвертирующий конструктор int y = x; //использовали умение класса MyClass приводить собственные его объекты к типу int cout << y << '\n'; //55 MyClass a = 77.88; //использовали конвертирующий конструктор //но параметр int принимает тип double, происходит обрезание до целого double b = a; //MyClass преобразуется к int, а потом int преобразуется к double cout << b << '\n'; //77 } |
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 |
//Листинг #3 Пользовательские преобразования типов clang #include <iostream> using std::cout; class MyClass{ double x; //<=== будьте внимательны, тип изменился (и в конструкторе тоже) public: MyClass (double value):x(value){} //конструктор по умолчанию, он же сейчас конвертирующий конструктор, ибо один параметр принимает и не explicit operator int(); //задаём умение объектам класса MyClass преобразовываться к типу int operator double(); //задаём умение объектам класса MyClass преобразовываться к типу double }; MyClass::operator int(){ return x; //вернет int, потому что operator int() } MyClass::operator double(){ return x; //вернёт double, потому что operator double() } int main(){ MyClass x = 55; //использовали конвертирующий конструктор int y = x; //использовали умение класса MyClass приводить собственные его объекты к типу int cout << y << '\n'; //55 ////////////////////////////////// MyClass a = 77.88; //использовали конвертирующий конструктор //параметр double принимает тип double double b = a; //MyClass преобразуется к double, потому что в классе operator double() предпочтительнее Operator int(), ибо не требует доп. приведений cout << b << '\n'; //77.88 } |
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 |
//Листинг #4 Пользовательские преобразования типов clang #include <iostream> using std::cout; class A; class B; class A { public: A(){} explicit A(const B& value){} //запрещаем конвертирующий конструктор operator B(); }; class B { public: B(){} explicit B(const A& value){} //запрещаем конвертирующий конструктор operator A(); }; A::operator B(){ return B(); } B::operator A(){ return A(); } int main() { A a; B b; a = b; //использовали умение B: (---operator A()---) b = a; //использовали умение A: (---operator B()---) } |
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 |
//Листинг #5.1 Пользовательские приведения типов Запрещаем неявность приведений clang #include <iostream> using std::cout; class MyClass{ double x; //<=== будьте внимательны, тип изменился (и в конструкторе тоже) public: MyClass (double value):x(value){} //конструктор по умолчанию, он же сейчас конвертирующий конструктор, ибо один параметр принимает и не explicit explicit operator int(); //задаём умение объектам класса MyClass преобразовываться к типу int explicit operator double(); //задаём умение объектам класса MyClass преобразовываться к типу double }; MyClass::operator int(){ return x; //вернет int, потому что operator int() } MyClass::operator double(){ return x; //вернёт double, потому что operator double() } int main(){ MyClass x = 55; //использовали конвертирующий конструктор int y = x; //<---- Ошибка!!! Попытка неявного приведения, неявное приведение запрещено применённым explicit, приписанного к operator int() cout << y << '\n'; //55 ////////////////////////////////// MyClass a = 77.88; //использовали конвертирующий конструктор //параметр double принимает тип double double b = a; //<--- Ошибка!!! Попытка неявного приведения, неявное приведение запрещено применённым explicit, приписанного к operator double() cout << b << '\n'; //77.88 } |
1 |
MyClass x = MyClass(55); |
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 |
//Листинг #5.2 Пользовательские приведения типов Запрещаем неявность приведений clang #include <iostream> using std::cout; class MyClass{ double x; //<=== будьте внимательны, тип изменился (и в конструкторе тоже) public: MyClass (double value):x(value){} //конструктор по умолчанию, он же сейчас конвертирующий конструктор, ибо один параметр принимает и не explicit explicit operator int(); //задаём умение объектам класса MyClass преобразовываться к типу int explicit operator double(); //задаём умение объектам класса MyClass преобразовываться к типу double }; MyClass::operator int(){ return x; //вернет int, потому что operator int() } MyClass::operator double(){ return x; //вернёт double, потому что operator double() } int main(){ MyClass x = MyClass(55); //использовали конвертирующий конструктор int y = int(x); //Использовали явное приведения, преобразуя MyClass в тип int cout << y << '\n'; //55 ////////////////////////////////// MyClass a = 77.88; //использовали конвертирующий конструктор //параметр double принимает тип double double b = double(a); //Использовали явное приведения, преобразуя MyClass в тип double cout << b << '\n'; //77.88 } |
В видео показано, куда вписывать _CRT_SECURE_NO_WARNINGS
Если там что-то будет вписано, то нужно будет испольовать точку с запятой как разделитель.
Свойства проекта -> С/С++ -> Препроцессор -> Опеределения препроцессора
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
//Листинг #6.1 Visual Studio Пользовательские преобразования типов #include <iostream> #include <string.h> using std::cout; using std::ostream; class string{ char *ch; //указатель для создания строкового представления данных public: explicit string(); //конструктор без параметров, прототип explicit string(const char*); //конструктор, принимающий строку, прототип ~string(); //деструктор friend ostream& operator << (ostream&, const string&); //прототип дружественной функции operator int(); //учим приводиться к типу int, прототип }; string::string(){ ch = 0; } string::string(const char* ch_){ const size_t MAX_LEN = strlen(ch_); ch = new char[MAX_LEN + 1]; strcpy(ch, ch_); } string::~string(){ delete []ch; } ostream& operator <<(ostream& stream, const string& s){ return stream << s.ch; } /*УЧИМ КЛАСС ПРИВОДИТЬ СВОИ ОБЪЕКТЫ К ТИПУ int*/ string::operator int(){ int x = 0; //это конечное значение, которое будет отдаваться, оно должно быть int или уметь приводиться к int //цикл преобразования из строкового представления числа в число for (size_t i=0; i<strlen(ch); i++){ x*= 10; x = (x + ch[i] - '0'); } return x; //отдаем полученное вычислением значение на выход } int main(){ string S("678"); int x = S; //int умеет принимать в себя string!!! cout << x << '\n'; } |
1 2 3 4 |
string S("Hello"); //Не число, но набор символов преобразуется в числовое представление и этот результат будет отдан в виде числа, которое и присвоится в x ниже //это происходит потому что мы так написали функцию преобразования из строки в число int x = S; cout << x << '\n'; |
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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
//Листинг #6.2 Visual Studio Пользовательские преобразования типов #include <iostream> #include <string.h> #include <cstdlib> #include <string> #include <sstream> //для относительно короткого способа перевода числа в строку using std::cout; using std::ostream; using std::stringstream; class my_string { char *ch; //указатель для создания строкового представления данных public: explicit my_string(); //конструктор без параметров, прототип explicit my_string(const char*); //конструктор, принимающий строку, прототип ~my_string(); //деструктор friend ostream& operator << (ostream&, const my_string&); //прототип дружественной функции operator int(); //учим приводиться к типу int, прототип void operator = (const int); //перегружаем операцию присваивания, чтобы принимала в себя число, прототип }; my_string::my_string() { ch = new char[255]; ch[0] = 0; } my_string::my_string(const char* ch_) { const size_t MAX_LEN = strlen(ch_); ch = new char[MAX_LEN + 2]; //конец строки, знак (положительное или отрицательное) strcpy(ch, ch_); } my_string::~my_string() { delete[]ch; } ostream& operator <<(ostream& stream, const my_string& s) { return stream << s.ch; } my_string::operator int() { int x = 0; bool negative = false; //признак отрицательности числа for (size_t i = 0; i<strlen(ch); i++) { if (ch[i] == '-') { //если число отрицательное negative = true; //обозначаем continue; //пропускам ход цикла } x *= 10; //собираем из символов число x = (x + ch[i] - '0'); } if (negative) x = -x; //если было определено, что вошло отрицательное представление числа, то возвращаем отрицательное число return x; } /*ПЕРЕГРУЗКА ОПЕРАЦИИ =*/ void my_string::operator=(const int value) { stringstream ss; //описываем перевод из числа в строку ss << value; ss >> ch; } int main() { my_string S; S = 25; //Ход конём. Сначала int переносим в объект нашего класса int x = S; //Потом в независимый int переносим объект нашего класса cout << x << '\n'; //выводим значение стороннего int system("PAUSE"); } |
Добавить комментарий