Приведение типа – это преобразование значения одного типа в значение другого.
Например, рассмотрим принцип работы оператора сложения "+". Этот оператор с одинаковым успехом используется для сложения, как целых, так и вещественных чисел. Код, генерируемый компилятором при сложении целых чисел, часто коренным образом отличается от кода с плавающей точкой. Но программист думает об этих операциях как о единой функции "сложение". Если в данном примере разрешить арифметические действия со смешанными операндами, то сложение двух значений может интерпретироваться несколькими способами:
– разрешено использование четырех различных функций, которые соответствуют операциям "целое + целое", "целое + вещественное", "вещественное + целое", "вещественное + вещественное". В этом случае есть перегрузка, но нет приведения типа;
– разрешено использование двух различных функций: "целое + целое" и "вещественное + вещественное". Для операций "целое + вещественное" и "вещественное + целое" целое значение должно быть приведено к вещественному. В таком случае присутствует комбинация перегрузки и приведения типа;
– есть только одна функция сложения: "вещественное + вещественное". Все аргументы приводятся к типу данных "вещественное число". В этом случае нет перегрузки, а есть только приведение типов.
При выполнении операции приведения типа может возникнуть неопределенность – ситуация когда компилятор не может сделать выбор между перегруженными функциями.
Неопределенные инструкции являются ошибками, и программа, содержащая неопределенности, не будет откомпилирована.
Основная и наиболее распространенная причина возникновения неопределенностей – вызов функции с одновременным автоматическим преобразованием типов.
Ошибка вызывается не автоматическим преобразованием типа, а особенностями вызова функции.
С++ автоматически пытается преобразовать аргументы, использованные при вызове функции, к типу аргументов интерфейса функции.
Например:
#include<iostream.h>
float myfunc(float i); // объявление функции myfunc() для значений типа float
double myfunc(double i); // объявление функции myfunc() для значений типа double
int main()
{
cout<<myfunc(10.1)<<" "; // автоматическое преобразование числа 10.1
// к типу double и вызов функции myfunc(double i)
cout<<myfunc(10)<<" "; // неопределенная ситуация
return 0;
}
float myfunc(float i)
{
return i;
}
double myfunc(double i)
{
return -i;
}
В данном примере функция myfunc() перегружена и может в качестве аргументов использовать переменные типа float или double.
Вызов функции со значением 10.1 не вызывает неопределенности, так как С++ автоматически преобразовывает его к типу double и вызывается функция myfunc(double i).
Но когда функция вызывается со значением 10, возникает неопределенность, так как компилятор не может определить, к какому типу преобразовать это число. Программа не компилируется и выдается сообщение об ошибке.
Чтобы снять неопределенность достаточно число 10 заменить числом 10.0
Другой причиной возникновения неопределенности может быть использование в перегруженных функциях аргументов по умолчанию.
Например:
#include <iostream.h>
#include <conio.h>
int myfunc(int i);
int myfunc(int i, int j=1);
int main()
{
clrscr();
cout<<myfunc(4, 5)<<" "; // неопределенности нет
cout<<myfunc(10); // неопределенность
return 0;
}
int myfunc(int i)
{
return i;
}
int myfunc(int i, int j)
{
return i*j;
}
В данном примере при вызове функции myfunc(4, 5) неопределенности не возникает, так как здесь указываются два аргумента.
Но когда вызывается функция myfunc(10), возникает неопределенность, так как компилятор не знает, вызывать ли функцию myfunc() с одним аргументом, или использовать функцию с двумя аргументами, у которой второй аргумент принимает значение по умолчанию.
Чтобы снять неопределенность, нужно явно указать второй аргумент.
34. Понятие "параметрическая перегрузка"?
Параметрической перегрузкой называется перегрузка при которой процедурам (функциям, методам) в одном и том же контексте разрешается использовать совместно одно имя, а двусмысленность снимается за счет анализа числа и типов аргументов.
В С++ любой метод функция, процедура или оператор могут быть параметрически перегруженными, если их аргументы таковы, что выбор можно произвести однозначно на этапе компиляции. Например, автоматическое приведение типа от символьных значений к целым числам или от целых – к числам с плавающей точкой.
35. Понятие "переопределение"? В чем заключается различие между перегрузкой и переопределением?
Переопределение (или чистый полиморфизм) – это ситуация, когда одна и та же функция применяется к аргументам различных типов, т. е. в случае переопределения есть одна функция (тело кода) и несколько ее интерпретаций.
Перегрузка является обязательной частью переопределения методов, но переопределение методов может происходить без перегрузки.
Переопределение методов вносит свой вклад в совместное использование кода, так как экземпляры классов, которые не переопределяют данный метод, могут использовать одну копию оригинального кода.
В тех случаях, когда метод не подходит, создается альтернативный фрагмент кода.
Производные классы автоматически перенимают все то, что обеспечивает базовый класс. Например, если класс "Лодка" определяет метод "Поставить в док", то производные классы автоматически наследуют его. Если же есть необходимость, то можно в производных классах переопределить реализацию метода требуемым образом. Например, переопределить метод "Поставить в док" для класса "Подводная лодка" Если во время выполнения в программе присутствует указатель на объект типа "Лодка" (а это базовый тип), этот указатель может ссылаться как на парусную или моторную лодку, так и на подводную