Zeiger (Pointer) sind 1:1 aus C übernommen. Sie sind in ihrer Handhabung relativ 'gefährlich', da sie auf praktisch alles zeigen können: ein valides Objekt, NULL, ein mittlerweile nichtmehr existentes Objekt oder einfach irgendwo in den Speicher.
Man muss also, wenn man mit Zeigern umgeht, darauf achten, dass sie auf etwas Gültiges zeigen, da ein z.B. uninitialisierter Zeiger keinen Compilerfehler wirft (AFAIK wird dieser spezielle Fall aber mittlerweile oft als Warnung angezeigt).
Referenzen sind mit C++ als praktisch sichere Zeiger eingeführt worden. Sie können nur ein mal bei ihrer Erzeugung zugewiesen werden und sind dann fest an dieses Objekt gebunden. Auch kann man nur 'echte' Objekte und PODs an eine Referenz zuweisen, NULL oder irgendeine Speicheradresse geht nicht.
Für einen großen Teil der Aufgaben kann man Referenzen oder Zeiger gleichsam verwenden. Wie du schriebst, nutzt man Call by Reference, wenn man ein Objekt oder POD an eine Funktion übergeben will, um es hierdrin zu verändern. Du sparst dir den Nullcheck sowie Dereferenzierungen ('*').
Willst du aber z.B. mit Zeigern rechnen, also z.B. in einem Array hin- und herspringen, erlaubst das Übergeben von NULL für einen optionalen Parameter oder willst Kompatibilität mit C (z.B. für eine Public API), so verwende Call by Pointer, da dies mit Referenzen nicht möglich ist.
Ele