Ошибка при перегрузке opertor >> для строковых членов в классе - PullRequest
0 голосов
/ 04 ноября 2018

При вводе значения для типов string , например:

_ho Я набрал Peter
_hoten Я набрал Peter Parker
_ten Я набрал Marry

Мой вывод на экран был:

Peter Peter Marry

Вот мой код:

class SinhVien
{
private:
    string _ho;
    string _tenlot;
    string _ten;
public:
    static int InstanceCount;
    SinhVien();
    string ToString() const;
    friend istream& operator>>(istream& in, SinhVien* p);
    friend ostream& operator<<(ostream& out, const SinhVien* p);
    ~SinhVien();
};
istream& operator>>(istream& in, SinhVien *p)
{
    cout << "Nhap ho: \n";
    in >> p->_ho;
    rewind(stdin);
    cout << "Nhap ten lot: \n";
    in >>  p->_tenlot;
    rewind(stdin);
    cout << "Nhap ten: \n";
    in >> p->_ten;
    return in;
}
string SinhVien::ToString() const
{
    stringstream writer;
    writer << _ho << " " << _tenlot << " " << _ten << "\n";
    return writer.str();
}
ostream& operator<<(ostream &out, const SinhVien* p)
{
    out << p->ToString();
    return out;
}

void main()
{
    SinhVien *a;
    a = new SinhVien();
    cin >> a;
    cout << a;
    cout << "\nTo string:\n";
    cout << a->ToString();
    delete a;
    system("pause");
}

1 Ответ

0 голосов
/ 04 ноября 2018

При вашей перегрузке std::basic_istream::operator>> вам нужно использовать std :: geline () вместо std::cin >>, чтобы вы могли получить полное имя ввода с пространства .

Во-вторых, вы должны передать ссылку на указатель объекта, чтобы изменение было применено к переданному объекту, а не к его копии.

Fix:

std::istream& operator>>(std::istream& in, SinhVien* &p)
{                                                // ^^ take ref of object you pass, so that the change will be applied to the object, not to the copy of it.
    std::cout << "Nhap ho: \n";
    std::getline(in, p->_ho);   // change
    std::rewind(stdin);
    std::cout << "Nhap ten lot: \n";
    std::getline(in, p->_tenlot);   // change
    std::rewind(stdin);
    std::cout << "Nhap ten: \n";
    std::getline(in, p->_ten);   // change
    return in;
}

Выше будет работать для одного входа. Однако в случае нескольких входов и использования std::cin >> в main() могут снова возникнуть некоторые проблемы с пропуском ввода. Спасибо @Yksisarvinen за это. Вы можете прочитать больше в этом посте SO: Почему std :: getline () пропускает ввод после форматированного извлечения?


Примечание : В современном C ++ вам больше не нужно управлять необработанными указателями. Потому что у вас есть умных указателей , которые будут управлять временем жизни вашего объекта, когда он выходит из области видимости. Так что используйте его, когда это возможно.

Это означает, что вы можете сделать что-то вроде этого: SEE LIVE

#include <memory>

class SinhVien
{
private: // memebrs
public:
    // other member functions
    friend istream& operator>>(istream& in, const std::unique_ptr<SinhVien> &p);
    friend ostream& operator<<(ostream& out, const std::unique_ptr<SinhVien> &p);
};

std::istream& operator>>(std::istream& in, const std::unique_ptr<SinhVien> &p)
{                                                                          
    std::cout << "Nhap ho: \n";
    std::getline(in, p->_ho);   // change
    std::cout << "Nhap ten lot: \n";
    std::getline(in, p->_tenlot);   // change
    std::rewind(stdin);
    std::cout << "Nhap ten: \n";
    std::getline(in, p->_ten);   // change
    return in;
}

std::ostream& operator<<(std::ostream &out, const std::unique_ptr<SinhVien> &p)
{
    return out << p->ToString();
}

int main()
{
    auto a = std::make_unique<SinhVien>();
    std::cin >> a;
    std::cout << a;
    std::cout << "\nTo string:\n";
    std::cout << a->ToString();
    return 0;
}
...