Почему функция «cpy» работает со строками?
Возьмите за правило делать все конструкторы с одним аргументом explicit (хорошо, есть случаи, когда это может оказаться неудобным, но новичку совет хороший).  В этом случае не будет неявных преобразований и ваш код не скомпилируется пока вы не напишите a.cpy(String("rap")).print().
И я всё понимаю, но назвать функцию "cpy"... Так и тянет прочитать по-русски. Эту функцию чисто по смыслу надо заменить на оператор присванивания.
String(const char *str);//конструктор по принимаемой строке
вот и ответ. (конструктор неявного преобразования).
Если хотите проверить - поставьте перед этим конструктором кейворд explicit - и строка a.cpy("rap").print();
должна перестать компилироваться.