Fonctionnellement, dans votre exemple, les deux versions font la même chose.
La première a l'avantage d'être transparente du côté de l'appel. Imaginez ce que cela donnerait pour un opérateur :
cin >> &x;
Et comment c'est laid pour une invocation de swap
swap(&a, &b);
Vous voulez échanger a et b. Et c'est beaucoup mieux que lorsque vous devez d'abord prendre l'adresse. À propos, bjarne stroustrup écrit que la raison principale des références était la transparence ajoutée du côté de l'appel - en particulier pour les opérateurs. Voyez aussi comment il n'est plus évident de savoir si l'opération suivante
&a + 10
ajouterait 10 au contenu de a, en appelant l'opérateur+ de celui-ci, ou s'il ajoute 10 à un pointeur temporaire vers a. Ajoutez à cela l'impossibilité de surcharger des opérateurs pour des opérandes intégrés uniquement (comme un pointeur et un entier). Les références rendent cela très clair.
Les pointeurs sont utiles si vous voulez pouvoir mettre un "null" :
a1(0);
Ensuite, en a1, la méthode peut comparer le pointeur avec 0 et voir si le pointeur pointe vers un objet quelconque.