Il punto non è ottimizzare, ma fare attenzione perché il programma non vada in tilt.
Ad esempio:
codice:
Image* img = new Image(...);
Button btn(img); // passo il puntatore ad un oggetto nell'heap. 
//Dove lo libero? Nel distruttore di Button o in seguito? 

Image img_a(...);
Button btn_a(&img_a); // passo il puntatore di un oggetto sullo stack. 
// Non posso fare una delete di un oggetto posto sullo stack. 

Image* img_a = new Image(...);
Button btn_b(*img_b); // passo il reference.  
delete img_b;
// il reference di btn_b adesso è invalido.
Sono esempi un pò forzati, ma dovrebbero rendere l'idea di che succede se non si fà attenzione al lifetime dell'oggetto considerato.

Invece:

codice:
Image* img = new Image(...);
Button btn(img); // passo il puntatore ad un oggetto nell'heap, 
ma non lo libero nel distruttore: ci devo pensare fuori.  

Image img_a(...);
Button btn_a(&img_a); // passo il puntatore di un oggetto sullo stack. 

Image img_b(...)
Button btn(img_b); // passo un reference. 
//L'oggetto img_b ha lifetime superiore rispetto a btn, quindi sono sicuro.
Vanno bene.
In caso tu voglia utilizzare un reference, la sintassi della classe diventa:
codice:
class Button
{
private:
	Image& img; 
public:
	Button(Image& i ) : img(i) // obbligatorio
	{ }
	
	void draw( void )
	{
		img.draw();
	}
};