AcceleratedC++/Chapter8 | AcceleratedC++/Chapter10 |
기본 타입 | char, int, double 등 기본언어의 일부 |
클래스 타입 | string, vector, istream 등 기본언어를 가지고 구현된 타입 |
~cpp struct Student_info { std::string name; double midterm, final; std::vector<double> homework; };
~cpp struct Student_info { std::string name; double midterm, final; std::vector<double> homework; std::istream& read(std::istream&); //입력 스트림으로 부터 입력을 받아서 4개의 멤버변수를 초기화한다. double grade() const; //내부 멤버변수를 활용하여 점수를 계산하고 double 형으로 리턴한다. //함수 명의 뒤에 const를 붙이면 멤버 변수의 변형을 할 수 없는 함수가 된다. (구조적으로 좋다) };
~cpp istream & Student_info::read(istream& in) { in>>name>>midterm>>final; read_hw(in, homework); return in; }이 함수에서 알아야할 3가지
~cpp double Student_info::grade() const { return ::grade(midterm, final, homework); }::를 사용함으로써 호출되는 grade를 객체의 멤버함수가 아니라 전역 grade의 형으로 사용하는 것이 가능하다.
~cpp class Student_info { public: //interface is here double grade() const; std::istream& read(std::istream&); private: //implementation is here std::string name; double midterm, final; std::vector<double> homework; };struct 키워드 대신 class 키워드 사용. 보호레이블(protection label) 사용. 레이블은 순서없이 여러분 중복으로 나와도 무관함.
class 키워드를 사용한 클래스 | 기본 보호모드가 private 으로 동작한다. |
struct 키워드를 사용한 클래스 | 기본 보호모드가 public 으로 동작한다. |
~cpp class Student_info { public: double grade() const; }; struct Student_info { dobule grade() const; };
~cpp class Student_info { std::string name; public: double grade() const; }; struct Student_info { private: std::string name; public: dobule grade() const; };일반적으로 자료구조가 간단할 때에는 struct를 이용한다. 그러나 2가지 키워드의 사용의 차이는 존재하지 않는다. 단지 문서화를 어떻게 하느냐에 의해 차이가 생길 뿐이다.
~cpp class Student_info { public: double grade() const; std::istream& read(std::istream&); std::string name() const {return n;} private: std::string n; double midterm, final; std::vector<double> homework; };name 멤버 변수에 직접적으로 접근하는 대신에 name()함수를 만들어서 접근하도록 만들었다. const 함수이므로 멤버변수의 변경을 불허한다. 리턴값이 복사된 것이기 때문에 변경을 하더라도 멤버변수에 영향을 주지는 않는다.
~cpp bool compare(const Student_info& x, const Student_info& y) { return x.name() < y.name(); }인자로 받은 변수들을 직접 접근하지 않고 그 멤버함수로 접근한다.
~cpp class Student_info { public: double grade() const; std::istream& read(std::istream&); std::string name() const {return n;} bool valid() const { return !homework.empty(); } // 사용자에게 그 객체가 유효한 데이터를 가졌는지를 알려준다. private: std::string n; double midterm, final; std::vector<double> homework; };상기와 같은 방식으로 통해서 grade를 호출하기 전에 객체의 유효성을 검사한다면 에러를 없애는 것이 가능하다.
~cpp class Student_info { public: double grade() const; std::istream& read(std::istream&); std::string name() const {return n;} bool valid() const { return !homework.empty(); } // 사용자에게 그 객체가 유효한 데이터를 가졌는지를 알려준다. private: std::string n; double midterm, final; std::vector<double> homework; }; bool compare(const Student_info& x, const Student& y);동일한 일을 하지만 프로그래머는 실제로 객체의 내부의 구현을 감추는 것이 가능하다.
~cpp class Student_info { public: Student_info(); Student_info(std::istream&); };
~cpp Student_info::Student_info():midterm(0). final(0) {} // n, homework 의 경우 STL에서 제공되는 디폴트 생성자가 재귀적으로 호출
객체의 생성 순서 |
* 구현 시스템이 객체를 담을만한 메모리를 할당함. * 초기 설정자 목록에 의해 객체들을 초기화 * 생성자 본체를 실행 |
~cpp Student_info::Student_info(istream& is) {read(is);}이 생성자는 실질적인 작업을 read 함수에 위임합니다.
~cpp //Student_info.h #ifndef GUARD_Student_info #define GUARD_Student_info #include <string> #include <vector> class Student_info { public: Student_info(); // construct an empty `Student_info' object Student_info(std::istream&); // construct one by reading a stream std::string name() const { return n; } bool valid() const { return !homework.empty(); } // as defined in 9.2.1/157, and changed to read into `n' instead of `name' std::istream& read(std::istream&); double grade() const; // as defined in 9.2.1/158 private: std::string n; double midterm, final; std::vector<double> homework; }; bool compare(const Student_info&, const Student_info&); #endif
~cpp //Student_info.cpp #include <iostream> #include <vector> #include "grade.h" #include "Student_info.h" using std::istream; using std::vector; double Student_info::grade() const { return ::grade(midterm, final, homework); } bool compare(const Student_info& x, const Student_info& y) { return x.name() < y.name(); } Student_info::Student_info(): midterm(0), final(0) { } Student_info::Student_info(istream& is) { read(is); } // read homework grades from an input stream into a `vector<double>' istream& read_hw(istream& in, vector<double>& hw) { if (in) { // get rid of previous contents hw.clear(); // read homework grades double x; while (in >> x) hw.push_back(x); // clear the stream so that input will work for the next student in.clear(); } return in; } istream& Student_info::read(istream& in) { in >> n >> midterm >> final; read_hw(in, homework); return in; }
~cpp //grading_prog.cpp #include <algorithm> #include <iomanip> #include <ios> #include <iostream> #include <stdexcept> #include <string> #include <vector> using std::max; #include "Student_info.h" #include "median.h" using std::cin; using std::cout; using std::domain_error; using std::endl; using std::setprecision; using std::setw; using std::sort; using std::streamsize; using std::string; using std::vector; int main() { vector<Student_info> students; Student_info record; string::size_type maxlen = 0; // read and store the data while (record.read(cin)) { // changed maxlen = max(maxlen, record.name().size()); // changed students.push_back(record); } // alphabetize the student records sort(students.begin(), students.end(), compare); // write the names and grades for (vector<Student_info>::size_type i = 0; i != students.size(); ++i) { cout << students[i].name() // this and the next line changed << string(maxlen + 1 - students[i].name().size(), ' '); try { double final_grade = students[i].grade(); // changed streamsize prec = cout.precision(); cout << setprecision(3) << final_grade << setprecision(prec) << endl; } catch (domain_error e) { cout << e.what() << endl; } } return 0; }