📘 OOP 특징

1장

c++에서 추가된 기능을 설명할 수 있어야함

  • 함수 중복 : 매개 변수의 개수나 타입이 다른 동일한 이름의 함수들 선언
  • 디폴트 매개 변수 : 매개 변수에 디폴트 값이 전달되도록 함수 선언
  • 참조와 참조 변수 : 하나의 변수에 별명을 사용하는 참조 변수 도입
  • 참조에 의한 호출 : 함수 호출 시 참조 전달
  • new/delete 연산자 : 동적 메모리 할당/해제 를 위해 new와 delete연산자 도입
  • 연산자 재정의 : 기존 c++ 연산자에 새로운 연산 정의
  • 재네릭(generic)함수와 클래스 : 데이터 타입에 의존하지 않고 일반화 시킨 함수나 클래스 작성 가능

객체지향의 특성 3가지 캡슐화 상속 다형성 개념을 설명할 수 있어야함

  • 캡슐화 : 실세계 대상과 속성을 하나로 묶어주면서 외부의 감춰야될 속성들을 은닉하는것 c++에서는 클래스키워드로 구현하고 클래스+정보은닉 개념은 접근 지정자를 통해서 언어를 통해서 구현한다고 했다.
    • 클래스 키워드로 객체의 상태와 행동을 하나의 캡슐로 묶어주고 접근지정자를 통해서 외부의 접근으로부터 보호 하는것
  • 상속 : 객체에 대한 자산을 재사용하게끔 부여하는 것
    • 기존 클래스를 재사용(확장)하여 새로운 클래스를 작성하는것
  • 다형성 : 이름 같은 레퍼런스인데 반응하는것이 다른 것
    • 서로 다른 객체가 동일한 메시지에 대해 다른 방법으로 응답할 수 있는 기능

객체지향프로그래밍과 절차지향프로그래밍의 차이점

  • 절차지향언어는 : 동사중심의 명령할 순서와 흐름의 중점을 둠
    • 실행하고자 하는 절차대로 일련의 명령어 나열, 흐름도를 설계하고 흐름도에 따라 프로그램 작성
  • 객체지향 언어 : 객체간의 상호작용 객체간의 메시지를 주고받으면서 진행됨
    • 객체들을 정의하고, 객체들의 상호 관계, 상호 작용으로 구현

2장

