Short Version
Overload the insertion operator.
TL;DR Version
While there is nothing harmful about a function that only writes to cout, it is much more useful, and no harder to write, a function that can write to any ostream.
void Student::PrintStudentDetails(std::ostream & out) // pass in any out stream
{
    out << "Name: " << student.GetName() << '\n'
        << "Age: " << student.GetAge() << '\n'
        << "Gender: " << student.GetGender() << '\n';
}
Note: insertion operators can chain.
Side note: std::endl is a new line AND a stream flush, and that stream flush can be very expensive. Generally you only want to flush when you have to to push information immediately to a client or the stream's buffer is full. Prefer to use '\n' to endl in most other cases.
It is only marginally more difficult to write a << overload that prints your class so you can anystream << myClassInstance;. 
std::ostream & operator<<(std::ostream & out, // any outstream
                          const Student & student) // the object to print
{
    out << "Name: " << student.GetName() << '\n'
        << "Age: " << student.GetAge() << '\n'
        << "Gender: " << student.GetGender() << '\n';
    return out; // this is the magic that allows chaining
}
You can now 
cout << myStudent;
Note: the insertion operator is often implemented as a friend of the class in order to provide easy access to private variables.
For more wisdom on overloading operators read What are the basic rules and idioms for operator overloading?