Что представляет собой ссылка?
Ну конечно что ждет от вас препод, нам тут все равно не угадать. Я бы как раз и ответил, что это имя для переменной. Я не соглашусь с некоторыми ответами здесь, т.к. не всегда для ссылки компилятор будет выделять память - локальная ссылка на локальную же переменную как раз таки будет просто вторым именем в таблице идентификаторов компилятора при компиляции программы.
Главная фишка ссылки в том, что это абстрактное l-value, т.е. сущность, в которую можно что-то присвоить (если базовый тип - не константный). То есть ссылка всегда оборачивает какой-либо адрес в памяти, причем на время жизни ссылки этот адрес постоянен (ссылку нельзя "переставить" на другую область памяти). Именно поэтому ссылки всегда нужно инициализировать.
ЧЕМ инициализировать - другое дело. Можно переменной, а можно - разыменованным указателем.
В зависимости от ситуации технически ссылка может быть реализована по-разному. Если это ссылка на лок. переменную, то большинство компиляторов просто добавят себе новое имя в таблицу. Никакой дополнительной памяти выделяться не будет. Если же ссылка приходит как параметр или отдается как возвращаемое значение - то тут скорее всего понадобится реализовать ее как указатель (указатель передавать/возвращать). Однако, еще раз напомню: ссылка скрывает технические подробности, вы с ней работаете как с обычной переменной. Более того, она скрывает настолько, что даже может продлевать жизнь временным объектам.
Теперь попробуем сранить ссылку и другие сущности в языке.
Определение ссылки vs определение обычной переменной:
определение обычной переменной это всегда выделение памяти и добавление нового имени в таблицу компилятора для этой области памяти. Определение ссылки - это прежде всего ОПРЕДЕЛЕНИЕ ИМЕНИ, а уже в тех случаях, когда привязку этого ИМЕНИ к АДРЕСУ невозможно осуществить во время компиляции (т.е. например в случае передачи ссылки как параметра функции), то для реализации ссылки применятся указатель. Важно, что компилятор сам выбирает способ реализации поведения ссылки. В любом случае, назначение ссылки - обернуть в l-value уже ВЫДЕЛЕННУЮ память (совершенно не важно, на стеке, куче или где-то еще). Новой памяти для хранения значения целевого типа НЕ выделяется. Если у вас есть переменная и ссылка/несколько ссылок на нее, то при присвоении значения через любую из сущностей вы будете менять одну и ту же область памяти.
Ссылка vs указатель:
- самое важное отличие - указатель САМ ПО СЕБЕ является переменной. Под указатель int* компилятор выделит память также, как и под int. Указатель существует сам по себе, ему (если он не const) можно присваивать новые значение, можно присвоить nullptr. Можно даже хранить в нем совершенно некорректный адрес и все будет ок до тех пор, пока вы не разыменуете его. Только когда вы разыменовываете указатель, вы превращаете его в l-value, и с этого момента между ним и ссылкой разницы нет.
- второе отличие - собственно необходимость разыменования. Т.к. указатель - самостоятельная переменная, для обращения по адресу, на который указатель смотрит, нужно сделать ему *p. Именно в этот момент компилятор начинает рассматривать значение указателя как адрес в памяти, с которым вы собираетесь что-то сделать (если быть совсем точным, но не в момент разыменования, а при попытке чтения/записи. В принципе вы можете даже инициализировать ссылку некорректным указателем, и программа не упадет, пока вы не попытаетесь читать/присваивать по этой ссылке).
- с учетом сказанного, ссылку можно грубо считать "константым указателем с автоматическим разыменованием". Грубо, т.к. согласно стандарту есть нюансы, такие как вышеупомянутое продлевание жизни временным объектам.
Это переменная, хранящая внутри себя адрес памяти, в котором хранится объект некого типа. В отличие от указателя - ссылка должна быть проинициализирована начальным значением и не может быть null.