Back-end/C++

22.03.11 - 생성자 초기화 리스트, 포인터형과 참조형

giggs 2022. 3. 16. 13:55

오늘 강의의 전체 흐름

 

생성자 리스트 설명하기 위해 ( 객체, 생성자, 소멸자, 멤버 변수 초기화 ) 개념 잡고 접근 

포인터형과 참조형 설명하기 위해 ( 함수와 변수, 데이터 타입  ) 개념 잡고 접근

 

 


 

객체

  • - It 쪽에서 말하는 객체와 게임 쪽에서 말하는 객체의 정의가 다르다.
  • 대상 객체가 될 수 있는 공통 조건 -> 데이터화를 시킬 수 있어야 한다는 점
  • IT 쪽에서는 - 현실 세계에 있는 명사나 대명사로 표현 가능한 모든 것
  • 게임 쪽에서는 - 용, 귀신, 악마 등 상상할 수 있는 모든 것

 


 

생성자

  • 객체를 생성하는 경우 생성자가 반드시 필요하다.
  • 그런데 우리가 생성자를 안 만들어도 객체가 만들어지는 이유는?
  • 생성자를 따로 만들지 않는 경우 컴파일러가 자동으로 기본 생성자 코드를 삽입해준다.
  • 다만, 인자를 받는 생성자나 // 디폴트 생성자를 우리가 만들어 놓은 경우 - 컴파일러는 기본 생성자 안 만들어준다.
  •  
  • Student(){ } -  생성자 - 선행됨
  • ~Student(){ } - 소멸자 - 후행됨
  • 객체 생성 시에 자동으로 디폴트 생성자가 호출되는 것이다~ -컴파일러가 자동으로 해줌
  • 객체 삭제 시에 자동으로 디폴트 소멸자가 호출되는 것이다~ -컴파일러가 자동으로 해줌

 

멤버 변수의 값을 초기화시켜줄 때 생성자와 소멸자 주로 사용

 

디폴트 생성자 만들어 줄 경우에는 멤버 변수들 다 초기화해주는 방식으로 만들기!

출력된 것에서 차이 점 check!

 

디폴트 생성자에 - 밑에서 살펴 볼 생성자 초기화 리스트로 멤버 변수들 초기화 해 줌.
디폴트 생성자에 - 멤버 변수 아무것도 초기화 안 해 줌.

 


소멸자

  • 객체가 없어질 때 컴파일러에 의해 자동으로 호출된다. ~Student(){ } 형식으로 만들어 준다.

 

 


 

 

생성자 초기화 리스트 - C++에만 있는 기능

 

 

지금까지 생성자를 만드는 데 사용한 방법은

이미 메모리 할당이 다 끝난 상태에서 대입 연산으로 값을 넣어 주는 방식이었다. 

  • Student( ) { _age =0;    _address="주소 없음";    _grade=0;    _classNum=0;  }

 

C++에서는 메모리 할당과 동시에 값을 입력하는 방법을 사용할 수 있다.

  • Student( ) : _age(age), _address(address), _grade(0), _classNum(0) {   }

 

 


 

함수와 변수

 

 

함수와 변수는 선언하는 위치에 따라 변수의 성격이 달라진다.

 

함수

  • 멤버 함수 – 클래스 내부의 함수 - 객체를 통해서만 호출할 수 있다.
  • 일반 함수 – 클래스 외부의 함수 - 바로 직접 호출할 수 있다.

변수

  • 멤버 변수 - 클래스 내부에 만들어진 변수
  • 외부 변수 – ( = 전역 변수 ) - 함수의 바깥쪽에 만들어진 변수
  • 지역변수 – ( = 자동 변수 ) - 함수 내부 { } 블록 안에서만 호출이 가능한 변수 - { } 블록 끝나면 사라짐
  • static 정적 변수 – ( = 로컬 변수 ) - 블록 끝나도 없어지지 않음 – 프로그램 종료 시까지 안 없어짐.

 

클래스 바깥 쪽에 만들어진 변수와 함수 이름 체크!

 

 


 

포인터형 변수 ref& , 참조형 변수 int* pa / *pa  

 

 

포인터형 

변수가 만들어질 때

정수형을 저장할 int, 문자열을 저장할 string, 실수를 저장할 float처럼 dataType 이 필요한데

 

주소 값( & )을 저장하는 dataType 은?

그것이 바로 포인터형 ( * )이라고 한다.!

 

 

포인터형에는 ( * )의 쓰임새에 따라 1. 포인터 형 지정자 2. 포인터 연산자로 나뉜다.

 

 

1. 포인터 형 지정자

  • a의 주소 값을 나타낼 때는 &a라고 한다. -> &a를 저장할 수 있는 dataType은 * 포인터 형 지정자
  • a가 int 값을 저장하는 변수이므로 int* pa = &a; -> int 형 변수를 저장하고 있는 공간의 주소 값!
  • int* 에서 ( * )는 #포인터 형 지정자  

 

2. 포인터 연산자

  • 주소를 저장하는 변수를 만들 때는 int* pa = &a;
  • a의 주소 값을 나타내는 &a에다가 포인터 연산자(*)를 쓰면 -> *&a -> 공간을 의미!
  • *pa라고 하면 -> pa = &a 저장되어있다. -> *&a와 같은 것이다. -> a의 주소 값을 저장하고 있는 공간 -> a
  • 따라서 *pa = a가 되는 것으로, *pa를 통해 a의 값을 변경할 수 있다. 
  • *pa = a에서 ( * )는 #포인터 연산자 

 

