개체지향 프로그래밍(OOP: Object-Orieted Programming)
JAVA vs C++
JAVA
- 클래스
- 개체
- 생성자
- 함수 오버로딩
- 힙에 개체 생성하기
C++
- 클래스
- 개체
- 생성자
- 함수 오버로딩
- 힙에 개체 생성하기
- 스택에 개체 생성하기
- 복사 생성자
- 소멸자
- 연산자 오버로딩
C++ 에서는 OOP 와 OOP 가 아닌 것을 섞어 쓸 수 있음 (C 와의 호환성)
C++ 은 언매니지드 언어이기 때문에 매니지드언어인 JAVA 에 없는 특별한 기능이 많음
OOP 란 뭘까?
- '사람들이 세상을 바라보는 방식' <= OOP 의 핵심
- 직관적
다음 이미지는 '사람' 을 예시로 들 때, 사람이 가지는 데이터나 행위에 대해 예를 든 것이다
위 예시를 아래처럼 코드화하는 것이 OOP 의 방식이다.
// JAVA 클래스
public class Human
{
private string name;
private sex;
private age;
public void eat();
public void walk();
public void talk();
}
Human student = new Human();
Human teacher = new Human();
복잡하게 구현된 OOP
- 닷컴버블 시절
- 일부 객체지향 분석과 디자인(OOAD)
- 일부 디자인 패턴들
예) 개체 A 가 개체 B 를 통해 숫자를 증가시키는 과정
해당 방식은 오브젝트를 직접 수정하는 것이 아닌 오브젝트가 포함된 다른 오브젝트를 만듬으로써,
오브젝트의 크기를 계속 키우는 방식을 사용함
(오브젝트를 직접 수정하는 것이 오류를 더 많이 발생할 것이라는 생각에 기초)
위를 직관적 OOP 로 수정한다면
이렇게 간단하게 구성할 수 있다.
접근제어자(Access Modifier)
클래스(class)
Vector 클래스 구상해보기(JAVA 코드 활용)
// JAVA
public class Vector
{
int x; // this 를 통해 멤버 변수 사용
int y;
}
------------------------------------------
// C++ (위의 JAVA 코드를 그대로 가져왔을 경우의 코드)
class Vector
{
int mX; // 최근 멤버의 m 을 붙혀서 변수를 사용하는 쪽으로 지향
int mY;
};
// 이런 코드 스타일은 권장하지 않음 (멤버 변수 내용 제외)
멤버 변수의 접근
C++ 의 기본 접근 권한은 'Private'
class Vector
{
int mX; // private
int mY; // private
};
자바에선 접근권한 제어 키워드를 생략하면 public 도 private 도 아닌 상태가 됨
- 해당 변수는 패키지 내에서 접근가능
- 오브젝트를 다른 곳에서 마음대로 접근 가능
- C++ 의 fried 기능처럼 사용하려고?
접근제어자
- public
- 누구나 접근 가능
- protected
- 자식 클래스에서 접근 가능
- private
- 해당 클래스에서만 접근 가능(개체에서가 아님, 클래스 단위)
보통 제어자별로 C++ 멤버들을 그룹 지어서 프로그래밍함
class SomeClass
{
public:
int PubliMember;
protected:
int mProtectedMember;
private:
int mPrivateMember1;
int mPrivateMember2;
};
개체 생성(오브젝트 인스턴스 생성)
// C++
// 스택 메모리에 만들기 (빠름)
Vector a;
// 힙 메모리에 만들기 (느림)
Vector *b = new bector();
-------------------------------------------------
// JAVA
// 스택 메모리에 만들 수 없음
// 힙 메모리에 만들기 (느림)
Vector a = new Vector();
Vector a 의 구조
- 스택에 메모리 할당
- int x, y (4바이트씩 총 8바이트 멤버 크기 보유)
Vector *b = new Vector() 의 구조
- 힙에 메모리 할당
스택(Stack)
- 예약된 로컬 메모리 공간(작음, 일반적으로 1MB 이하) - 컴파일 과정에서 확인 후 할당
- 함수 호출과 반환이 이 메모리에서 일어남
- 단순히 스택 포인터를 옮김
- 메모리를 할당 및 해제할 필요가 없음
- 스택에 할당된 메모리는 범위(scope)를 벗어나면 사라짐
- 변수와 매개변수를 위해 필요한 크기는 컴파일 도중에 알 수 있음
- but! 스택에 큰 개체를 많이 넣을시
- 스택 오버플로우가 발생할 수 있음
- 성능이 느려질 수 있음(OS 단위에서의 표현)
스택에 1MB 공간을 프로그램 실행시 한 번에 고정 시키는 것이 아닌 필요한 만큼은 사용하고,
나머지는 하드웨어에 swap 파일(페이징) 형태로 남아 있다가, 필요시 하드에서 읽어와서 사용함
힙(Heap)
- 전역 메모리 공간(크고, ~GBs 단위)
- 비어있는 채로 존재하며, 연속된 메모리 블록을 찾아야 함
- 프로그래머가 메모리를 직접 할당 및 해제해야 함
- 직접 하지 않을 시 메모리 누수가 발생
- 언매니지드 언어의 특성
프로그램 작성시 스택을 활용할 수 있다면 가능한한 스택을 사용하는 게 유리,
실행 도중 새로 만들거나, 한 함수 스코프 안에서 끝나지 않고 여러 곳에 전달되는 경우엔 힙을 쓰는 것이 좋음
또한 반환하는 오브젝트 크기가 크다면, 힙으로 생성해서 주소만 던져주는 방식도 도움이 됨
스택 활용 코드를 통해 스택을 살펴보기
Vector AddVector(const Vector& a, const Vector& b) // const 참조를 통해 해당 파라미터의 값이 바뀌는 것을 방지
{
Vector result;
result.mX = a.mX + b.mX;
result.mY = a.mY + b.mY;
return result;
}
void Foo()
{
Vector c = AddVector(a, b);
}
해당 코드의 스택 변화
힙 활용 코드를 통해 힙을 살펴보기
Vector PrintVector(const Vector& a, const Vector& b) // const 참조를 통해 해당 파라미터의 값이 바뀌는 것을 방지
{
Vector result = new Vector; // 함수 내부에서 new 를 사용하는 건 좋은 예시는 아님
result.mX = a.mX + b.mX;
result.mY = a.mY + b.mY;
// 출력 ...
}
void Foo()
{
PrintVectors(a, b);
}
해당 코드의 힙 변화 (delete 가 없는 것을 고려해서 변화 확인)
delete 를 사용하지 않아 함수는 끝났음에도 불구하고 heap 메모리가 사용중인 채로 잡혀있음
아래와 같이 delete 를 사용해줌으로써, 해당 영역을 해제하여야 다른 곳에서 필요시 다시 사용할 수 있음
Vector PrintVector(const Vector& a, const Vector& b) // const 참조를 통해 해당 파라미터의 값이 바뀌는 것을 방지
{
Vector result = new Vector; // 함수 내부에서 new 를 사용하는 건 좋은 예시는 아님
result.mX = a.mX + b.mX;
result.mY = a.mY + b.mY;
// 출력 ...
delete result; // delete 를 통해서 사용한 힙 영역 해제
}
void Foo()
{
PrintVectors(a, b);
}
C++에서는 함수 내 new 사용을 '지양'하는 것을 권장, 현대 C++에서는 RAII 원칙에 따라 자동 자원 관리를 우선시하기 때문임
메모리 누수, 예외 안전성 부족, 소유권 불명확 등의 문제가 발생하는 것을 방지하고자 하는 방향임
대신 스마트 포인터(std::unique_ptr 등)나 표준 컨테이너(std::vector 등)를 사용하는 것이 안전함
(RAII: Resource Acquisition Is Initialization)
개체 배열(Array)
// JAVA
Vector[] list = new Vector[10];
// 벡터 레퍼런스로 10개 담을 '공간을 NULL 로 할당'(벡터 생성은 별도로 다시 작업해줘야 됨)
--------------------------------------------------------------------------
// C++
Vector *list = new Vector
// 벡터 10개 생성
두 벡터 생성의 차이를 그림으로 설명한다면 다음과 같다
C++
// 10개의 '벡터 개체'를 힙에 생성
Vector *list = new Vector[10];
// 10 개의 '포인터'를 힙에 생성
Vector **list = new *Vector[10];
-------------------------------------------
JAVA
// 10 개의 '벡터 개체'를 힙에 생성
불가능
// 10 개의 '포인터'를 힙에 생성
Vector[] a = new Vector[10];
개체 소멸
// JAVA
Vector a = new Vector();
// ...
// 가비지 컬렉터를 통한 메모리 해제, 메모리 할당을 즉시 해제하지 않음
a = NULL;
---------------------------------------------------------
// C++
Vector *a = new Vector;
Vector *list = new Vector[10];
// ...
delete a; // 직접 호출, 메모리 즉시 해제
a = NULL; // 미재사용시 생략가능, 재사용시 실수 방지 차원에서 기입
delete [] list; // [] 를 반드시 입력!!
list = NULL; // 미재사용시 생략가능, 재사용시 실수 방지 차원에서 기입
new 를 한 뒤에는 반드시 delete 를 사용!!!!
멤버 변수 초기화
// JAVA
public class Vector
{
private int x;
private int y;
}
Vector a = new Vector();
// a 의 멤버 변수 x 와 y 는 0 으로 초기화
---------------------------------------
// C++
class Vector
{
public:
int mX;
int mY;
};
Vector a;
Vector *b = new Vector();
// 따로 설정을 해주지 않으면 a 나 b 의 멤버 변수 mX, mY 는 쓰레기 값을 가짐
JAVA 와 C# 은 0으로 초기화시켜줌
C++ 은 초기화 작업이 없음
- 성능을 위해서
JAVA 의 초기화
- 어떤 자료형에서도 동일하게 적용
- string str; = null 의 비트패턴은 전부 0 이므로 null
- float f; = 0.0 의 비트패턴은 전부 0 이므로 0.0
- int i; = 0 의 비트패턴은 전부 0 이므로 0
만일 C 에 없는 기능이 다른 언어에 있다면
- 컴퓨터가 알지 못하는 것
- 다른 엔지니어가 구현한 것
- 해당 기능을 구현한 부분에 대해서 배움의 자세를 가져야 함
'C++ > FOCU_C++' 카테고리의 다른 글
C++ chpt8. (1) | 2025.07.21 |
---|---|
C++ chpt7. (2) | 2025.07.01 |
C++ chpt5. (0) | 2025.05.04 |
C++ chpt4. (0) | 2025.05.03 |
C++ chtp3. (0) | 2025.05.03 |