cin cout namespace키워드 알기

  • cin cout 사용법
    • iostrem 헤더파일을 선언 , 표준 입출력을 위한 클래스와 객체,변수 등이 선언됨
    • cout : 스크린 출력 장치에 연결된 표준 c++ 출력 스트림 객체 ,std::cout으로 사용
    • « 연산자 : 스트림 삽입 연산자 cout 객체에 연결된 화면에 출력
    • 다음줄로 넘어가기 endl;
    • cin : 표준 입력 장치인 키보드를 연결하는 c++입력 스트림 객체 (enter키가 입력될때까지 입력된 키를 입력 버퍼에 저장
    • 연산자 : 스트림 추출 연산자 입력스트림에서 값을 읽어 변수에 저장

  • namespace : 동일한 클래스 이름에 대해서 충돌을 막히 위해 쓰는 것 namespace
    • namespace kitae{f()} ⇒ f() = kitae::f()
  • c++의 표준은 std라는 namespace를 쓰기 때문에 키워드를 알아야할것
    • ANSI c++ 표준라이브러리에서 정의한 이름 공간
    • using namespace std; ⇒ cout«”hello””«endl; // std생략

헤더파일

#include<헤더파일> : 헤더파일을 찾는 위치는 컴파일러가 설치된 폴더

#include”헤더파일” : 헤더파일을 찾는 위치는 개발자의 프로젝트 폴더

  • 클래스를 헤더파일과 cpp파일로 분리하여 작성
    • 클래스 선언 부는 헤더파일(.h)에 저장
    • 클래스 구현부는 소스파일 (.cpp)에 저장
    • 특정 클래스를 활용하고자 하면 클래스가 선언된 헤더파일 include 함

문자열 사용하는 2가지 방법

cstring이나 string 클래스 방법을 설명할수 있어야함

  • C-스트링 방식 : \0 로 끝나는 문자 배열
    • char name1[6] = = {‘G’, ‘r’, ‘a’, ‘c’, ‘e’, ‘\0’}; // name1은 문자열 “Grace”
    • char name5[10] = “Grace”; name[6~9] \0 으로 초기화
      • 빈칸을 만나면 문자열 입력 종료
    • strcmp()문자열 비교, strlen(),strcpy()사용가능
    • #include, #include
    • 공백이 낀 문자열을 입력 받는 방법
      • cin.getline(char buf[],int size, char delimitChar)
      • cin.getline(address, 100, ‘\n’); buf에 최대 size-1 끝에 \0
        • 최대 99개의 문자를 읽어 address 배열에 저장. 도중에 키를 만나면 입력 중단
  • string클래스 : 다양한 멤버 함수 제공, 문자열 비교 ,복사 ,수정등
    • c-스트링보다 다루기 쉬움
    • 문자열의 크기에 따른 제약 없음
    • string 클래스가 스스로 문자열 크기에 맞게 내부 버퍼 조절
    • #include
    • getline(cin, singer); single에 string타입의 문자열을 입력받음
    • string str = “I love “; // str은 ‘I’, ‘ ‘, ‘l’, ‘o’, ‘v’, ‘e’, ‘ ‘의 7개 문자로 구성 str.append(“C++.”); // str은 “I love C++.”이 된다. 11개의 문자

string 이나 int 입력받는 코드 짜는거 시험 나옴

3장

생성자와 소멸자의 특성을 설명할 수 있어야함

  • 생성자 : 객체가 생성되는 시점에서 자동으로 호출되는 멤버 함수
    • 클래스 이름과 동일한 멤버 함수
      • 목적 : 객체가 생성될 때 초기화를 위해 필요
      • 리턴타입을 선언하지 않음 , 객체 생성 시 오직 한번만 자동으로 호출
      • 생성자는 중복 가능 : 생성자는 한 클래스 내에 여러 개 가능 , 중복된 생성자 중 하나만 실행되지만 이 생성자가 다른 생성자를 호출할 수 있다.
      • 생성자가 선언되어 있지 않으면 기본 생성자 자동으로 생성 : 기본 생성자 - 매개 변수 없는 생성자, 컴파일러에 의해 자동 생성
    • 위임 생성자 : Circle::Circle() : Circle(1)
    • 타겟 생성자 : Circle::Circle(int r)
    • 소멸자 : 객체가 소멸되는 시점에서 자동으로 호출되는 함수
      • 오직 한번만 자동 호출, 임의로 호출할 수 없음
      • 객체 메모리 소멸 직전 호출됨
      • Circle::~Circle(){}
      • 목적 : 객체가 사라질 때 마무리 작업
      • 중복 불가능 : 소멸자는 한 클래스 내에 오직 한 개만 작성 가능
      • 소멸자가 선언 되어 있지 않으면 기본 소멸자가 자동 생성(아무 것도 하지 않고 단순 리턴)
      • 지역 객체 : 함수 내에 선언된 객체, 함수가 종료하면 소멸
      • 전역 객체 : 함수의 바깥에 선언된 객체 , 프로그램이 종료 될때 소멸

생성자를 통해서 변수를 초기화 하는데 생성자 맴버 변수 초기화 하는 방법 3가지 방법 코드 짤수 있어야함

생성자 코드에서 멤버 변수 초기화
Point::Point() { x = 0; y = 0; }
Point::Point(int a, int b) { x = a; y = b; }

생성자 서두에 초깃값으로 초기화
Point::Point() : x(0), y(0) { // 멤버 변수 x, y를 0으로 초기화
}
Point::Point(int a, int b) // 멤버 변수 x=a로, y=b로 초기화
: x(a), y(b) { // 콜론(:) 이하 부분을 밑줄에 써도 됨
}
클래스 선언부에서 직접 초기화
class Point {
int x=0; y=0; // 클래스 선언부에서 x, y를 0으로 직접 초기화
public:
};

생성자에서 컴파일 오류가 나는 이유를 설명할 수 있어야함

개발자가 클래스에 생성자를 작성해 놓을 경우 컴파일러는 기본 생성자를 자동으로 생성하지 않음

밑을 보면 circle클래스에 생성자가 선언되어 있기 때문에 컴파일러는 기본 생성자를 자동으로 생성하지 않는데 main에서 기본생성자를 호출하여서 컴파일 오류가 발생

class Circle {
public:
int radius;
double getArea();
Circle(int r);
};
Circle::Circle(int r) {
radius = r;
}
int main() {
Circle pizza(30);
Circle donut;
}

접근지정자에 대해서 키워드에 관한 부분을 알아야함

중요한 멤버는 다른 클래스나 객체에서 접근 할 수 없도록 보호

  • private : 동일한 클래스의 멤버 함수에만 제한함(디폴트접근지정)
  • public : 모든 다른 클래스에 허용
  • protected : 클래스 자신과 상속받은 자식 클래스에만 허용

헤더파일을 통해서 클래스 선언하는 경우 조건컴파일문에 대해 알아야함

헤더파일의 주복 include 문제를 조건 컴파일로 해결

Circle.h
#ifndef CIRCLE_H
#define CIRCLE_H
class Circle {
};
#endif

main.cpp
#include <iostream>
using namespace std;
#include "Circle.h"
#include "Circle.h"
#include "Circle.h"
int main() {
...........
} 컴파일 오류 없음

inline함수의 사용법

  • 작은 크기의 함수를 호출하면, 함수 실행 시간에 비해, 호출을 위해 소요되는 부가적인 시간 오버헤드가 상대적으로 크다.
  • 인라인 함수를 호출하는 곳에 컴파일러가 인라인 함수 코드를 확장 삽입
  • 인라인 함수 호출로 프로그램의 실행 속도 개선
  • c++프로그램의 실행속도 향상
  • recursion, 긴 함수, static, 반복문, goto 문 등을 가진 함수는 수용하지 않음
  • 사용법 : 앞에 inline을 붙이면 된다 inline Circle :: Circle()

구조체와 클래스의 차이점도 알아야함

  • 상속,멤버,접근지정등 모든 것이 클래스와 동일
  • 유일하게 다른점 구조체의 디폴트 접근 지정은 -public
  • 수용한 이유 : c언어와의 호환성 때문 , c의 구조체 100프로 호환 수용, c소스를 그대로 가져다 쓰기 위해

타겟 생성자 : 객체 초기화를 전담하는 생성자 위임 생성자 : 타겟 생성자를 호출하는 생성자, 객체 초기화를 타겟 생성자에 위임

Circle::Circle() : Circle(1) { // Circle::Circle(int r)의 생성자 호출
}
Circle::Circle(int r) {
radius = r;
cout << "반지름 “<<radius<<"  생성<<endl;
}

4장

객체배열을 생성하고 반환하는 방법

배열 선언

  1. 객체 배열을 위한 공간 할당
  2. 배열의 각 원소 객체마다 생성자 실행
    • c[0]의 생성자, c[1]의 생성자, c[2]의 생성자 실행
    • 매개 변수 없는 생성자 호출
    • 매개 변수 있는 생성자를 호출할 수 없음

배열 소멸

  • 배열의 각 객체마다 소멸자 호출, 소멸 순서는 생성의 반대순

객체 배열의 원소를 접근하는 방법 2가지 (index,pointer)코드 작성할 줄 알아야함

  1. index

    for(int i=0; i<3; i++) // 배열의 각 원소 객체의 멤버 접근 circleArray[i].getArea()

  2. pointer

    Circle *p = pArray; for(int i=0; i<3; i++) { cout « p->getArea() « ‘\n’; p++;

Circle p; p = &donut; cout « p->getArea() « endl; // donut의 getArea() 호출 cout « (p).getArea() «endl; // donut의 getArea() 호출 p = &pizza; cout « p->getArea() « endl; // pizza의 getArea() 호출 cout « (*p).getArea() « endl; // pizza의 getArea() 호출

객체 배열 생성할때 컴파일 오류가 나는경우를 설명할 수 있어야함

개발자가 클래스에 생성자를 작성해 놓을 경우 컴파일러는 기본 생성자를 자동으로 생성하지 않음

밑을 보면 circle클래스에 생성자가 선언되어 있기 때문에 컴파일러는 기본 생성자를 자동으로 생성하지 않는데 main에서 기본생성자를 호출하여서 컴파일 오류가 발생

#include <iostream>
using namespace std;
class Circle {
int radius;
public:
Circle(int r) { radius = r; }
double getArea() {
return 3.14*radius*radius;
}
};
int main() {
Circle waffle(15);
Circle circleArray[3];
}
현재 Circle(int r) 이라는 생성자가 선언되어 있기 때문에 컴파일러는 기본 생성자를 자동으로
생성하지 않는데 main에서 기본생성자를 호출하여서 컴파일 오류가 발생

thispoint의 특성과 thispoint를 활용할 수 있는 경우를 설명할 수 있어야함

  • 포인터 ,객체 자신 포인터
  • 클래스의 멤버 함수 내에서만 사용
  • 각 객체 속의 this는 다른 객체의 this와 다름
  • this 가 필요한 경우
    • 매개변수의 이름과 멤버변수의 이름이 같은 경우
    • 멤버 함수가 객체 자신의 주소를 리턴할때
  • 제약사항
    • 멤버 함수가 아닌 함수에서 this사용 불가
    • static멤버함수에서 this사용 불가

동적 할당

필요한 양이 예측되지 않는 경우 . 프로그램 작성시 할당 받을 수 없음

실행중에 운영체제로부터 할당 받음

int *pInt - new int;

delete pInt;

int *p = new int[n];

delete[] p;

Circle *pArray = new Circle[3];

delete [] pArray;

5장

함수 인자 전달 방식 3가지 (참조변수 받는다)

  1. call by value
    • 호출하는 코드에서 넘어온 값이 매개 변수에 복사됨
    • 매개 변수 객체의 생성자는 호출되지 않음(호출되는 순간의 실인자 객체 상태를 매개변수객체에 그대로 전달하기 위함)
    • 함수종료되면 매개변수 객체의 소멸자 호출
  2. call by adress
    • 호출하는 코드에서 넘어온 주소 값이 매개 변수에 저장됨
    • 함수 호출시 객체의 주소만 전달
    • 생성자 소멸자가 실행되지 않는 구조
    • adress 주소에 해당되는 4바이트가 복사가 된다 (매게변수 입장에서는 공간을 할당한다)
  3. call by reference
    • 함수의 매개 변수를 참조 타입으로 선언
    • 이름만 생기고 공간이 생기지 않음
    • 실인자 변수 공간 공유
    • reference 매게변수 입장에서는 공간을 별도로 생성하지 않는다

참조변수를 활용하는 예(코드를 해석할줄알아야함)

  • 참조자 &의 도입
  • 이미 존재하는 변수에 대한 다른 이름(별명)을 선언
  • 참조 변수는 이름만 생기며 참조 변수에 새로운 공간을 할당하지 않는다
  • 초기화로 지정된 기존 변수를 공유한다
cout << "i" << '\t' << "n" << '\t' << "refn" << endl;
int i = 1;
int n = 2;
int &refn = n; // 참조 변수 refn 선언. refn은 n에 대한 별명
n = 4;
refn++; // refn=5, n=5
cout << i << '\t' << n << '\t' << refn << endl;
refn = i; // refn=1, n=1
refn++; // refn=2, n=2
cout << i << '\t' << n << '\t' << refn << endl;
int *p = &refn; // p는 n의 주소를 가짐
*p = 20; // refn=20, n=20
cout << i << '\t' << n << '\t' << refn << endl;

복사생성자에 대한 부분 얕은 복사생성자의 문제점과 해결방법을 설명할 줄 알아야함

얕은 복사 생성자를 쓰게 되면 사본은 원본 객체가 할당 받은 메모리를 공유하는 문제 발생한다, 그리고 같은 공간의 주소를 쓰기 때문에 소멸할 때 프로그램 비정상 종료됨

  • 해결방법에서는 복사생성자에 대한 코드를 작성할 줄 알아야함

      public:
      	    Person(int id, char *name); // 생성자
      	    ~Person();                  // 소멸자
      	    void changeName(char *name);
      	    void show() { cout << id << ',' << name << endl; }
      	};
      	Person::Person(int id, char *name)
      	{ // 생성자
      	    this->id = id;
      	    int len = strlen(name);         // name의 문자 개수
      	    this->name = new char[len + 1]; // name 문자열 공간 할당
      	    strcpy(this->name, name);       // name에 문자열 복사
      	}
      	Person::~Person()
      	{                      // 소멸자
      	    if (name)          // 만일 name에 동적 할당된 배열이 있으면
      	        delete[] name; // 동적 할당 메모리 소멸
      	}
      	void Person::changeName(char *name)
      	{ // 이름 변경
      	    if (strlen(name) > strlen(this->name))
      	        return;
      	    strcpy(this->name, name);
      	}
    
    • string으로 바꾸는법

      스트링클래스로해결할경우 소멸자를 만들필요가없다 자동으로 스트링 클래스는 소멸하기 때문에)(깊은복사가 필요없음 스트링 클래스로 할경우

        public:
            Person(int id, string name); // 생성자
            ~Person();                  // 소멸자
                  
            void changeName(string name);
            void show() { cout << id << ',' << name << endl; }
        };
        Person::Person(int id, string name)
        { // 생성자
            this->id = id;
            this->name =name;
        }
        Person::~Person(){}
        void Person::changeName(string name)
        { // 이름 변경
            this->name = name;
        }
      
    • 깊은 복사자로 바꾸는법

      복사생성자를 사용하여 해결할 경우는 객체배열을 하나 더 만들어서 해결함

        public:
            Person(int id, char *name); // 생성자
            Person(Person &person);     // 복사 생성자
            ~Person();                  // 소멸자
            void changeName(char *name);
            void show() { cout << id << ',' << name << endl; }
        };
        Person::Person(int id, char *name)
        { // 생성자
            this->id = id;
            int len = strlen(name);         // name의 문자 개수
            this->name = new char[len + 1]; // name 문자열 공간 할당
            strcpy(this->name, name);       // name에 문자열 복사
        }
        Person::Person(Person &person)
        {                                    // 복사 생성자
            this->id = person.id;            // id 값 복사
            int len = strlen(person.name);   // name의 문자 개수
            this->name = new char[len + 1];  // name을 위한 공간 할당
            strcpy(this->name, person.name); // name의 문자열 복사
            cout << "복사 생성자 실행. 원본 객체의 이름 " << this->name << endl;
        }
        Person::~Person()
        {                      // 소멸자
            if (name)          // 만일 name에 동적 할당된 배열이 있으면
                delete[] name; // 동적 할당 메모리 소멸
        }
        void Person::changeName(char *name)
        { // 이름 변경
            if (strlen(name) > strlen(this->name))
                return; // 현재 name에 할당된 메모리보다 긴 이름으로 바꿀 수 없다.
            strcpy(this->name, name);
        }
      

