C++에서 동적 할당(dynamic allocation)은 new와 delete 키워드를 사용하여 수행할 수 있습니다. 이 방법은 실행 시간 동안 필요한 메모리를 할당하고 해제하는 데 사용됩니다.
class MyType
{
// 접근 제한 지정자
private:
// 맴버 변수
int a;
float b;
// 맴버 함수 - 특정 클래스, 구조체
// 맴버함수를 호출하기 위해서, 객체가 필요하다.
public:
void SetInt(int _a)
{
a = _a;
}
void SetFloat(float _f)
{
b = _f;
}
MyType* GetAdress()
{
return this;
}
};
MyType이란 Class를 객체에 할당하기 위해서 Malloc을 사용하는 것은 바람직 하지 않다. 그 이유는 Malloc을 통해서는 단순히 메모리 공간만을 할당하고 MyType Class안 생성자, 소멸자를 호출하지 않기 때문이다. 그 이유는 어떤 객체가 저장될지, 객체의 생성자나 소멸자가 필요한지에 대한 정보는 전혀 사용하지 않기 때문이다.
// C++ 에서의 동적할당
// 동적할당에 사용할 자료형 정보를 전달
// 자료형 정보를 통해서 크기정보와, 클래스 타입인 경우 클래스의 생성자 호출까지 연동할 수 있다.
MyType* pMyType1 = new MyType;
// C++ 에서의 힙메모리 해제
// delete 키워드에 포인터를 전달시킴, 전달시키는 포인터가 어떤 타입이냐에 따라서 힙메모리 공간을
// 어떤 용도로 썻는지 알 수 있음, 따라서 소멸자까지 호출이 가능
delete pMyType1;
// C++ 에서의 동적할**텍스트**당 여러개
MyType* pMyType2 = new MyType[4];
// C++ 에서의 힙메모리 해제
delete[] pMyType2;
생성자와 소멸자는 C++에서 클래스의 객체를 초기화하고 정리하는 역할을 합니다. 이들은 클래스의 중요한 멤버 함수로서 객체의 수명 주기 동안 중요한 작업을 수행합니다.
생성자 (Constructor)
생성자는 객체가 생성될 때 호출되며, 객체의 초기화를 담당합니다. 생성자는 클래스 이름과 동일한 이름을 가지며 반환 타입이 없습니다.
기본 생성자 (Default Constructor): 매개변수가 없는 생성자입니다.
매개변수가 있는 생성자 (Parameterized Constructor): 객체를 특정 값으로 초기화할 때 사용합니다.
복사 생성자 (Copy Constructor): 다른 객체를 이용해 새로운 객체를 생성할 때 사용합니다. ClassName(const ClassName &other) 형식을 가집니다.
이동 생성자 (Move Constructor): r-value 참조를 사용하여 자원을 이동할 때 사용합니다. ClassName(ClassName&& other) 형식을 가집니다.
public:
// 생성자
// - 맴버함수, 구현하지 않아도 자동 생성되는 맴버함수
// - 객체가 생성될 때 호출
MyType()
{
printf("생성자 호출됨\n");
}
// 소멸자
// - 맴버함수, 구현하지 않아도 자동 생성되는 맴버함수
// - 객체가 삭제될 때 호출 됨
~MyType()
{
printf("소멸자 호출됨\n");
}
};
생성자에는 매개변수를 통해 오버로딩이 가능하다.
MyClass(void)
: m_i(0) // 이니셜라이저
, m_f(0.f)
, m_s(0)
{
m_i = 0; // 대입
m_f = 0.f; // 대입
//m_s = 20; // 대입
}
// 생성자 오버로딩
MyClass(int _i, float _f, short _s)
: m_i(_i)
, m_f(_f)
, m_s(_s)
{
}
소멸자 (Destructor)
소멸자는 객체가 삭제될 때 호출되며, 객체가 사용한 자원을 해제하는 역할을 합니다. 소멸자는 클래스 이름 앞에 ~ 기호를 붙여 선언하며 반환 타입이 없습니다.
소멸자는 매개변수를 가질 수 없습니다.
객체가 스코프를 벗어나거나 delete 연산자가 호출될 때 자동으로 호출됩니다.
명시적으로 호출할 수 없습니다.
연산자 오버로딩은 C++에서 제공하는 기능으로, 사용자 정의 데이터 타입에 대해 기존 연산자를 재정의하여 사용할 수 있게 합니다. 이를 통해 클래스 객체가 기본 자료형처럼 자연스럽게 연산에 참여할 수 있습니다. 연산자 오버로딩은 함수 오버로딩의 특별한 형태로 볼 수 있습니다.
// 연산자 오버로딩
class CData
{
private:
int m_i;
long long m_ll;
public:
void SetInt(int _i) { m_i = _i; }
void SetLongLong(long long _ll) { m_ll = _ll; }
int GetInt() { return m_i; }
long long GetLongLong() { return m_ll; }
// 연산자 오버로딩
public:
CData operator + (const CData& _Other) const // 해당 맴버함수를 호출시킨 객체를 수정하지 않겠다.
{
CData data;
data.m_i = m_i + _Other.m_i;
data.m_ll = m_ll + _Other.m_ll;
// m_i = 200;
// _Other.m_i = 200;
return data;
}
public:
CData()
: m_i(0)
, m_ll(0)
{
}
~CData()
{
}
};
//CData operator+(const CData& _Left, const CData& _Right)
//{
// CData data;
//
// data.SetInt(_Left.GetInt() + _Right.GetInt());
// data.SetLongLong(_Left.GetLongLong() + _Right.GetLongLong());
//
// return data;
//}
int main()
{
CData d1, d2;
d1.SetInt(10);
d1.SetLongLong(10);
d2.SetInt(20);
d2.SetLongLong(20);
CData d3 = d1 + d2;
int a = 0, b = 0;
a = 10;
b = 20;
int c = a + b;
return 0;
}