승쨩개발공부
[C++] OOP(객체지향) 정리 본문
프로그래밍이란?
-> 어떠한 문제에 목적을 가지고 프로그래밍 언어(도구)를 이용하여 순차적으로 무언가를 짜는 것.
-> (도구 = 알고리즘, 자료구조 등)
-> 알고리즘이란?
-> 어떤 문제에 대해서 효율적인(빠른) 해결 방법이 목적이다
-> (컴퓨터가 조금이라도 쉴 수 있게(연산을 적게) 효율적으로 하는 것 (문제 -> 과정 -> 결과) )
-> 자료구조란?
-> 데이터를 기준으로 어떻게 관리하는가?
1. OOP(Object Oriented Programming)의 기본개념과 객체에 대해 기술.
-> 모든 데이터를 객체로 취급해서 하는 프로그래밍, 객체는 독립적으로도 동작하고
다른 객체의 부품으로 사용할수 있다.
-> 객체는 실체화되어있으며, 데이터나 기능으로 이루어져있다, 또 한, 자기 자신(객체)이 독립적으로도 동작하고 다른 객체에 부품으로 사용할 수 있다.
(ex) 변수(메모리 공간 어딘가에 구체화,실체화)
여기서, 중요한 것은 데이터 둘다 있을 수 있고, 하나만 있거나 둘다 없을 수도 있다.
2. 클래스 정의 및 특성에 대해 기술.
-> 클래스는 데이터와 동작(기능)으로 이루어진 하나의 사용자가 정의한 자료형이다.
-> 또한, 실체화 되지 않았으며, (즉 , 클래스 자체가 객체라고 할 수 없다. )
-> 실체화 되면 그 자료형 (클래스 안에 용량) 에 따라 메모리 공간이 잡힌다.
클래스의 특성
1. 다형성 : 부모의 공통된 인터페이스나 공통된 성질만 유지된다면, 여러 개로 변환할 수 있다.
하나의 클래스가 다양하게 쓰이는것.
-> 같은 메소드를 호출할 떄 실제 수행되는 내용은 객체가 무엇이냐에 따라 달라지는 개념
2. 은닉화 : 숨기는 것, 정보은닉 (외부에 정보를 보여주지도 말고, 볼려고도 하지 말자)
3. 재사용성 : 다른 객체에 부품으로 사용하거나, 상속을 통해 사용하던지, 재사용하는 것.
4. 추상화 : 어떠한 추상적인 개념을 효율적으로 구체화 시키는 것
5. 상속 : 부모 - 자식 의 계층 구조로 되어 있으며, 부모의 성질을 그대로 물려 받아서 사용하는 것
6. 캡슐화 : 외부와 공개할 정보는 공개(인터페이스)하고 공개하지 않을 정보를 숨기는 것
-> 비슷한 기능들을 묶는것
-> 클래스의 여러 기능을 객체라고 하는 하나의 집합으로 묶는 것을 캡슐화라고 한다.
3. 인터페이스란?
-> 외부와 약속된 접촉면 (혹은 접점) 다른 말로는 외부에 공개되어 있는 부분
4. 인스턴스란?
-> 메모리 공간에 무언가 (객체)를 구체화, 실체화 하는 것
클래스 안에 인스턴스란?
ex) class Obj {} 가 있다.
Obj a;
Obj b; ...
위와 같은 객체들은 Obj 클래스에 인스턴스라고 한다. ( 클래스로 부터 메모리가 잡혀있는 것)
하지만 같은 객체라고 볼 수 없다.
(왜? 같은 메모리 주소가 아닌 각자만의 메모리 주소를 가지고 있기떄문)
5. 접근권한 지정자의 종류를 나열하고 각각을 설명하라
- public : 모든 위치에서 접근 허용, 외부에서 수행할 맴버 함수의 경우 (외부에서 접근 가능)
- private : 같은 클래스 맴버만 접근하용, 멤버 변수와 내부 처리하는 경우 (외부에서 접근 불가능)
- protected : 외부에서 접근 불가능하지만 상속 되어진 자식 클래스에서 접근 가능
Tip. : private 에서도 접근 가능하는게 있는데, 바로 friend 키워드를 사용하는 것과
private를 사용한 클래스 타입과 같은 타입의 객체를 인자로 받거나 대입할 경우
private: 안에있는 멤버 변수에 값이 들어간다.
6. 인스턴스와 객체의 차이점
-> 객체란 물건 (클래스나 구조체로 만들어진 것들),
클래스는 자료형의 타입이고 아직 메모리가 잡혀져 있지 않은 상태이기 떄문에,
인스턴스가 좀 더 포괄적인 개념이고 객체는 그 안에 포함되어 있는 개념이다.
-> 인스턴스화가 일어날 떄 내부의 멤버들이 인스턴스 되고 그 뒤에 객체가 생성되고 이러한 것을
인스턴스라고 부를 수도 있다. 그래서, 하나의 클래스 안에서는 여러 개의 인스턴스를 가질 수 있다.
-> 객체는 인스턴스 없이 생성될 수 없다.
클래스만 쓴다고 메모리가 할당 받는다고 할 수 없다. (따라서, 인스턴스화 해야 한다.)
7. 생성자란?
-> 클래스가 인스턴스될 떄(생성될 떄) 호출되는 함수이다, (즉, 메모리가 잡히는 직후)
-> 클래스와 동일한 이름을 가지고 시스템 내부에서 호출해주는 자동 함수이다.
-> 생성자를 따로 안적어도 컴파일러가 친절하게 디폴트 생성자를 만들어준다.
-> 반환값이 없고, 오버로딩이 가능하다. (그래서, virtual 키워드가 필요없다.)
-> 객체 생성 시 하나 이상의 생성자가 존재한다면 디폴트 생성자가 호출되지 않는다. 리턴 값이 없다.
(인자가 있는 생성자는 목적이 명확하기 떄문에 디폴트 생성자를 만들어주지 않는다.)
정리 : 클래스 명과 동일, 오버로딩이 가능, 상속은 안됨, 반환값이 없다, 객체가 인스턴스 될 떄,
딱 한번 자동으로 호출된다.
8. 소멸자란?
-> 클래스가 소멸될 떄 (메모리가 소멸되기 직전) 실행되는 함수로써
클래스와 동일한 이름 앞에 ~를 붙여준다, 오버로딩이 되지 않는다.
-> 부모 - 자식 관계에서 자식은 부모에 접근이 가능하다.
-> 그래서 부모부터 소멸시키면 자식이 부모에 참조하고 있으면 문제가 생기게 된다.
-> 그래서 자식부터 소멸시킨다. (생성은 부모, 자식 순으로 생성되고, 소멸은 자식, 부모 순으로 소멸한다.)
정리 : 클래스 명과 같되, 앞쪽에 ~ 를 붙임, 상속이 안됨, 반환값이 없다,
매개변수가 없으므로 오버로딩이 불가능
9. 복사생성자란?
-> 일반적으로 객체를 생성해서 복사할 떄 호출되는 함수이다.
-> 인자가 있다. (인자값을 레퍼런스로 꼭 하자!!!)
(쓸모없는 복사를 하지말라고 포인터나 레퍼런스로 전달한다) (객체)
복사생성자 호출시점
1. 객체를 복사해서 생성할 떄
-> ex) class CObj {} 클래스가 있다.
CObj Obj1;
CObj Obj2 = Obj1; <- 이 시점에서 복사 생성자 호출
2. Call by Value (값의 전달 형태) 로 객체를 전달시킬 떄
-> 포인터나 레퍼런스로 전달하지 않는다면 임의로 같은 타입의 다른 객체를 만들어서 넣어버린다
(메모리 낭비)
3. 임시 객체로 반환할 떄
-> 반환할 떄 복사 (값을 임시로 저장) 하고 반환한다.
(왜? 함수도 지역이기 떄문에 연산이 끝난 후 값이 사라지기 떄문에 임의로 저장해야한다)
10. 클래스에서 기본적으로 제공되는 것들을 모두 나열
-> 디폴트 생성자, 디폴트 소멸자, 복사생성자, 대입연산자, 캐스팅 연산자, this 포인터
11. vitual이란?
-> 클래스에서 다형성을 위한 키워드로써 가상함수를 만들기 위함이다.
-> 오버라이딩에도 쓰이고, 1개 이상 사용시 4바이트의 가상 함수 테이블을 만들게 된다.
-> 상속구조에서 접근할 경우 가상 함수 테이블을 이용하여 접근하여 이동한다.
-> 상속구조에서 소멸자에 virtual 키워드를 붙여줘야한다.
-> 만약 없다면, 소멸자를 호출하지 않을 경우가 생긴다.
-> memset을 사용하게 되면 가상함수테이블을 지워버리기 떄문에 문제가 된다.
정리 : virtual은 OOP에 중요한 다형성을 이루게해준다
12. 가상함수란?
-> virtual 키워드가 붙어 만들어지는 함수로써 프로그램 실행에서 누구의 멤버 함수를 싱행할 것인지를
결정하는 동적 바인딩에 사용
-> 반드시 재정의할 필요는 없다.
(강제성이 없다. 재정의를 하면 자신의 함수로 쓰고, 자신의 정의가 없으면 부모 함수를 사용한다.)
-> 기능을 확장하거나 다른 기능으로 사용한다.
동적 바인딩 : 프로그램이 싱행하는 도중에 메모리를 할당받는 것
13. 순수 가상함수란?
-> 자식에서 반드시 재정의 해야 하는 가상함수 (강제성)
-> 상속에서 부모에서 vitual void Func () = 0; 의 행태를 가지는 함수이다.
-> 순수 가상함수를 가지는 class는 추상 클래스 (순수 가상 클래스)가 된다.
(추상 클래스가 되면 컴파일러가 실제 존재하는 코드가 아니라고 판단하기에 인스턴스화 할 수 없다)
-> 공통적인 인터페이스를 지원하기 위한 함수 (사용하는 주 목적)
14. 함수 오버로딩 과 함수 오버라이딩을 각각 설명하고 차이점을 설명하라.
-> 함수 오버로딩은 반환 값에 상관없이 함수의 이름은 같고 매개변수가 다르고 기능이 다른 함수
(같은 이름에 다른 기능을 하는 함수)
-> 함수 오버라이딩은 상위 클래스에서 선언된 반환 형태, 함수이름, 매개변수가 모두 같아야 되고
부모 - 자식간의 관계일 경우 재정의해야한다.
(상위(부모)클래스에서 선언된 함수에 virtual 키워드가 붙어야 한다.)
(상속 관계간에 발생하며, 부모클래스의 내용이 보이지않고, 자식클래스에서 재정의하여 기능을 하는 함수)
(다형성과 관계 있음, 같은 메소드를 호출할 떄 실제 수행되는 내용은 객체가 무엇이냐에 따라 달라지는 개념)
15. 추상화란?
-> 공통된 특성을 모아서 효율적으로 관리하기 위해서 구조나 설계를 일반화시키는 작업을 일컷는다.
(객체의 효율적이고도 안전한 사용을 위해 인터페이스를 설계하는 것)
-> 쉽게 말해, 어떤 추상적인 개념을 효율적으로 구체화 시키는 것.
-> 설계와 밀접한 관계가 있다.
16. this포인터에 대해 기술하고 사용하는 이유를 설명하시오
-> 함수는 자신을 호출한 객체의 번지를 인수로 전달받는 데,
이떄 전달받은 숨겨진 인수를 this 포인터 라고 한다.
-> 호출한 객체의 번지를 가리키는 상수 포인터 이다.
-> 일반적인 클래스형 맴버 함수들은 this로부터 객체의 고유한 멤버에 접근할 수 있다.
-> 멤버 변수와 지역 변수명이 같을 떄 구분을 위해 사용한다.
멤버 함수가 객체를 칭할 필요가 있을 떄 this를 직접 사용되고
그리고 객체가 자신을 스스로 삭제하고자 할 경우도 this를 사용한다
17. friend?
-> 엑세스 저장자는 숨기면 정상적인 문법으로는 외부에서 멤버를 참조할 수 없어서 예외적으로
지정한 대상에 대해서는 모든 멤버를 공개할수 있도록 해준다.
-> 맴버속성에 관계없이 모든 멤버변수에 접근할 수 있으며, 전이 되지 않고, 동시에 여러 클래스를
friend로 지정할 수 있다. 상속되지 않는다.
-> friend의 이러한 특징은 은닉성을 무너뜨린다 (접근제어 무시)
18. 연산자 오버로딩?
-> 오버로딩은 같은 이름이 다른 기능을 하는것 (new도 오버로딩을 할 수 있다)
-> 대입연산자 이외에는 지원해주지 않는다. 그래서 연산자를 추가하기 위해서 추가하는 것. (객체간의)
-> C++에서 연산자가 하는 일을 필요에 맞게 함수로 구현한 것이며,
객체간의 연산은 일반적인 연산자로는 불가능해 연산자 오버로딩을 정의하여 사용한다.
19. 얕은복사와 깊은복사를 기술후 사용하는 이유를 설명
-> 얕은 복사는 클래스를 복사하는 것을 얕은 복사라고 부른다.(일반적으로 대입 연산자 사용시 얕은 복사)
-> 깊은 복사는 객체간 복사에 있어 동적할당(힙영역)이 있을 경우 그 영역을 새로 설장하여 힙 영역간에도
복사가 이루어져 독립된 동적할당 영역을 유지하는 것
자세히 애기하자면
-> 얕은 복사란 [따로 정의하지 않은 경우] 디폴트 복사 생성자가 컴파일러에 의해 자동 호출되고
이 디폴트 복사 생성자는 멤버간의 1:1 복사를 하게 되느넫 주소만을 복사하게 된다.
만약 동적할당된 메모리를 복사하려고 할 떄 얕은 복사를 할 경우 힙 영역의 메모리를 두 객체가
가르키게 되며, 두 객체는 독립성을 잃고 해제할 떄 문제가 생기게 된다. 이미 해제된 메모리를
다시 해제하려해서 실행 중 에러가 발생하게된다.
이러한 동적 메모리 할당된 곳을 복사하기 위해 깊은 복사가 필요하며, 깊은 복사란 동적 할당된 메모리
주소가 아닌 다른 메모리를 동적 할당하여 두 객체에 완전한 독립성을 갖도록 사용자가 정의한 복사
생성자 함수를 일컷는다.
쉽게 애기하자면
-> 얕은 복사는 주소를 참조하고 있는 것이고. (실제 데이터를 복사해온 것이 아니라)
원본의 주소값이 바뀌게 된다면, 오류가 발생하거나 원하지 않는 값을 얻을 수 있다.
이러한 문제를 방지하기 위해 실제 데이터의 값을 복사하는 깊은 복사를 해야한다.
20. 오퍼레이터?
-> 연산자 오버로딩을 하기 위한 키워드
-> 연산자를 함수의 형태로 오버로딩하기 떄문에 재정의된 연산자를 연산자 함수라고도 한다.
21. 멤버 이니셜 라이져
-> 생성자가 실행되기 바로 직전에, 멤버들이 메모리 공간에 바로 잡히고 바로 값을 넣어준다. (초기화)
-> const 멤버변수, 레퍼런스 변수, 부모의 생성자에서 원하는 값이 있을 떄 (부모의 멤버변수)
-> 선언시 초기화 해줘야하는 것은 멤버 이니셜 라이져라고 생각하면 된다.
22. 클래스에서 static?
-> 공용변수, 공용함수 (중요)
-> 선언은 한번만 할 수 있고, 프로그램 시작시 생성되고 프로그램 종료시 소멸된다.
-> 객체는 아직 생성되지 않았는데, static은 생성이 되어있어서 선언없이 사용할 수 있으며
static 함수명 (static이 함수에 붙었을떄)로 사용하면 this포인터 사용불가, 멤버변수 사용불가,
static 변수는 사용가능
<클래스 소속이지만, 객체는 아니다.>
정적 함수에서는 비정적 멤버는 접근할 수 없다, 왜? 비정적 멤버가 생성되었는지 안되었는지 모르기 떄문
ex) class CObj {}; 에 static int m_iA = 0; 멤버 변수가 있다.
CObj() { m_iA++; } 생성자 함수에서 증가시키게 한 다음 객체를 막 생성하면 static 변수 값이
증가하면서 값이 저장된다.
즉, CObj 타입으로 선언된 객체들이 공통적으로 접근 가능하게 되버린다.
23. 포인터와 레퍼런스
-> 포인터는 어떤 변수의 주소값을 가진 변수를 말하는 것.
-> 레퍼런스는 어떤 변수의 또 다른 이름(혹은 별명)을 말하는 것.
-> 포인터는 가리키는 대상을 변경할 수 있지만, 레퍼런스는 변경할 수 없다.
24. 구조체와 클래스 차이
-> 구조체와 클래스의 차이는 디폴트 접근제어 지시자가 다르다.
-> 구조체는 public이며, 클래스는 private이다.
-> 구조체의 설계 목적은 관리이므로 public이고 클래스는 데이터와 기능을 묶은 것.
25. 정적 변수와 전역 변수의 만들어지는 시점
-> 정적 변수는 프로그램 시작시 메모리를 할당 받는다.
-> 전역 변수는 프로그램이 시작하고 전역변수를 만났을 떄 할당 받는다.
'C++' 카테고리의 다른 글
[C++] CallbyValue, CallbyAdress, CallbyReference (0) | 2022.01.04 |
---|---|
[C++] 난수(rand/srand) (0) | 2021.12.15 |
[C++] 지역변수 / 전역변수 / 정적변수(static) (0) | 2021.12.14 |
[C++] 진수 (0) | 2021.12.14 |
[C++] 템플릿 (0) | 2021.12.07 |