Small Step

[C++] 씹어먹는 C++ 공부 정리(~오버로딩, 생성자) 본문

코딩/C, C++

[C++] 씹어먹는 C++ 공부 정리(~오버로딩, 생성자)

Esunn 2022. 8. 5. 18:34

https://modoocode.com/135

 

씹어먹는 C++ 강좌 계획

 

modoocode.com

모두의 코드의 C++ 강좌를 공부한 내용을 정리해 볼까 한다.

C++ 어렵고 배울 양도 매우 많다.

그러므로 이 강좌를 전체적으로 완강하는것을 먼저 목표로 할 생각이다.

 

첫 C++ 프로그램

네임스페이스 (namespace)

C++에는 네임스페이스라는 개념이 등장한다.

 

cout << "Hello, World!" << endl;

이 코드는 사실 

 

std::cout << "Hello, World!" << std::endl;

std라는 네임스페이스에 있는 cout과 endl을 사용한것을 명시해주는 std::를 생략한 코드이다.

 

using namespce std;

이 코드를 이용해 std를 이용한다는 것을 나타낸다.

 

 

입출력은 바뀌었지만 기존의 반복문(for, while)과 조건문(if, else, switch)등등은 C언어와 똑같이 사용가능하다.

 

참조자 (reference)

이 부분은 전에 내가 C++을 배울때 레퍼런스 변수라고 배웠던 부분이다.

 

https://youtu.be/Bpu5YiAgETo

이 부분에 나온 내용인듯 했다.

 

C언어에서 어떠한 변수를 가리킬때는 포인터만을 사용했으나 C++에서는 참조자를 이용할 수 있다.

 

int a= 3;
int& another_a = a;

포인터를 만들때 *를 붙이듯이 &를 붙여 참조자를 만들 수 있다.

 

레퍼런스는 누구의 별명이 될 것인지 지정해야한다.

레퍼런스 같은 경우에는 다음과 같은 코드가 불가능하다.

 

int& another_a;

누구의 별명이 될 것인지 지정되지 않았기 때문 반면에 포인터는

 

int* p;

이런 코드가 가능하다.

 

또 레퍼런스는 별명이 지정되면 다른 별명이 될 수 없다.

레퍼런스는 메모리 상에 존재하지 않을 수도 있다.

 

https://modoocode.com/141

 

씹어먹는 C++ - <2. C++ 참조자(레퍼런스)의 도입>

 

modoocode.com

이 부분 내용이 긴만큼 어려운 것 같다.

 

 

new 와 delete

C언어에서 maclloc과 free를 new와 delete로 대체하여 사용할 수 있다.

다른 강의도 참고했다.

 

https://youtu.be/yOiBxEfYU9E

동적 할당 : 프로그램 실행 중에 변수를 메모리에 할당하는 것

원할때 메모리에 값을 할당 가능.

 

int* a = new int(5);

new는 연산자이다.

new의 역할 : 주소값을 반환

 

위 코드는 메모리에 특정 위치에 int 5를 할당하고 이 것은 이름도 없고 주소 값만 존재.

이 주소 값을 포인터로 넘겨줌.

 

delete 를 통해 해제해줘야함.

 

#include <iostream>
using namespace std;

int main() {
	int* a = new int(5);

	cout << a << endl;
	cout << *a << endl;
	
	*a = 10;

	cout << a << endl;
	cout << *a << endl;

	delete a;
}

작성된 코드

 

배열의 동적 할당

배열을 동적 할당하는 경우가 매우 많다.

 

#include <iostream>
using namespace std;

int main() {
	int* arr;
	int len;

	cout << "동적 할당 할 배열 길이 입력 : ";
	cin >> len;

	arr = new int[len];

	for (int i = 0; i < len; i++) {
		arr[i] = i;
	}
	for (int i = 0; i < len; i++) {
		cout << arr[i] << endl;
	}

	delete[] arr;
}

배열을 해제할때는 delete[]를 이용해준다.

 

이 강의는 여기까지 정리하고 씹어먹는 C++에서 객체 내용을 정리한 후에

객체의 동적할당 내용을 적으려고 한다.

 


씹어먹는 C++ 4-1. 객체

객체란, 변수들과 참고 자료들로 이루어진 소프트웨어 덩어리

 

추상화

객체를 만들기 위해 추상화(abstraction)라는 과정이 필요

현실의 무언가를 옮길때 그에 맞게 설정하는 것을 추상화라고 한다.

 

객체의 변수나 함수들을 인스턴스 변수(instance variable)와 인스턴스 메소드(instance method)라고 한다.

 

캡슐화

객체내의 값을 직접적으로 조절하지 못하게 하고 인스턴스 메소드를 이용해서 간접적으로 조절하는 것을

캡슐화(Encapsulation)이라고 한다.

 

 

클래스

객체의 설계도가 되는 클래스가 있다.

이 클래스(class)를 이용해서 만든 객체를 인스턴스(instance)라고 한다.

 

#include <iostream>
using namespace std;

class Animal {
private:
	int food;
	int weight;
public:
	void set_animal(int _food, int _weight) {
		food = _food;
		weight = _weight;
	}
	void increase_food(int inc) {
		food += inc;
		weight += (inc / 3);
	}
	void view_stat() {
		cout << "이 동물의 food : " << food << endl;
		cout << "이 동물의 weight : " << weight << endl;
	}
}; // 세미콜론 빼먹지 않기!