우리가 쓴 코드중에서 복사생성이 자동으로 발생하는 경우 3가지 형태 설명할수 있어야함

  1. 객체로 초기화하여 객체가 생성될 때. son 객체의 복사 생성자 호출
    • Person son = father;
  2. ‘값에 의한 호출’로 객체가 전달될 때. person 객체의 복사 생성자 호출
    • void f(Person person)
  3. 함수에서 객체를 리턴할 때 mother 객체의 복사본 생성. 복사본의 복사 생성자 호출
    • return mother;
void increase(Circle &c) {
int r = c.getRadius();
c.setRadius(r+1);
}
int main() {
Circle waffle(30);
increase(waffle);
cout << waffle.getRadius() << endl;
}

 
increase(waffle)  increase(&waffle) 바뀌면
 함수 Circle &c Circle *c  c.getRadis   cgetRadis()

6장

함수중복의 조건

동일한 이름의 함수가 공존

중복된 함수들의 매개 변수 타입이 다르거나 개수가 달라야함

리턴 타입은 함수 중복과 무관

디폴트 매개 변수를 사용하는 예를 코드로써 이해해야함

매개 변수에 값이 넘어오지 않는 경우 , 디폴트 값을 받도록 선언된 매개 변수

디폴트 매개 변수는 끝 쪽에 몰려 선언되어야 함

