C++ 객채배열, this포인터, 복사생성자.md!

객체배열

객체 기반의 배열은 다음과 같은 형태로 선언할 수 있다.

SoSimple arrp[10];
SoSimple *ptrArray = new SoSimple[10];

구조체의 배열 선언과 똑같다. 단 위처럼 객체배열 선언시 생성자에게 매개변수를 전달 할 수 없다. 객체생성시 반드시 무언가를 해야한다면 디폴트 생성자를 추가로 정의해서 사용해야 한다.

포인터를 사용하면 객체배열를 생성하면서 매개변수도 전달 할 수 있다.

SoSimple *ptrArray[10];
for(int i=0; i<10; i++)
{
  ptrArray[i] = new SoSimple
}

this포인터

멤버함수 안에서 this라는 이름의 포인터를 볼 수 있다. 간단히 말하면 자기 자신을 가리키는 포인터이다.

...
SoSimple* SoSimple::GetThisPointer()
{
  return this;
}

...

SoSimple sim1(100);
SoSimple *ptr = sim1.GetThisPointer();

...

객체 생성후 해당 객체 주소를 this 포인터를 통해 쉽게 획득 가능하다.

주소뿐 아니라 객체의 참좆자 또한 쉽게 구할 수 있다.

...
SoSimple& SoSimple::GetThisReference()
{
  return *this;
  //포인터가 아닌 객체 자신을 반환하겠다는 뜻. 
  //반환형이 참조자이니 참조자를 반환하게 된다.
}
...
SoSimple sim2(100);
SoSimple &ref = sim2.GetThisReference();

복사생성자

지금까지 아래 방식으로 참조자를 선언, 정의하였다.

int num1 = 20;
int &ref1 = num1;
int num2(30);
int &ref2(num2);
//모두 같은 맥락이다.

int형 뿐만 아니라 모든 객체가 위와같이 사용 가능하다.

SoSimple sim1(10);
SoSimple sim2=sim1;
//묵시적으로 SoSimple sim2(sim1)로 변환됨

SoSimple클레스에 SoSimple객체를 매개변수로 받는 생성자가 없어도 자동으로 디폴트 복사생성자가 만들어지기 떄문에 가능하다.
다음이 자동으로 디폴트 복사생성자의 예시이다.

SoSimple(const SoSimple &copy) :num(comy.num)
{}

이렇게 생긴놈이 디폴트 생성자처럼 자동으로 추가된다 생각하면 된다.
보통은 깊은복사(포인터 안의 데이터까지 카피)를 위해 디폴트 복사생성자를 사용하지 않고 별도로 만들어 사용한다.

깊은 복사는 클레스 맴버중에 포인터 변수가 있을경우 보통 사용한다. 디폴트 복사를 통해 객체를 만들면 포인터를 복사해오기 때문에 변수의 위치를 같이 가리킬뿐 그안의 데이터까지 복사해오는것은 아니기 떄문에 데이터까지 복사해오기 위해 사용하는 개념이 깊은 복사다.

복사생성자의 호출 시점

복사생성자가 호출되는 시점은 크게 3가지로 나눌 수 있다.

  1. 기존에 생성된 객체를 이용해 새로운 객체를 초기화하는 경우
    Person man1("Lee dong woo", 29);
    Person man2=man1;
    //복사생서자가 호출되는 가장 기본적인 경우
    


  2. call by value 방식의 함수 호출 과정에서 객체를 인자로 전달한 경우
    SoSimple SimpleFuncObj(SoSimple ob)
    {...}
    int main(void)
    {
      SoSimple obj;
      SimpleFuncObj(obj);
      ...
      //SimpleFunc가 호출되는 순간 매개변수 ob 생성되고 obj로 초기화(복사생성)된다.
      //SoSimple ob=obj; 가 함수 호출되고 바로 실행됨. 물론 ob는 함수가 종료되면 사라짐.
    }
    


  3. 객체를 반환하되 참조형으로 반환하지 않는 경우.
    SoSimple SimpleFuncObj(SoSimple ob)
    {
      ...
      return ob;
    }
    /*
    일단 반환된다는건 메모리에 반환받은 데이터(객체든 뭐든)가 올라 가는 것이다. 
    만약 반환받은 값을 쓸 필요가 없어 반환값을 변수에 따로 저장하지 않는다 해도
    임시객체가 생성되어 반환값을 유지한다.
    그냥 SoSimpleFuncobj(...) 이렇게 호출해도
    SoSimple temp = SoSimpleFuncobj(...)이 된다는 뜻.
    temp가 ob로 초기화 되면서 복사생성자를 호출한다.
    임시객체인 temp는 한줄이 넘어가는 순간 언제든 소멸될수 있는 쓰레기 값으로
    변할것이다.
    */
    


    다음 코드를 보고 언제 복사생성자가 호출되는지 알아보자. ``` Class SoSimple { private: int num; public: SoSimple(int n) : num(n); {} SoSimple(const SoSimple &copy) : num(copy.num) { cout«“복사생성자 호출”«endl; } SoSimple& Addnum(int n) { num+=n; return *this; } void ShowData() { cout«num«endl; } }; Sosimple SimpleFuncObj(SoSimple ob) { return ob //2. ob를 임시객체로 넘기면서 복사생성자 호출 }

int main() { SoSimple obj(7); SimpleFuncObj(obj).AddNum(30).ShowData(); //1. ob를 obj로 넘기면서 복사생성자 호출. // obj.ShowData(); return 0; } //결과는 2번 호출된다.

태그: ,

카테고리:

업데이트: