개요

클래스 타입에 사용되는 기본 함수들에 대한 이야기

 


기본 함수 ( Default Method )

클래스 타입이 기본적으로 갖고 있는 메소드를 기본 함수라 한다.

기본 함수는 메소드가 없는 경우 컴파일러가 자동으로 만들어주는 메소드라 할 수 있다.

 

기본 함수의 종류

- 기본 생성자 ( Default Constructor )

- 복사 생성자 ( Copy Constructor )

- 이동 생성자 ( Move Constructor )

- 소멸자 ( Destructor )

- 복사 할당 연산자 ( Copy Assignment Operator )

- 이동 할당 연산자 ( Move Assignment Operator )

 

 

생성자

인스턴스의 초기화를 담당하는 특수한 메소드를 생성자라 한다.

 

생성자의 문법은 기본적으로 반환타입을 갖지 않으며,  클래스 타입의 이름과 동일한 식별자를 사용한다.

매개변수가 없는 생성자를 기본 생성자라 한다.

class A
{
public :
	A() 			// 기본 생성자
    : _data(0)		// 맴버 초기화 목록 (Member Initializer List)
    {
    	_data = 10; // 할당
    }

private
	int _data = 5 	// 여기서 초기화도 가능하다.
}

 

explicit 한정자

생성자에 사용한 매개변수 목록에서 클래스 타입으로 암시적 변환이 일어난다.

struct Derived
{
    public:
        Derived(int _data, bool _data2)
            : data(_data)
        {
            cout << _data2 << "\n";
        }
    private:
        int data = 0;
};

void Foo(Derived d) {};

int main()
{
    Foo({10, true});
}

Foo()에 사용되는 int 또는 {int , bool} 은 Derived 타입으로 암시적 변환이 일어나,

Derived(int _data, bool _data2)의 생성자가 실행된다.

 

이러한 경우, void Foo(int, bool) 함수가 있다면 의도하지 않은 결과가 발생할 수 있으므로

암시적 변환을 원치 않는다면 explicit 한정자를 사용할 수 있다.

struct Derived
{
public:
    explicit Derived(int _data, bool _data2)
        : data(_data)
    {
        cout << _data2 << "\n";
    }
private:
    int data = 0;
};

void Foo(Derived d) {};

int main()
{
    Foo({10, true}); // 오류 발생
}

 

복사 생성자 ( Copy Constructor )

동일 타입의 레퍼런스를 인자로 받는 생성자를 복사 생성자라고 한다.

복사 생성자는 아무런 복사 생성자가 정의되어 있지 않을 경우 자동으로 합성된다.

class A
{
public:
    A(int data) : _data(data) { }
    A(const A& other) : _data(other._data) { } // 복사 생성자
    
private:
    int _data;
};

A a(10);
A a2(a);	// 복사 생성자 호출.
A a3 = a;	// 복사 생성자 호출.

 

얕은 복사 ( Shallw Copy ) & 깊은 복사 ( Deep Copy )

맴버에 포인터가 있는 경우!! 포인터는 메모리 주소를 값으로 갖고 있다.

복사 생성자를 통하여 복사된 인스턴스가 같은 주소값을 가지고 있다면,

하나의 인스턴스의 변경이 다른 인스턴스에 영향을 주게 되며 이를 얕은 복사라 이야기 한다.

class A
{
public:
    A() : _p(malloc(sizeof(int) * 3)) { }
 
    A(const A& other)
      : _p(malloc(sizeof(int) * 3)) 	// 새로운 영역 할당
    {
      for (int i = 0; i < 3; ++i)
      {
        _p[i] = other._p[i];
      }
    }
 
    void Foo(int index, int value)
    {
      _p[index] = value;
    }
private:
    int* _p;
};

얕은 복사를 의도한 것이 아니라면, 초기화 시 다른 메모리 영역을 가리킬 수 있도록 새로운 메모리 영역을 할당해 줘야 한다. 이를 깊은 복사라고 한다.

 

 


소멸자

소멸자는 객체의 수명이 다할 때 자동으로 호출되는 특수한 메소드이다.

보통 자원을 정리하기 위해 사용된다.

class A
{
public:
    A() : _p(malloc(sizeof(int) * 3)) { }
    
    ~A() // 소멸자 
    { 
       free(_p); _p = nullptr; // 자원을 정리한다.
    }	

private:
    int*    _p;
};

소멸자는 정의되지 않은 경우 자동으로 컴파일러에 의해 합성된다.

 

 


복사 할당 연산자

C++에서는 연산자 오버로딩 ( Operator Overloading )이 가능하다.

클래스 타입과 동일한 타입의 하나의 매개변수를 갖는 할당 연산자를 복사 할당 연산자라고 한다.

class A
{
    int _data;
public:
    A& operator=(A a)	// 복사 할당 연산자
    {
        std::swap(_data, a._data);
        return *this;
    }
};

복사 할당 연산자를 구현하는 방법은 여러가지 있다.

위와 같이 복사 후 교환 관용구를 사용하여 복사 할당 연산자를 구현할 수 있다.

 

 

연산자 오버로딩 C++ Reference

 

operator overloading - cppreference.com

Customizes the C++ operators for operands of user-defined types. [edit] Syntax Overloaded operators are functions with special function names: operator op (1) operator type (2) operator new operator new [] (3) operator delete operator delete [] (4) operato

en.cppreference.com

 

728x90

'Program > C (C++,C#)' 카테고리의 다른 글

자료구조와 알고리즘  (0) 2022.06.07
[C++] Class 상속  (0) 2022.06.02
[C++] 레퍼런스와 클래스  (0) 2022.05.30
객체지향 프로그래밍  (0) 2022.05.30
[C] 스택 프레임과 호출 규약  (0) 2022.05.30

+ Recent posts