Поскольку Employee
и User
- это совершенно два разных объекта, поэтому вы не можете разыграть как ваш случай
Простой пример
Пользователь
[ 110]Сотрудник
public class Employee extends User {
//constructor
}
Тогда вы можете сделать это
Employee e = new Employee();
Object o = e;
User = (Employee) o;
Конечно, в этом случае вы не можете поступите противоположным образом: приведите User
к Employee
Надеюсь, этот небольшой пример поможет вам ясно понять дело.
Параметр ссылки на массив не позволяет типу массива преобразовываться в тип указателя. т.е. точный тип массива сохраняется внутри функции. (Например, вы можете использовать трюк sizeof arr / sizeof * arr
для параметра и получить количество элементов). Компилятор также выполнит проверку типа, чтобы убедиться, что тип аргумента массива в точности совпадает с типом параметра массива, т.е. если параметр объявлен как массив из 10 целых чисел, аргумент должен быть массивом ровно из 10 ints и ничего больше.
Фактически, в ситуациях, когда размер массива фиксирован на времени компиляции , использование объявления параметра ссылки на массив (или указателя на массив) может рассматриваться как первичный, предпочтительный способ передать массив. Другой вариант (когда типу массива разрешено распадаться до типа указателя) зарезервирован для ситуаций, когда необходимо передать массивы размера времени выполнения .
Например, правильный способ передать массив размера времени компиляции функции -
void foo(int (&arr)[10]); // reference to an array
или
void foo(int (*arr)[10]); // pointer to an array
Возможно, неправильным способом было бы использовать подход «распавшийся».
void foo(int arr[]); // pointer to an element
// Bad practice!!!
Подход «распавшийся» обычно должен быть зарезервирован для массивов размера времени выполнения и обычно сопровождается фактическим размером массива в отдельном параметре
void foo(int arr[], unsigned n); // pointer to an element
// Passing a run-time sized array
Другими словами, действительно нет вопроса «почему», когда дело доходит до ссылки на массив ( или указатель на массив). Вы должны использовать этот метод естественно, по умолчанию, когда можете, если размер массива фиксирован во время компиляции.Вопрос «почему» действительно должен возникнуть, когда вы используете «устаревший» метод передачи массива. «Разложившийся» метод предполагается использовать только как специализированный прием для передачи массивов размера во время выполнения.
Вышесказанное, по сути, является прямым следствием более общего принципа. Когда у вас есть «тяжелый» объект типа T
, вы обычно передаете его либо по указателю T *
, либо по ссылке T &
. Массивы не являются исключением из этого общего принципа. У них нет причин быть.
Имейте в виду, что на практике часто имеет смысл писать функции, которые работают с массивами размера времени выполнения, особенно когда речь идет об общих функциях библиотечного уровня. Такие функции более универсальны. Это означает, что часто есть веская причина использовать «разложившийся» подход в реальном коде. Тем не менее, это не освобождает автора кода от распознавания ситуаций, когда размер массива известен во время компиляции и использования ссылки на -array соответственно.
Одно отличие состоит в том, что (предполагается) невозможно передать нулевую ссылку. Таким образом, в теории функции не нужно проверять, является ли параметр нулевым, тогда как параметру int * arr можно было бы передать значение null.
Вы можете убедиться, что функция вызывается только для int
массивов размера 10. Это может быть полезно с точки зрения проверки типов.
Вы можете написать шаблон функции, чтобы узнать размер массива во время компиляции.
template<class E, size_t size>
size_t array_size(E(&)[size])
{
return size;
}
int main()
{
int test[] = {2, 3, 5, 7, 11, 13, 17, 19};
std::cout << array_size(test) << std::endl; // prints 8
}
Больше никаких sizeof (test) / sizeof (test [0])
для меня; -)
, вы получаете более семантическое значение относительно того, что функция ожидая.