객체 지향
포인터, 구조체, 추상화, 상속, 다형성
함수 포인터
- 함수 명 앞에 *를 붙이면 됨. (쉽죠?)
int Plus(int a){
return a;
}
int Minus(int a, int b){
return a-b;
}
int main{
int a = 20;
int b = 20;
int (*functionPointer)(int pa, int pb);
functionPointer = Plus; //분신이 됨. call by reference
int result = functionPointer(a, b);
}
함수 포인터 사용 이유
- 주솟값으로 관리하면 새로운 값을 메모리에 올려서 ~ 이게 아니라 걍 거기 있는 걸 가리키니까 확장하기도 편하고 관리하기도 편함. 추가 메모리도 필요도 없구.. 기능 추가해도 컴파일도 다시 안해도 되고 …
구조체, 공용체, 열거형 (내가 만든 데이터 타입)
구조체
- 하나 이상의 서로 다른 종류의 변수들을 묶어서 새로운
데이터 타입
을 정의 하는 것. - 클래스도 구조체를 기반. 따라서 본질은 둘 다 새로운
데이터 타입
이라는 것. - 왜 사용해?
- 연관된 변수들을 싸악 묶어서 관리해가지고 관리하기 편하라고 …
- 학생 한 명을 그룹으로 지정하고 이름, 나이, 성별 등의 정보를 그룹으로 묶는 게 편하다.
struct student { //구조체 이름
char name[10];
int age;
int height; //구조체 멤버들
};
st1이라는 구조체 변수
라면
다음과 같은 변수가 생성된다.
st.name 으로 접근할 수 있다.
공용체
- 사용자 정의 자료형
- 구조체와 달리 메모리 공간을
공유
한다. - ts에도 나온다..!!
union unTemp
{
char a;
int b;
double c;
}
열거형
- 데이터들을 열거한 집합 (연속된 데이터를 주로 묶음)
enum Week
{
sun = 0,
mon,
tue,
sed,
thu,
fir,
sat
};
첫번째 멤버를 0으로 설정하면 다음 멤버는 1, 그 다음은 2로 1씩 증가한다.
동적 메모리 할당
메모리 구조
- 메모리 영역
- 코드 영역- 실행할
명령어
들이 순서대로 쌓임.CPU
가 코드 영역에서 명령어를 하나씩 가져다가 처리함. - 스택 영역- 나중에 들어온게 먼저 나감. 지역 변수, 매개 변수들이 다 사용하는 영역.
- 힙 영역 - 컴퓨터 메모리의 일부가 할당 됐다가 회수되었다가 반복반복…(동적 메모리)
실행 시
사용자로부터 할당 메모리를 입력 받음. <javascript
가 주로 활용하는 영역> - 데이터 영역 - 전역 변수, static 변수가 저장되는 공가능로 프로그램
종료
시에 소멸된다.
- 코드 영역- 실행할
동적 메모리 할당 이유
- 사람수를 100명이라고 했는데 30명이 더 늘었다면..? 얼래? 유동적이니까 실행 시에 걍 결정하자.
동적 메모리 할당 (C)
- void *malloc (size_t size); 전달인자 size는 바이트 단위로 입력하고 할당 되면 메모리의 주솟값을 리턴한다.
- void* 라는건, void는 타입 지정 x, *는 포인터. 즉 타입이 지정되지 않은 포인터.
-
객체 기반에서 new 연산자를 사용하면, 객체 생성의 메모리 구조는 동적메모리와 같다.
- C, C++ 같은 경우 동적으로 메모리할당을 하면 꼭 해제해줘야함. 그러나 framework 기반의 java, javascript는 알아서 가비지 컬렉터가 처리해준다.
객체 지향 철학
객체 지향
- 사물을 향한다. (사물=되게 추상적. 뭐를 떠올려야 하지? )
구조적 프로그래밍 vs 객체 지향 프로그래밍
구조적 프로그래밍 - 순차적, 건물짓기, 기능 기본 단위는 함수.
- 설계를 완벽하게 해야 함.
- 다시 무르기 어려움. 변경 불가. (커스터머의 요구가 바뀔수도..)
객체 지향 프로그래밍 - 기능 기본 단위는 객체
- 중간중간 변경, 반영 가능. 분리가 쉬움.
- 조립식 건물 같음. 중간에 에러나면 그 객체(부위)만 바꾸면 됨.
추상화(대상의 공통된 특성을 뽑아낸 것)
대상에서 특징만을 뽑아냄. 일상 사물은 관념적이고 추상적이다.
캡슐화 (추상화 된 결과를 외부로부터 보호하는 것)
- 은닉, 숨기다. 즉 외부에서 내부를 볼 수 없게 한다. 그러나 숨기기만 하면 데이터는 쓸모가 없다.
- 내부를 보지 못하기에 외부로부터 데이터를 조작할 인터페이스가 필요하다.
- 캡슐화: 클래스 = 데이터(은닉) + 메소드(인터페이스, 출입 가능) (구조체 base이므로 사용자 정의 타입이다.)
class
: 사용자 정의 데이터타입
사용자가 데이터와 메소드를 새로 정의한 데이터 타입! 즉 본질은 Data Type이라는 것이다. like 구조체. 멤버 변수와 멤버 함수(메소드)로 구성된다.
추상화는 공통 특성을 정리하는 것이고, 캡슐화는 추상화된 결과를 하나의 클래스에 포함시킨 뒤, 그걸 보호하게 끔 만드는 것이다.
- clsas에서 상태(변수), 행동(메소드)
- 클래스 선언 형식
- public : 누구나 접근 가능
- protected: 상속 관계시, 상속 받은 자식 클래스에서만 접근 가능
- internal: 같은 프로젝트(어셈블리) 내의 모든 클래스 접근 가능
- private: 외부 접근 불가.
객체
: 클래스를 통해 선언한 변수
클래스의 본질은 데이터 타입이므로, 새로운 변수를 선언했을 때의 그 변수의 타입일 뿐이다.
동적 메모리를 할당받는다(new 연산자). 런타임에 heap 메모리를 할당 받아서, 주솟값을 stack 영역(4byte)에 담는다. (a에 담는다. a는 포인터변수)
생성자
모든 변수는 선언이 되면 초기화 해야 함. 객체도 본질적으로 변수이기에 선언되면 초기화 해야 한다.
따라서 객체 생성 시, 초기화 함수를 써야 하는데 이것이 class에서 제공하는 생성자이다.
- 생성자는 객체 생성 시 자동으로 호출되는 메소드이다.
상속성
완성된 클래스를 다른 클래스에 상속할 수 있음.
부모 클래스로부터 상속을 받을 때는 클래스 이름 끝에 콜론,javascript는 extends
를 붙인다.
접근지정자 클래스이름 extends 부모클래스이름
- B프로젝트가 A프로젝트 기능과 유사하다면, A클래스를 상속받고 추가 기능만 구현하면 된다.
다형성
함수는 이름이 같더라도 전달 인자 타입, 개수에 따라 구분이 된다. (다른 그림 찾기처럼 얼핏보면 같은데 얼핏보면 다른 것)
C언어는 함수 이름이 같으면 중복되는 건데, 객체지향에서는 (javascript등) 이름이 같아도 인자 타입이 다르거나 개수가 다르면 다른 함수이다.
1. overloading (겉모습은 같아도 내용이 다름)
: 이름이 같아도 전달인자 타입, 개수가 다른
경우. (적재하다)
같은 개수의 전달 인자가 서로 다른 타입으로 존재하는 경우
- 오버로드라는 유닛이 있음. 오버로드는 다른 유닛을 태워서 다니는 열기구(수송기)이다. 저그는 저글링, 히드라, 럴커 3 유닛으로 나뉜다. 각 오버로드에 다 다른 유닛들이 타고 있으므로 각 오버로드는 오버로드지만 구분된다. OR 다 저글링이 타고 4,5,6마리 타면 다 다른 오버로드이다.
2. overriding(올라타서 기존 것을 덮어버린다)
: 상속 개념이 기반. 재정의 한다. 기존의 것을 리뉴얼, 재정의
class Pudle():Dog{
public Puble(){
base.eyes = 2;
Console.WriteLine("푸들 눈: {0}", eyes);
}
public override void bark(){
Console.WriteLine("왈왈")
}
}
위 코드는 Dog를 재정의 한 것.
Dog dog = new Dog(); dog는 Dog타입
dock.bark();//왈왈
Pudle pd = new Pudle();
pd.bark();//컹컹
dog = new Pudle(); //부모 Dog타입인 dog에 Pudle을 쓸 수 있음.
dog.bark();//왈왈
인터페이스
: 메소드 목록만
가지고 있는 사용자 타입. 선언만 하고 구현하지 않기에 꼭 상속하고 써야한다.
interface Snack(){
sort : string //변수interface Snack(){sort : string //변수
getSort():void
}
class Nacho implements Snack {
}
-
왜 써요?
- 보통 class 상속은 기존 기능을 추가 or 수정하기 위함.
- interface는 동일한 개념의 기능을 새롭게 구현하기 위함임. 즉, 공동 작업에서 표준이 된다 (명세 작성)
-
추상 클래스를 상속하는 이유
- for
기능 확장
을 위해
- for
- 인터페이스를 상속(구현)하는 이유
-
- for 여러
기능을 나열
하기 위해 - interface에서 기능을 명세하고 자식 클래스에서 상속한다.
- for 여러
-
- 메모리 관리
-
- 객체 지향 언어(플랫폼 기반)는 가비지 컬렉터가 자동 관리.
- new로 heap에 동적 메모리가 할당 된다면, 사용하지 않으면 가비지 컬렉터가 알아서 회수한다.
그러나 반복하게 되면 빈공간이 발생하는데 이를
단편화 현상
이라고 한다. 가비지 컬렉터는 이 빈 공간을 최대한 줄이기 위해컴팩션
을 진행한다.
-
람다
: JavaScript의 익명 함수와 화살표 함수의 원리.
function () { //익명함수
}
const func = function() { } //보통 이렇게 많이 쓴다
const func_lamda = () => { }//람다함수
- 왜 익명 함수를 사용하는가 ?
- callback함수는 미리 등록 한 걸 event 때에만 부르므로, 익명이어도 상관 없음. 즉 event에만 연결되면 됨.
- 코드가 간결해지고 별도 메소드를 만들지 않아도 되니 코딩 오버헤드를 줄일 수 있다. 대신 익명 메소드는 내용이 복잡하면 안되며 람다식에서 사용된다.
-
- 람다식: 기존 익명 메소드를 더욱 간결하게 만든다.
- for 코드를 짧고 간결하게 표현하기 위함.
let lamdaEx = () => {};
-