지난 시간에 이어서 프로그래밍의 기본 원리를 마무리해 볼게요.
기존 포인터 변수가 변수의 메모리 주소를 저장했던 것처럼, 함수의 주소를 받아서 사용하는 것을 함수 포인터라고 해요.
int Plus(int a, int b) {
return a + b;
}
int main() {
int a = 20;
int b = 10;
int (*fPtr)(int pa, int pb);
fPtr = Plus;
int result = fPtr(a,b);
printf("결과값 : %d", result); // 결과값 : 30
return 0;
}
위 코드를 보면 함수 포인터를 사용해서 함수를 호출하는 것을 볼 수 있어요. 함수 포인터를 사용하면 프로그램에 유연한 확장성을 제공할 수 있어요. 자바스크립트에서 함수를 일급 객체로 다루는 것과 비슷한 원리예요.
구조체는 하나 이상의 서로 다른 종류의 변수들을 묶어서 새로운 데이터 타입을 정의하는 문법이에요. 새로운 기준을 만들어 연관된 변수들을 하나의 타입으로 관리하기 유용해요.
공용체도 구조체와 유사하게 새로운 데이터 타입을 정의해요. 하지만 내부 변수들이 동일한 메모리 공간을 공유한다는 점이 구조체와의 가장 큰 차이점이에요.
열거형은 데이터들을 나열한 집합이에요. 구조체와 비슷하게 데이터를 묶어서 사용하지만, 요일처럼 연속적인 성격을 가진 데이터를 나타낼 때 주로 사용해요. 또한 열거형 멤버를 정수형 상수로 취급한다는 특징이 있어요.
동적 메모리 할당은 new 연산자 등을 통해 객체를 생성할 때 사용되는 개념이에요. 메모리 구조 중 힙 영역을 런타임 시에 필요한 만큼 할당받아 사용하는 방식이에요. 가비지 컬렉터가 없는 언어에서는 메모리 누수를 막기 위해 사용이 끝난 메모리 공간을 직접 해제해 주어야 해요.
메모리 관리를 하다 보면 중간에 사용되지 않는 빈 공간이 발생하는 단편화 현상이 생기기도 하는데, 이를 모아서 해결해 주는 컴팩션(Compaction)이라는 기능도 존재해요.
구조적 프로그래밍은 함수 단위로 순차적으로 동작하기 때문에 중간에 문제가 생기면 수정이 어려웠어요. 이를 보완하기 위해 객체 단위로 기능을 나누어 유연하게 설계하고 수정할 수 있는 객체 지향 프로그래밍이 등장했어요.
추상화
대상에서 핵심적인 특징만 뽑아내는 것을 의미해요. 구체적인 사물보다 일반적인 개념을 모델링하는 과정이에요.
캡슐화
알약처럼 외부에서 내부 구현을 볼 수 없게 데이터를 은닉하는 것을 의미해요. 무조건 숨기는 것이 아니라, 외부에서 접근 가능한 적절한 통로를 제공하는 것이 중요해요.
상속성
중복을 줄이기 위해 부모 클래스의 필드와 메서드를 자식 클래스에서 물려받아 사용하는 것을 의미해요. 부모 클래스 타입의 변수에는 자식 객체를 할당할 수 있지만, 반대로 자식 클래스 타입의 변수에는 부모 객체를 할당할 수 없어요.
다형성
클래스는 사물의 특징을 필드와 메서드로 추상화하고 캡슐화하여 개발자가 새로 정의한 데이터 타입이에요. new 연산자를 사용해 객체를 생성해서 사용해요.
class 이름 {
public 생성자() {}
접근지정자 자료형 변수명;
접근지정자 반환자료형 함수명() {}
}
접근 지정자
public : 누구나 접근 가능해요.protected : 상속 관계에 있는 자식 클래스만 접근 가능해요.private : 클래스 내부에서만 접근 가능해요.생성자 (Constructor)
클래스를 초기화하기 위해 내부에 작성되는 메서드예요. 객체가 생성될 때 자동으로 호출돼요.
인터페이스는 실제 구현 없이 메서드의 목록(명세)만 가지고 있는 사용자 정의 타입이에요. 표준을 정하는 역할을 하며, 실제 구현은 인터페이스를 상속받은 클래스에서 담당해요. 여러 기능을 명세하기 위해 언어에 따라 다중 상속을 지원하기도 해요.
접근지정자 interface 이름 {
접근지정자 반환자료형 함수명();
}
람다식은 익명 메서드를 더 간단하게 표현한 식이에요. 자바스크립트의 화살표 함수와 비슷한 역할을 해요.
이름이 없는 익명 메서드를 사용하면 코드가 간결해지고 함수 생성에 따른 오버헤드를 줄일 수 있어요. 하지만 가독성을 위해 너무 복잡하거나 중요한 로직에는 사용을 지양하는 것이 좋아요.