Czemu funkcja:

std::istream & operator>>(std::istream & is, const complex & c)
{
    std::cout << "skladowa rzeczywista: ";
    is >> c.real;
    std::cout << "skladowa urojona: ";
    is >> c.imag;
    return is;
}

się zapętla?

P.S. Już wiem dlaczego, bo konstruktor daje możliwość konwersji double na complex. Dodatkowo trzeba wyrzucić słowo const z parametru complex.