int main() {
	Animal animal1;
	animal1.set_animal(100, 50);
	animal1.increase_food(30);

	animal1.view_stat();
}

만들어본 Animal 객체

캡슐화를 이용해 food와 weight를 직접적으로 조절이 불가능하도록 해준다.

 

클래스 상에서 존재하는 변수나 함수를

멤버 변수(member variable)과 멤버 함수(member function)이라고 부른다.

 

접근 지시자

접근 지시자를 이용해서 어떤 멤버들을 접근시킬지 지시해준다.

private 안의 내용은 객체 안에서만 접근 가능

 

public 키워드는 main함수에도 이용할 수 있듯이 마음대로 접근 가능하다.

키워드 명시를 하지 않았다면 기본적으로 private로 설정된다.

 

4-2. 함수의 오버로딩, 생성자

함수의 오버로딩 (Overloading)

먼저 오버로드란 무엇일까?

그 뜻은 과적하다, 너무 많이 주다, 과부하가 걸리게 하다. 이런뜻이 있다.

 

C언어 에서는 하나의 이름을 가지는 함수는 딱 1개만 존재할 수 밖에 없다.

C++에서는 반면에 같은 이름을 가진 함수가 여러개 존재해도 된다.

 

이를 구별하는 방법은 함수를 호출했을 때 사용하는 인자를 보고 결정하게 된다.

 

#include <iostream>
using namespace std;

void print(int x) { cout << "int : " << x << endl; }
void print(char x) { cout << "char : " << x << endl; }
void print(double x) { cout << "double : " << x << endl; }

int main() {
	int a = 1;
	char b = 't';
	double c = 3.1f;

	print(a);
	print(b);
	print(c);
}

같은 이름의 함수가 3개 이지만 인자의 따라 다른 결과가 나타난다.

자료형에 따라 다른 결과가 만들어진다.

 

#include <iostream>
using namespace std;

void print(int x) { cout << "int : " << x << endl; }
//void print(char x) { cout << "char : " << x << endl; }
void print(double x) { cout << "double : " << x << endl; }

int main() {
	int a = 1;
	char b = 't';
	double c = 3.1f;

	print(a);
	print(b);
	print(c);
}

만약에 2번째 print함수를 주석처리한다면 char형은 어떤 결과를 가질까?

실행해보면 int : 116으로 나오게 된다. 

정확히 일치하는 인자를 가지는 함수가 없다면 자신과 최대한 근접한 함수를 찾는다고 한다.

 

생성자 (Constructor)

생성자는 기본적으로 객체 생성시 자동으로 호출되는 함수이다.

생성자는 클래스 이름으로 만든 함수를 이용하면 된다.

 

https://modoocode.com/173

 

씹어먹는 C++ - <4 - 2. 클래스의 세계로 오신 것을 환영합니다. (함수의 오버로딩, 생성자)>

 

modoocode.com

글에 나온 Date 객체를 이용하면

 

class Date {
  int year_;
  int month_;  // 1 부터 12 까지.
  int day_;    // 1 부터 31 까지.

 public:
  void SetDate(int year, int month, int date);
  void AddDay(int inc);
  void AddMonth(int inc);
  void AddYear(int inc);

  // 해당 월의 총 일 수를 구한다.
  int GetCurrentMonthTotalDays(int year, int month);

  void ShowDate();

  Date(int year, int month, int day) {
    year_ = year;
    month_ = month;
    day_ = day;
  }
};

Date 객체 내부를 보면 Date라는 함수가 있는 것을 볼 수가 있다.

이를 이용해서 객체의 값을 생성과 동시에 정의해 줄 수 있다.

 

Date day(2011, 3, 1); // 암시적 방법 (implicit)
Date day = Date(2012, 3, 1); // 명시적 방법 (explicit)

2가지 방법이 있다.

 

디폴트 생성자 (Default Constructor)

만약 그냥 객체를 만들듯이 이런 코드를 써도 생성자가 호출될까?

Date day;

이런식으로 써도 생성자는 호출된다.

바로 디폴트 생성자가 호출된다.

클래스에서 어떤 생성자도 명시적으로 정의하지 않았을 경우에 자동으로 추가해주는 생성자.

 

디폴트 생성자를 정의할 수 도 있다.

class Date {
  int year_;
  int month_;  // 1 부터 12 까지.
  int day_;    // 1 부터 31 까지.

 public:
  void ShowDate();

  Date() {
    year_ = 2012;
    month_ = 7;
    day_ = 12;
  }
};

 

생성자 오버로딩

전에 쓴 함수의 오버로딩을 생성자에도 쓸 수 있다.

 

class Date {
  int year_;
  int month_;  // 1 부터 12 까지.
  int day_;    // 1 부터 31 까지.

 public:
  void ShowDate();

  Date() {
    std::cout << "기본 생성자 호출!" << std::endl;
    year_ = 2012;
    month_ = 7;
    day_ = 12;
  }

  Date(int year, int month, int day) {
    std::cout << "인자 3 개인 생성자 호출!" << std::endl;
    year_ = year;
    month_ = month;
    day_ = day;
  }
};

생성자를 오버로딩해서 초기화 값을 지정했을 경우에는 특정 값으로 초기화해주고

그렇지 않다면 디폴트 생성자를 이용하는 방식이다.

 


여기서 한 번 끊고 다른 글에 다음 내용은 정리해야겠다.

Comments