파일입출력
fstream
#include <fstream>
기본 메소드
- .open("파일 명") : 파일명에 해당하는 파일 열기
- .is_open() : 파일 열기에 성공하면 true
- .fail() : 파일 열기에 실패하면 true
- .close() : 파일 닫기
ifstream - 파일 읽기
std::ifstream file; // 파일을 담을 변수
file.open("test.txt"); // test.txt 파일 열기
std::ifstream file("test.txt"); // 파일을 담을 변수 선언과 동시에 파일 열기
string str;
file >> str; // 띄어쓰기 전까지 읽어서 str에 저장
string line;
std::getline(file, line); // 엔터 전까지 읽어서 line에 저장
ofstream - 파일 쓰기
std::ofstream file;
file.open("test.txt");
std::ofstream file("test.txt");
if(file.fail())
cout << "파일 없음" << endl;
file << "hello world!";
실습 - 파일에 입력된 내용을 거꾸로 쓰기
- 벡터를 활용한다 (벡터를 거꾸로 읽어서 쓰기)
string line;
vector<string> v;
ifstream file("hello");
if (file.is_open())
{
while(getline(file, line))
v.push_back(line);
}
file.close();
ofstream file2("output");
if (file2.is_open())
{
for (int i=0; i<v.size();i++)
file2 << v.at(v.size()-1-i) << endl;
}
file2.close();
실습 - 회원명부를 이용한 로그인 성공 시 전화번호 저장하기
ifstream member("member.txt");
string name, pw, name_in, pw_in;
cout << "이름을 입력하세요: ";
cin >> name_in;
cout << "비밀번호를 입력하세요: ";
cin >> pw_in;
bool is_login = false;
if (member.is_open()) {
while (member >> name >> pw) {
if (name_in == name && pw_in == pw) { //로그인 성공
is_login = true;
break;
}
}
if (is_login) {
cout << "로그인 성공\n";
string num_in, num;
cout << "전화번호를 입력하세요 : ";
cin >> num_in;
ifstream member_tel_r("member_tel.txt");
bool is_modify = false;
string member_tel_tmp = "";
if (member_tel_r.is_open()) {
while (member_tel_r >> name >> num) {
string line = name + " ";
if (name_in == name) { //이미 있는 경우
is_modify = true;
line += num_in; //새로 입력받은 번호를 저장
}
else {
line += num;
}
member_tel_tmp += line + "\n";
}
}
member_tel_r.close();
ofstream member_tel_w;
if (is_modify) { //파일이 변경된 경우
member_tel_w.open("member_tel.txt");
member_tel_w << member_tel_tmp;
}
else { //변경되지 않은 경우
member_tel_w.open("member_tel.txt", ios::app);
if (member_tel_w.is_open()) {
member_tel_w << name_in << " " << num_in << endl;
}
}
member_tel_w.close();
} else cout << "로그인 실패\n";
}
else cout << "파일을 읽지 못하였습니다.\n";
member.close();
구조체
struct Position {
int x=0;
int y=0;
};
Position p;
p.x=3;
p.y=5;
클래스
객체 지향 프로그래밍
- 필요한 데이터와 코드를 묶어 하나의 객체로 만들고 이 객체들 간에 상호작용을 하도록 프로그램을 만드는 방식
- 실제 세계를 모델링하여 소프트웨어를 개발
- 장점 : 코드 재사용, 유지보수 용이
- 단점 : 처리속도가 느림, 설계가 복잡함
절차 지향 프로그래밍
- 순차적인 처리가 중요시됨
- 프로그램 전체가 유기적으로 연결되도록 만드는 프로그래밍 기법
- 장점 : 컴퓨터의 처리구조와 유사해 실행속도가 빠름
- 단점 : 유지보수가 어려움, 코드의 순서가 바뀌면 결과가 달라짐
객체(object)
- 실생활에서 우리가 인식할 수 있는 사물
- 객체의 상태(속성)
- 객체의 동작
클래스
class Position {
// 필드(변수)
int x=0;
int y=0;
public:
Position() {} // 생성자
void printXY() { // 메소드
std::cout << x << y;
}
}
int main() {
Position p; // p 객체 생성
}
생성자
- 생성자도 메소드의 일종이다. 리턴 타입이 없는 이유는 리턴타입을 지정할 수 없어서. 하지만 리턴은 일어나고 있다.
- 생성자는 객체를 생성할 때 꼭 호출해야 한다.
- 클래스를 정의할 때 생성자를 꼭 정의해야하는건 아니다. 생성자를 정의하지 않을 경우 기본 생성자가 자동으로 만들어진다.
- 생성자가 정의되지 않은 클래스로 객체를 만들 때 기본생성자가 자동으로 호출된다.
- 생성자가 정의되면 기본생성자를 만들어주지 않고 정의된 생성자만 존재한다.
클래스와 구조체
- 구조체도 변수 뿐만 아니라 생성자, 메소드를 가질 수 있다.
- 구조체 : 하나의 변수만으로 표현하기 어려운 것들을 표현하기 위해
- 클래스 : 객체지향 프로그래밍을 실현하기 위해
- 구조체의 접근 제어자의 기본값 : public
- 클래스의 접근 제어자의 기본값 : private (정보 은닉의 중요성)
접근 제어자
- public : 어디서나 접근 가능
- private : 자기 자신(해당 클래스 내)에서만 접근 가능
- protected : 자기자신과 자식클래스(해당 클래스 & 하위 클래스 내)에서만 접근 가능 (상속 개념)
getter, setter
- 클래스 외부에서 private 변수에 접근할 수 있도록 도와주는 메소드
- getter : 변수를 반환해주는 메소드
- setter : 변수에 값을 할당해주는 메소드
실습 - 클래스 사용
- 접근제어자를 지정하지 않으면 private, 생성자는 public
- private 속성값은 getter,setter를 이용해 접근할 수 있다.
- 클래스 내에서 속성은 this-> 로 구별
class Rectangle {
double width;
double height;
public:
// 생성자
Rectangle() {}
Rectangle(double w, double h) {
this->width = w;
this->height = h;
}
// getter 함수
double getWidth() {
return width;
}
double getHeight() {
return height;
}
//setter 함수
void setWidth(double w){
this->width = w;
}
void setHeight(double h){
this->height = h;
}
double area() {
return this->width * this->height;
}
};
int main()
{
Rectangle r(width, height);
r.setWidth(width);
r.setHeight(height);
cout << r.area() << endl;
}
객체 지향 프로그래밍의 4가지 특징
- 추상화 : 객체의 공통적인 속성과 기능을 추출하여 정의하는 것 - 필드와 메서드로
- 캡슐화 : 연관 있는 속성과 기능들을 하나의 캡슐로 만들어 내부의 데이터들을 외부로부터 보호하는 것 - 데이터 보호, 데이터 은닉
- 상속 : 부모클래스에 정의된 속성(변수) 및 기능(메서드)들을 자식 클래스에서 상속받아 사용하는 것
- 다형성 : 같은 대상이라도 문맥이나 상황에 따라 다르게 사용될 수 있다는 원리 - 상위(부모)클래스로 하위(자식)클래스의 인스턴스를 생성할 수 있음
클래스 상속
- 부모 클래스에 있는 멤버(변수, 메소드)를 자식 클래스에서 사용할 수 있게 됨
class Person { //Student의 부모 클래스, 슈퍼 클래스, 상위 클래스
protected:
string name;
int age;
// 필드, 메소드, 생성자
public: // private, protected
//Person() { return ???; } // 기본 생성자
Person(string name, int age) {
this->name = name;
this->age = age;
}
Person() {}
//Person(int age) {}
//Person p = Person("김소연");
//Person() {}
//Person p = Person();
void sleep() { cout << "잠자기 zzzz"; }
};
class Student : public Person {
// 부모 클래스에서 상속받은 멤버들의 접근제어자의 한계를 지정함.
string stu_id;
protected:
string name;
int age;
public:
//Student 생성자를 작성하지 않은 경우. 기본 형태
//Student(){ Person(); ~~~~~; return; }
Student(string name, int age) : Person(name, age) {
//this->name = name;
//this->age = age;
//부모클래스의 생성자를 선택함.
this->stu_id = "11111111111";
//return 값;
}
void study(){
sleep();
cout << "공부하기";
}
};
int main(){
//Person p = Person("김소연"); // 객체를 생성하는 순간.
//Person p = Person();
//Person p = Person(1,3);
Student s = Student("김소연", 99);
s.sleep();
return 0;
}
오버라이딩
- 상속 관계
- 부모 클래스에서 이미 정의된 메소드를 자식 클래스에서 다시 정의하는 것
- 함수의 원형이 완전히 같아야 함(이름, 매개변수의 유형, 매개변수 개수, 자료형)
오버로딩
- 기본 문법 (클래스에 국한된 개념이 아님)
- 같은 이름의 함수를 중복하여 정의하는 것
- 매개변수의 유형과 개수가 달라도 됨