and the suppliedManagedAccount is of type BrassAccount it calls the operator<<() for the BankAccount class instead of the derived class (BrassAccount). Why?
BankAccount myBankAccount();
BrassAccount myBrassAccount();
BankAccount* myPointer = &myBankAccount;
cout << *myPointer; // *myPointer is a BankAccount object, uses friend ostream& operator<<(ostream &os, const BankAccount &rhs)
myPointer = &myBrassAccount;
cout << *myPointer; // *myPointer is a BrassAccount object, SHOULD use friend ostream& operator<<(ostream &os, const BrassAccount &rhs);
it should work as described in the comments, right? Obviously not.. . But myPointer is pointing to a BrassAccount object, so *myPointer is the BrassObject and an output function is provided specifically for a BrassAccount.
The type of *myPointer is 'BankAccount &' because the type of myPointer is 'BankAccount *'. The complete type of the object pointed to by myPointer is stored only as run time type information, but the call to the correct operator<<() overload is resolved at compile time because the call is non-virtual.
For dynamic dispatch, you need a virtual print() function in the base class (you can make it protected if you want) that the derived class overrides.