본문 바로가기
C++(공부중)

C++ 공부 2일차

by 케찹이 2020. 7. 28.
반응형

지역변수의 레퍼런스를 리턴

int& function(){
    int a = 2;
    return a;
}

int main(){
    int b = function();
    b = 3;
    return 0;
}

위 코드는 컴파일 오류. 왜냐하면 function함수는 레퍼런스를 리턴하는 함수이다. 하지만 function함수는 리턴을 하게 되면 a는 사라지게 되고 int b는 a의 별명과 같다는 의미를 같게된다. b는 별명의 데이터와 같다고 명령받았지만 그 안의 실제 데이터인 a는 이미 사라져버린 상태이다. 이러한 레퍼런스를 댕글링 레퍼런스(dangling reference)라고 한다. 

*레퍼런스를 리턴하는 함수에서 지역 변수의 레퍼런스를 리턴하지 않도록 조심해야 한다.

 

외부 변수의 레퍼런스를 리턴

int& function(int& a){
  a = 5;
  return a;
}

int main(){
  int b = 2;
  int c = function(b);
  return 0;
}

위 코드는 function함수가 int& a를 매개변수로 받고 int& ref = a; int c = ref; 와 같은 형식의 코드가 된다. 지역변수의 레퍼런스와는 달리 function함수가 끝나고 a가 없어져도 b값을 참조하게 된다. 

 

상수 참조자 타입(const int&a = f()) 는 예외적으로 함수에서 값을 리턴받을 수 있다. 

 

C++은 객체지향프로그램을 지원해준다 이는 C보다 한단계 높은 언어가 되게 해주는 기능이고 자바를 배운 입장에서 이해하는데 낮설지 않았다. 주로 C언어에서 사용하던 구조체를 이제 클래스를 사용하면서 더 쉽게 사용할 수 있게 되었다.

그래서 클래스에 관한 내용, private, public, overloading, 생성자에 관한 이야기는 굳이 여기에 적지 않도록 하겠다. 

 

우리는 클래스를 만들면 배열을 이용해서 여러가지 클래스들을 호출할 수 있다. 바로 new와 delete으로 말이다.

new와 delete은 C에서 사용했던 malloc과 free의 개념과 완벽히 같다. 다만 C++에서 new와 delete을 사용하는 이유로서는 생성과 동시에 생성자를 동시에 호출할 수 있다는 장점때문이다. 한번 클래스에서 배열을 동적할당하게 되면

//Book 이란 클래스가 있다면...

Book* books[100];

books[0] = new Book(x,x);
books[1] = new Book(x,x);

delete books[0];
delete books[1];

대충 이런 식으로 사용이 가능하다는 것이다. 

이렇듯 메모리에 동적할당을 하게되면 우리가 delete을 사용하여 직접적으로 메모리를 다시 비워주어야한다. 근데 클래스안에서 메모리를 할당할때가 있다. 그때 우리는 소멸자를 사용해야 한다. 

소멸자는 ~(클래스 이름) ()식으로 만들고 main함수가 종료되면 메모리 할당한 순서부터 소멸시켜준다. 

 

복사 생성자, 즉 하나의 클라스만 생성하고 이 클라스를 복제하여 여러가지 클라스를 생성할 수 있게 도와주는 것이 복사 생성자입니다. 복사 생성자의 기본적인 틀은

T(const T& a);

처럼 정의가 된다. a는 const이기 때문에 내부의 데이터를 변경할 수는 없고 인스턴스 변수들을 복사만 할 수 있다. 

*안자로 받는 변수의 내용을 함수 내부에서 바꾸지 않는다면 앞에 const를 붙여 주는 것이 바람직하다.

 

복사 생성자는 default 복사 생성자를 지원한다. 이는 생성자와 소멸자와는 달리 실질적으로 데이터들을 1대1로 모두 복사하여준다. 하지만 여기서 조심해야 할 부분이 있는데 만약에 인스턴스 데이터에 쥬소값을 가리키는 데이터가 존재하면 오류가 발생한다. 이런 이유는 저장할 때에는 문제가 없지만 소멸자를 호출하게 되면 복사전 값과 복사 후 값이 같은 하나의 주소값을 가리키고 있는 상태에서 첫번째 피복사되는 데이터가 이 주소를 소멸자를 통해서 해제를 하게 되고 복사된 데이터는 소멸자를 통해서 이미 없어진 주소를 다시한번 해제를 하려고 시도를 하게 된다. 이럴때 바로 오류가 발생하게 된다. 그럼 이 문제를 어떻게 해결해야 할까....

이 문제는 복사가 이루어질때 그대로 복사하는 것이 아니라 다른 메모리를 만들어 거기다 동적할당하고 내용을 복사하면 된다. 이러한 복사를 (deep copy)라고 한다. 그럼 default복사 생성자를 사용하는 것이 아니라 함수를 더 만들어야겠지?

 

그다음에 생성자의 초기화 리스트라는 것을 배웠는데 이는 생성자를 조금 다른 방식으로 저장하는 형태임.

class Player{
  int height;
  int weight;
  int age;
  bool new;
  
 public:
  Player();
}

Player::Player() : height(175), weight(75), age(23), new(true) {}

바로 이렇게 생성자가 값들을 가지고 생성하게 된다. 이렇게 사용하는 것의 장점은 물론 보기에 더 편한 것도 있지만 const나 상수 같이 반드시 초기화를 먼저 해야지 작동하는 변수들을 잊지 않고 초기화할 수 있기 때문이다. 그리고 추가적으로 생성자안에 매개변수를 받아서 인스턴스 변수들을 변화시킬 수 있다. 

 

static 변수를 활용하면 클래스의 총 개수를 셀 수 있다. 원래 static 과 같은 전역 변수는 함수가 종료되면 소멸되어 버리지만 클래스의 static변수는 프로그램이 종료될 때까지 소멸되지 않는다. 

static은 변수뿐만 아니라 static 함수도 정의가 가능하다. static함수는 객체에 소속된 것이 아니고 클래스에 포함되었기 때문에 (클래스)::식으로 호출해주어야 한다. 그럼으로 static함수는 static변수만을 이용해야한다. 

 

 

 

*씹어먹는 C++을 참고하였습니다.

반응형

'C++(공부중)' 카테고리의 다른 글

C++ 공부 3일차  (0) 2020.07.30
C++ 공부 1일차  (1) 2020.07.28

댓글