void star(int a=5); // a의 디폴트 값은 5

star(); // 매개 변수 a에 디폴트 값 5가 전달됨. star(5);와 동일

사례 1 
void msg(int id, string text="Hello"); // text의 디폴트 값은 "Hello"
msg(10); // id에 10, text에 “Hello” 전달
msg(); // 컴파일 오류. 첫 번째 매개 변수 id에 반드시 값을 전달하여야 함
msg("Hello"); // 컴파일 오류. 첫 번째 매개 변수 id에 값이 전달되지 않았음

사례 2
void calc(int a, int b=5, int c, int d=0); // 컴파일 오류
void sum(int a=0, int b, int c); // 컴파일 오류
void calc(int a, int b=5, int c=0, int d=0); // 컴파일 성공

사례 3
void square(int width=1, int height=1);
square( ); square( , ); square( 1, 1 );

square(5);square( 5, ); square( 5, 1 );

before)
public:
Circle() { radius = 1; }
Circle(int r) { radius = r; }
after)
Circle(int r=1) { radius = r; }

함수중복을 간소화하게 코드를 짤수 있어야함(디폴트 매개 변수 사용)

MyVector() {
p = new int [100];
size = 100;
}
MyVector(int n) {
p = new int [n];
size = n;
}

MyVector(int n=100) {
p = new int [n];
size = n;
}

