Nel caso specifico di un ostream come cout, nella catena di derivazione, è disabilitato il passaggio per valore. (non ricordo in che punto, forse ios)
http://www.cplusplus.com/reference/iostream/
Nel caso l'operatore fosse definito per due classi differenti, si ricade sempre nel doppio passaggio per valore con annessi e connessi.
Costruttore di copia all'ingresso e all'uscita della funzione e se la classe contiene raw pointer, occorre fare molta attenzione.
C'è poi un altro caso.
test stamperà "A" , non B in quanto si verifica lo slicing della classe.codice:class A { public: virtual void p() { cout << "A" << endl; } }; class B : public A { public: void p() { cout << "B" << endl; } }; void test(A a) { a.p(); } main() { B b; test(b); }