From an implementation perspective, there is one very important difference between a pointer and a reference in C++: references cannot be null.

This is undefined behaviour:

```cpp
int* px = nullptr;
int &rx = *px;
```

This doesn't make a difference except in one specific scenario: casting in the presence of multiple inheritance.

Consider this:

```cpp
struct base1 {
 uint64_t member1;
};

struct base2 {
 uint64_t member2;
};

struct derived : public base1, base2 {
};
```

What code should this function compile to?

```cpp
base2& cast_from_derived_to_base2_ref(derived& pd)
{
 return (base2&)pd;
}
```

If you said "basically add 8", you would be correct. Clang 16.0.0 on x64 at `-O2` generates this code:

```asm
cast_from_derived_to_base2_ref(derived&):
 lea rax, [rdi + 8]
 ret
```

Now, what code should this function compile to?

```cpp
base2* cast_from_derived_to_base2_ptr(derived* pd)
{
 return (base2*)pd;
}
```

If you said "the same code", you would be wrong. It would give an incorrect answer if `pd` were a null pointer; in that case, this function should also return a null pointer.

This is the code that Clang 16.0.0 generates:

```asm
cast_from_derived_to_base2_ptr(derived*):
 lea rax, [rdi + 8]
 test rdi, rdi
 cmove rax, rdi
 ret
```

Of course, there are also high-level semantic differences (references are immutable, for example), but this is the key difference in implementation.