INDEX
- INDEX
- OOP란 - 객체지향 프로그래밍 - Java vs C++
- 클래스 접근 제어자 - 접근제어자
- 개체 생성, 스택 힙 - 개체 생성 - 스택 - 힙
- 개체 배열 생성, 개체 소멸 - 개체 배열 - 개체 소멸
- 클래스 멤버 변수 초기화 - 기본 값 - Java가 멤버 변수를 0으로 초기화하는 방법
- new/delete와 malloc()/free()의 차이점
- 클래스 생성자, 초기화 리스트 - 생성자 - 초기화리스트
- 클래스 기본 생성자, 컴파일러가 하는 일 - 기본 생성자 - 컴파일러가 하는 일
- 클래스 생성자 오버로딩, 소멸자 - 생성자 오버로딩 - 소멸자 - 클래스 안에서 동적 메모리 할당
- 클래스 const 멤버 함수 - const 란?
- 구조체(Struct) vs 클래스(Class) - 구조체 vs 클래스 - 구조체에 관한 코딩 표준
OOP란
객체지향 프로그래밍
- 인간의 사고방식으로 바라본 프로그래밍 패러다임
- 직관적
- 단, 추상화가 들어가면 복잡해질 수 있다.
Java vs C++
Java | C++ |
---|---|
클래스 | 클래스 |
개체 | 개체 |
생성자 | 생성자 |
함수 오버로딩 | 함수 오버로딩 |
힙에 개체 생성하기 | 입에 개체 생성하기 |
스택에 개체 생성하기 | |
복사 생성자 | |
소멸자 | |
연산자 오버로딩 |
클래스 접근 제어자
접근제어자
- public
- 누구나 접근 가능
- protected
- 자식 클래스에서 접근 가능
- private
- 해당 클래스에서만 접근 가능(개체에서가 아님)
개체 생성, 스택 힙
개체 생성
Java의 경우
//스택 메모리에 만들지 못함
//힙 메모리에 만들기 (느림)
Vector* a = new Vector();
C++의 경우
//스택 메모리에 만들기 (빠름)
Vector a;
//힙 메모리에 만들기
Vector* a = new Vector();
스택
- 예약된 로컬 메모리 공간 (작음, 일반적으로 1MB이하)
- 함수 호출과 반환이 이 메모리에서 일어남
- 단순히 스택 포인터를 옮김
- 메모리를 할당 및 해제 할 필요가 없음
- 스택에 할당된 메모리는 범위를 벗어나면 사라짐
- 변수와 매개변수를 위해 필요한 크기는 컴파일 도중에 알 수 있음
- 하지만 스택에 큰 개체를 많이 넣으면
- 스택 오버플로우가 발생할 수 있음
- 성능이 느려질 수 있음
힙
- 전역 메모리 공간 (큼, ~GBs)
- 비어있고 연속된 메모리 블록을 찾아야 함
- 프로그래머가 메모리를 직접 할당 및 해제해야 함
- 그렇지 않으면 누수가 발생함
- C++은 언매니지드 언어
개체 배열 생성, 개체 소멸
개체 배열
Java의 경우
Vector[] list = new Vector[10];
//백터를 10개 담을 수 있는 공간
//10개의 "포인터"를 힙에 만듦
C++ 의 경우
Vector* list = new Vector[10];
//백터 10개를 만듦
//10개의 백터 개체를 힙에 만듦
Vector** list = new Vector*[10];
//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; //안 해도 됨
클래스 멤버 변수 초기화
기본 값
- Java, C#
- 0으로 초기화됨
- C++
- 값이 초기화되지 않음
- 전에 메모리 공간에 저장되어 있던 값을 사용
- 쓰레기 값
Java가 멤버 변수를 0으로 초기화하는 방법
Vector a = new Vector();
//C의사코드
void* ptr = malloc(sizeof(Vector));
memset(ptr, 0, sizeof(Vector));
a = (Vector*)ptr;
new/delete와 malloc()/free()의 차이점
-
malloc/free는 라이브러리가 제공하는 함수인데 비해 new/delete는 언어가 제공하는 연산자이다. 그래서 별도의 헤더 파일을 포함할 필요없이 언제든지 사용할 수 있으며 이 연산자를 쓴다고 해서 프로그램이 커지는 것도 아니다. 연산자이기 때문에 사용자 정의 타입에 대해 오버로딩할 수도 있다.
-
malloc 함수는 필요한 메모리양을 바이트 단위로 지정하고 void *를 리턴하므로 sizeof 연산자와 캐스트 연산자의 도움을 받아야 한다. 이에 비해 new는 할당할 타입을 지정하고 해당 타입의 포인터를 리턴하므로 sizeof 연산자와 캐스트 연산자를 쓸 필요가 없다. 할당한 타입과 같은 타입의 포인터 변수로 대입만 받으면 된다.
-
malloc은 메모리를 할당하는 것만이 목적이므로 초기값을 줄 수 없지만 new 연산자는 동적으로 생성한 변수의 초기값을 지정할 수 있다. 즉 할당과 동시에 초기화를 할 수 있는데 할당 타입 다음의 괄호에 초기값을 적어 주면 된다. int *pi=new int; *pi=123; 두 문장은 int *pi=new int(123); 하나로 합칠 수 있다.
-
new 연산자로 객체를 할당할 때 생성자가 자동으로 호출된다. 생성자는 생성과 동시에 객체를 초기화할 수 있도록 함으로써 클래스가 기존 타입과 동등한 자격을 가지도록 하는 중요한 역할을 한다. 생성자를 호출한다는 점이 malloc과 new의 가장 큰 차이점이며 C++에서 별도의 할당 연산자가 추가된 이유이다. 마찬가지로 delete로 객체를 삭제할 때는 파괴자라는 특별한 함수가 자동으로 호출된다.
-
malloc/free 함수로 할당한 메모리는 realloc으로 크기를 바꿔 재할당 할수 있지만 new에는 이에 대응하는 기능이 없어 새로 할당하여 복사하고 원래 메모리를 해제하는 과정을 직접 해야 한다. 그래서 재할당할 때마다 매번 번지가 바뀌며 심지어 축소할 때도 번지가 바뀐다. 또한 실행중에 할당 블록의 크기를 조사하는 _msize에 해당하는 기능도 없다. 할당 대상이 객체가 아니고 재할당을 빈번하게 한다면 malloc/free를 사용할 수도 있고 객체를 할당할 때는 반드시 new/delete를 써야 한다. 단, 할당, 해제 함수는 반드시 짝을 맞추어야 하며 섞어서 쓸 수는 없다. new로 할당한 메모리는 반드시 delete로 해제해야 하고 malloc으로 할당한 메모리는 free로 해제한다.
-
역시 가장 큰 차이점은 new연산자는 생성자/소멸자가 호출된다는 점이다!!!
클래스 생성자, 초기화 리스트
생성자
Java의 경우
public class Vector
{
private int x;
private int y;
// 매개변수 없는 생성자
// 안 만들어도 상관없음
public Vecotr()
{
x = 0;
y = 0;
}
}
C++의 경우
class Vector
{
public:
//매개변수 없는 생성자
Vecotr() : mX(0), mY(0)
{
}
private:
int mX;
int mY;
}
초기화리스트
- 멤버 변수 대입 없이 쵝화
- 상수나 참조 변수도초기화 가능
class X
{
const int mNameSize;
AnotherClass& mAnother;
X(AnotherClass& another)
: mNameSize(20)
, mAnother(another)
{
}
};
class X
{
const int mNameSize;
AnotherClass& mAnother;
X(AnotherClass& another)
{
//에러!
mNameSize = 20;
//에러!
mAnother = another
}
};
// Header 파일 ~
class Vector
{
public:
Vector();
Vector(int x, int y);
private:
int mX;
int mY;
}
// Cpp 파일 ~
Vector::Vector()
: mX(0)
, mY(0)
{
}
Vector::Vector(int x, int y)
: mX(x)
, mY(y)
{
}
클래스 기본 생성자, 컴파일러가 하는 일
기본 생성자
-
기본 생성자는 매개변수를 받지 않음
-
클래스에 생성자가 없으면 컴파일러가 기본 생성자를 자동적으로 만들어 줌
-
이렇게 자동적으로 만들어진 생성자는
-
- 멤버 변수를 초기화 하지 않음
- 하지만 모든 포함된 개체의 생성자를 호출
- Vector( ) { }
컴파일러가 하는 일
-
클래스에 생성자가 없는 경우
-
- 기본 생성자를 자동으로 만들어 줌
-
클래스에 생성자가 있는 경우
-
- 기본 생성자를 자동으로 만들어주지 않음
클래스 생성자 오버로딩, 소멸자
생성자 오버로딩
-
여러 개의 생성자를 만들 수 있음
-
- 같은 이름
- 인자의 개수나 자료형은 다름
-
기본 생성자
Vector() : mX(0), mY(0) { } Vector a; // 기본 생성자 호출
-
매개변수를 가지는 생성자
Vector(int x, int y) : mX(x) , mY(y) { } Vector a(1, 3); // 매개변수 목록이 일치하는 생성자 호출
소멸자
-
개체가 지워질 때 호출됨
-
가상 소멸자에 대해선 나중에 배워보자
-
C++ 클래스는 그 안에서 동적으로 메모리를 할당할 수도 있음
-
- 그런 경우 필히 소멸자에서 메모리를 직접 해제해 줘야 한다
클래스 안에서 동적 메모리 할당
MyString.h
class MyString
{
public:
MyString();
~MyString();
private:
char* mChars;
int mLength;
int mCapaciy;
};
MyString.cpp
MyString::MyString()
: mLength(0)
, mCapaciy(15)
{
mChars = new Char[mCapaciy + 1];
}
MyString::~MyString()
{
delete[] mchars;
// mCapacity = 0;
// mChars = NULL;
}
- 소멸자 안에 메모리 해제가 있어야 한다!!
클래스 const 멤버 함수
const 란?
- 바꿀 수 없는 것을 말함
- const 변수 : 값을 바꿀 수 없는 변수
- const 메서드 : 해당 개체 안의 어떠한 것도 바꾸지 않음
구조체(Struct) vs 클래스(Class)
구조체 vs 클래스
-
구조체 클래스 기본 접근 권한 public 기본 접근 권한 private -
- 딱 한가지 차이!
- 나머지는 구조체가 클래스 기능을 전부 대체 가능
-
컴퓨터는 둘을 구분할까
-
-
ㄴㄴ 구분 못함
-
C에는 클래스가 없음
-
- 그럼 컴퓨터는 그런거 모른다는 거다
-
-
컴파일러는 둘을 구분할까?
-
-
구분 가능
-
- 기본 접근 권한 설정 가능
-
구조체에 관한 코딩 표준
-
C++에서는 구조체를 클래스처럼 쓸 수 있음
-
- 하지만 절대 그러지 말자
- 구조체는 C 스타일로 쓰자
-
구조체는 순수하게 데이터 뿐이어야 함 (Plain Old Data, POD)
-
-
단순한 옛날 데이터를 사용
-
- Plain Old Data, POD
- int, float, char 등등
-
사용자가 선언한 생성자나 소멸자 X
-
static 아닌 private/protected 멤버 함수 X
-
가상 함수 X
-
메모리 카피 가능함
-
- memcpy()를 사용하여 strcut를 char[]로, 혹은 반대로 복사할 수 있음
-