다음 수업에서 한 번 더 설명하면서 다룰 예정! 그때 한 번 더 체크!

 


 

참조형

포인터형과 내부적으로 적용되는 코드는 똑같다.

 

차이점은

1. 정의와 동시에 초기화가 필요하다는 점

2. 포인터형처럼 pa나 ppa 변수를 생성 - 메모리가 따로 생긴다 - 참조형 &ref는 변수를 따로 생성하는 것이 아닌 X

   - 들어온 주소 값의 공간만 참조한다.

3. 포인터형은 pa나 *pa의 값을 변경할 수 있지만, 참조형 ( & ) 은 처음 들어온 주소 값의 공간만 참조 - 변경 불가능

 

a나 pa처럼 메모리 공간이 생기는것이 아닌 b에 접근할 수 있는 별칭이 하나 더 생긴것이다.

 

선언 방법 int &refa = b; -> 항상 b의 주소 값 공간을 가리키는 것이고, 변경 불가능하다.

 

메모리가 따로 생성되는 변수가 아니라, b에 접근할 수 있는 별칭이 하나 더  생긴 것이라고 이해

 


review

이번 강의의 메인 포인트는
생성자 초기화 리스트, 포인터형 지정자와 포인터 연산자, 참조형이었다.
C++에만 있는 생성자 초기화 리스트와 포인터형은 주소 값을 저장할 수 있는
데이터 타입 - 포인터 형 지정자가 있기에 가능!

생성자 초기화 리스트 ----
대입 연산으로 값 대입 X 아닌 메모리 할당과 동시에 초기화시켜주는 방법!
Student( ) : _age(age), _address(adress) { } 형식으로 사용

포인터형 지정자 ---- 
int* pa = &a
포인터형 연산자 ---- *pa = 1000;
참조형 ---- int& refa = a

C++에만 있는 생성자 초기화 리스트와 포인터형

이 외에도 객체의 정의 관점이 다를 수 있다는 것
객체 없어질 때 소멸자가 자동으로 불려지고 있었다는 것
변수나 함수를 사용하면 외부적으로 이렇게 작동되는구나 했던 부분들을
내부적으로 메모리가 어디에 어떻게 할당되고, 불려 오고 하는 것을 알 수 있어서 좋았다.





 

 

 

생성자 초기화리스트 실습해본 코드

#include <iostream>
#include <string>

using namespace std;

class Student {
private:
	int _age;
	string _address;
	int _grade;
	int _classNum;
	string _name;

public:
		
	
	Student() : _age(0), _address("주소없음"), _grade(0), _classNum(0), _name("이름없음")
	{
	
		cout << "기본 생성자" << endl;
		cout << endl;
	}
	

	
	Student(string name, int age, string address)
		: _name(name), _age(age), _address(address), _grade(0), _classNum(0)
	{
		
		cout << _name << "이 인자 2개를 받는 생성자" << endl;
		cout << endl;
	}
	

	Student(string name, int age, string address, int grade, int classNum) 
		:_name(name), _age(age), _address(address), _grade(grade), _classNum(classNum)
	{
		
		cout << _name << "이 인자 4개를 받는 생성자" << endl;
		cout << endl;
	}

	//소멸자
	~Student() {
		cout << _name << "의 소멸자 " << endl;
		cout << endl;
	}

	void SetAge(int value) {
		_age = value;
	}

	int GetAge() {
		return _age;
	}

	void Info() {
		cout << "이름: " << _name << endl;
		cout << "나이: " << _age << endl;
		cout << "주소: " << _address << endl;
		cout << "학년: " << _grade << endl;
		cout << "반: " << _classNum << endl << endl;
	}

};

int main() {

	Student a("오학생", 10, "런던");   

	Student b;

	a.Info();
	b.Info();


	
	return 0;
	
}

 

포인터형과 참조형 실습해본 코드

#include <iostream>

using namespace std;

int global = 10; //외부 변수

class A {
public:

	int _value; // 멤버변수

	void func() {//멤버함수
		int a = 0; // 지역변수
		global = 100;
	}
};


void func() {    // 일반함수
	static int score = 0;  // 정적변수, 로컬변수
	global = 10;
}


int main() {
	
	//a의 주소값을 저장하는 공간생기는 포인터변수 int* pa
	//*pa 는 현재 a의 주소값을 가리킨다. 그 주소값을 이용해서 a의 값 변경
	//*pa 는 다른 주소값 가리키도록 변경가능

	int a = 100;

	cout << "a = " << a << endl;
	
	int* pa = &a;
	*pa = 1000;

	cout << "a = " << a << endl;

	// b의 주소값을 저장공간하는 공간이 생기지않는 
	// 가리키는 방법만 추가되는 참조변수활용 int& reafa
	// refa 는 현재 b의 주소값을 가리킨다. 그 주소값을 이용해서 b의 값 변경 
	// refa 는 처음 선언할 때 초기화 필요. 이후에 변경불가능

	int b = 20;
	int& refa = b;

	cout << "b = " << b << endl;

	refa = 2000;

	cout << "b = " << b << endl;

	//pa변수가 가리키는 주소값 a에서 b로변경
	//*pa는 현재 b의 주소값을 가리킨다. 그 주소값을 이용해 b의 값 변경
	pa = &b;
	*pa = 50000;
	cout << "b = " << b << endl;


	return 0;

}