함수 중복이 3가지 상황 일어나는 경우 코드를 설명할수 있어야함

  • 형변환으로 인한 모호성

      float square(float a) {
      return a*a;
      }
      double square(double a) {
      return a*a;
      }
      int main() {
      cout << square(3);
      int 타입 3
      double로 변환
      할지 float로 
      환할  모호함
    
  • 참조매개변수로 인한 모호성

      #include <iostream>
      using namespace std;
      int add(int a, int b) {
      return a + b;
      }
      int add(int a, int &b) {
      b = b + a;
      return b;
      }
      int main(){
      int s=10, t=20;
      cout << add(s, t); // 컴파일 오류
      }
        
      call by value인지
      call by reference인지 모호
    
  • 디폴트매개변수로 인한 모호성

      #include <iostream>
      #include <string>
      using namespace std;
      void msg(int id) {
      cout << id << endl;
      }
      void msg(int id, string s="") {
      cout << id << ":" << s << endl;
      }
      int main(){
      msg(5, "Good Morning"); // 정상 컴파일. 두 번째 msg() 호출
      msg(6); // 함수 호출 모호. 컴파일 오류
      }
      디폴트 매개 
      수를 이용하고
      있는지 모호함
    

static 맴버 , 인스턴스 멤버의 차이점을 설명할 수 있어야함(메모리 공간 측면, 사이클)

  • static 멤버
    • 프로그램이 시작할 때 생성
    • 클래스 당 하나만 생성, 클래스 멤버라고 불림
    • 클래스의 모든 인스턴스(객체)들이 공유하는 멤버
  • non-static 멤버
    • 객체가 생성될 때 함께 생성
    • 객체마다 객체 내에 생성
    • 인스턴스 멤버라고 불림

태그:

카테고리:

업데이트: