← 블로그 목록

[Study Note] C++ 객체지향

@jinlee0310
  • #Study
목차

TL; DR

이 글은 씹어먹는 C++ 4-1, 4-2를 정리 및 요약한 글입니다.


프로그래밍 언어는 처음에는 절차지향으로 시작되었다. 하지만 프로그램의 크기가 예전보다 거대해지면서 새로운 패러다임이 필요하게 되었는데 객체 지향 언어이다.

객체지향 프로그래밍

객체란?

객체는 다음과 같이 정의된다.

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

객체가 현실세계에서 존재하는 것들을 나타내기 위해서는 추상화라는 과정이 필요하다. 컴퓨터상에서 현실 세계를 100% 나타낼 수 없기 때문에 적절하게 컴퓨터에서 처리할 수 있도록 바꾼다. 어떠한 객체는 자기만의 정보를 나타내는 변수들과 이를 가지고 어떠한 작업을 하는 함수들로 둘러싸고 있다. 이러한 객체의 변수나 함수들을 인스턴스 변수(instance variable), 인스턴스 메소드(instance method)라고 한다.

캡슐화

Animal animal;

animal.food+=100; // 불가능
animal.increase_food(100); // 가능

위와 같이 인스턴스 변수에 직접 접근하는 것은 불가능하고 인스턴스 함수를 통해 값을 조절하는 것을 캡슐화라고 한다. 이 개념을 처음 들었을 때는 나도, 저자도 왜 필요하지? 라고 생각했다. 그런데 캡슐화의 장점은 객체가 내부적으로 어떻게 작동하는지 몰라도 사용할 줄 알게 된다라고 볼 수 있다. increase_food를 했을 때 객체 내부의 다른 변수들이 자동으로 조작되는 설계가 가능하다는 의미이다.

클래스

C++에서 객체를 만들 수 있는 장치가 있다. 객체의 설계도라고 볼 수 있는데 클래스이다. 그리고 클래스를 이용해 만든 객체를 인스턴스(instance)라고 한다.

#include <iostream>

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(){
			std::cout << "food: " << food << std::endl;
			std::cout << "weihgt: " << weight << std::endl;
		}
};

int main(){
	Animal animal;
	animal.setAnimal(100,50);
	animal.increase_food(30);
	
	animal.view_stat();
	return 0;
}

food: 130 weight: 60

Animal animal;

구조체의 경우 struct를 명시해줘야 하는데 객체는 Animal animal;이라고만 적어줘도 된다.

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(){
			std::cout << "food: " << food << std::endl;
			std::cout << "weihgt: " << weight << std::endl;
		}
};

Animal 안에는 food, weight라는 변수가 있고 set_animal, increase_food, view_stat이라는 멤버 변수, 멤버 함수가 있다.

private 키워드는 접근 지시자이다. private은 외부에서 접근할 수 없다. main에서 animal.food=100을 실행한다면 컴파일 오류가 생긴다. public 키워드는 외부에서 접근 가능하다. 키워드를 명시하지 않으면 private으로 설정된다.

생성자 함수의 오버로딩

함수의 오버로딩

C++에서는 같은 이름을 가진 함수가 여러개 존재해도 된다. 같은 이름의 함수를 호출했을 때 구분하는 법은 사용하는 인자를 보는 것이다.

#include <iostream>

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

int main(){
	int a = 1;
	char b = 'c';
	double c = 3.2f;
	
	print(a);
	print(b);
	print(c);
	
	return 0;
}

int: 1 char: c double: 3.2

C++에서는 함수 이름이 같아도 인자가 다르면 다른 함수 취급을 하게 되어 오류가 생기지 않는다. 함수를 오버로딩 하는 과정은 다음과 같다.

  1. 자신과 타입이 정확히 일치하는 함수를 찾는다.
  2. 정확히 일치하는 타입이 없는 경우 형변환을 통해 일치하는 함수를 찾는다.
    • char, unsigned char, short -> int
    • unsigned hsart -> int, unsigned int
    • float -> double
    • enum -> int
  3. 위와 같이 변환해도 일치하는 것이 없다면 좀더 포괄적인 형변환을 통해 일치하는 함수를 찾는다.
    • 임의의 숫자 타입은 다른 숫자 타입으로 변환
    • enum은 임의의 숫자 타입으로 변환
    • 0은 포인터 타입이나 숫자 타입
    • 포인터는 void 포인터로 변환
  4. 유저 정의된 타입 변환으로 일치하는 것을 찾는다.
  5. 일치하는 함수를 찾을 수 없거나 두개 이상 일치하는 경우에 ambiguous 오류가 난다.

오버로딩 규칙을 숙지하는 것은 매우 중요하다.

그리고 일반적으로 함수 정의는 클래스 외부에서 한다.

생성자

생성자는 기본적으로 객체 생성시 자동으로 호출되는 함수라고 할 수 있다. 이 때 자동으로 호출되면서 객체를 초기화 해주는 역할을 담당하게 된다. 생성자는 아래와 같이 정의한다.

/*클래스 이름*/(/* 인자 */){}

이렇게 정의된 생성자는 객체를 생성할 때 생성자를 호출하며 객체를 생성할 수 있게 된다.

디폴트 생성자

클래스를 정의할 때 생성자를 명시적으로 정의하지 않았다면 컴파일러가 디폴트 생성자를 자동으로 추가해준다.

#include <iostream>

class Date{
	int year_;
	int month_;
	int day_;
	
	public:
		void ShowDate();
	
	Date(){
		year_ = 2012;
		month_ = 7;
		day_ = 12;
	}
};

void Date::ShowDate(){
	std::cout << "year: " << year_ << endl;
}

int main(){
	Date day=Date();
	Date day2;
	
	day.ShowDate(); // year: 2012
	day2.ShowDate(); // year: 2012
}

이렇게 인자가 없는 생성자를 정의해주더라도 값을 초기화 할 수 있는 생성자를 정의할 수 있다.

명시적으로 디폴트 생성자 사용하기

class Test{
	public:
		Test() = default; // 디폴트 생성자를 정의해라
}

생성자의 선언 바로 뒤에 Test의 디폴트 생성자를 정의하라고 컴파일러에게 명시적으로 알려줄 수 있다.

생성자 오버로딩

생성자 역시 함수이기 때문에 오버로딩을 사용할 수 있다.

#include <iostream>

class Date{
	int year_;
	int month_;
	int day_;
	
	public:
		void ShowDate();
	
	Date(){
		year_ = 2012;
		month_ = 7;
		day_ = 12;
	}
	
	Date(int year, int month, int day){
		year_ = year;
		month_ = month;
		day_ = day;
	}
};

댓글

Discussion 원문