2

When I input the value for the string types, for examples:

_ho I typed Peter
_hoten I typed Peter Parker
_ten I typed Marry

My output on the screen was:

Peter Peter Marry

Here is my code:

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");
}
JeJo
  • 20,530
  • 5
  • 29
  • 68
F.Wu
  • 55
  • 5
  • 2
    How are you calling the functions. Please provide an MCVE. – P.W Nov 04 '18 at 09:45
  • @P.W I have updated the post. – F.Wu Nov 04 '18 at 09:49
  • Unrelated to your question but, you can simplify the code as well as make it more performant (not important here but good practice is good practice) by eliminating pointers and `new`/`delete` by automatically allocating `SinhVien` i.e. `SinhVien* a = new SinhVien` -> `SinhVien a;` and passing by reference instead of by pointer, i.e. `istream& operator>>(istream& in, SinhVien *p)` -> `istream& operator>>(istream& in, SinhVien& p)`. – George Nov 04 '18 at 10:11

1 Answers1

2

In your std::basic_istream::operator>> overload, you need to use std::geline() instead of std::cin >>, so that you can get complete input name with spaces.

Secondly, you should pass the reference of the object pointer, so that the change will be applied to the passed object, not to its copy.

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;
}

Above will work for one single input. However, the case of multiple inputs and use of std::cin >> in the main() can cause again some input skipping problems. Thanks to @Yksisarvinen pointing this out. You can read more in this SO post: Why does std::getline() skip input after a formatted extraction?


Side note: In modern C++, you do not need to manage the raw pointers, anymore. Because you have smart pointers which will manage your object's lifetime as it goes out of scope. So use it whenever its possible.

That means you can do something like this: 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;
}
JeJo
  • 20,530
  • 5
  • 29
  • 68
  • @JeJo one more thing. Why do we add the std:: before every our operator? – F.Wu Nov 04 '18 at 10:27
  • @F.Wu Because `using namespace std;` is [considered as a bad coding paractice](https://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice). Read the link for more info. – JeJo Nov 04 '18 at 10:29