본문 바로가기
프로그래밍 언어

객체지향 프로그래밍(OOP) 개념정리

by do_ng 2024. 1. 25.

1. Encapsulation(캡슐화)

 

데이터 또는 데이터를 활용하는 함수를 캡슐(클래스) 안에 두는 것

  • class라는 구조를 만들어서 데이터와 함수들을 정리
  • 접근 제어자를 사용함으로써 클래스 내에서만 사용되는 내부 작업을 위해 외부에서 함부로 접근하지 못하도록 제한하거나 내부에 있는 데이터를 외부에서 사용해야 되는 경우 그 데이터를 외부에 노출시키는 역할도 수행
class Entrepreneur {
private:
	string name;
	int stocks;
	string company;	

public:
	void setStocks(int value) {
		this->stocks = value;		
	}

	string getName() {
		return this->name;
	}

	// 생성자 함수 -> 객체가 만들어질 때 멤버 변수의 초기화를 담당
	Entrepreneur(string name, int stocks, string company) {
		this->name = name;
		this->stocks = stocks;
		this->company = company;
	}
};

int main() {
	Entrepreneur entre("ElonMusk", 1000, "TSLA");
	
	// entre.Stocks = 2000;
	entre.setStocks(200);
}

 

 

2. Inheritance(상속)

  • 기존의 클래스를 재사용할 수 있기 때문에 적은 양의 코드로 새로운 클래스를 만들 수 있음
  • 코드를 공통적으로 관리할 수 있기 때문에 코드의 추가 및 변경이 매우 용이함 

코드를 재사용하고 중복을 제거하게 되므로 여러 명의 개발자들이 대규모 프로그램을 만들 때 생산성이 좋아지고 개발이 끝난 이후에도 유지보수가 수월해짐

class Cat {
private:
	int full;
	int energy;
	bool isFull;

public:
	void setEnergy(int value) {
		this->energy = value;
	}

	bool getIsFull() {
		return isFull;
	}
	
	Cat(int full, int energy, bool isFull) {
		this->full = full;
		this->energy = energy;
		this->isFull = isFull;
	}
};

class NormalCat : Cat {
private:
	string feature = "아주 평범한 고양이";

public:
	NormalCat(int full, int energy, bool isFull) : Cat(full, energy, isFull) {
		// Cat(부모 생성자)를 호출 해서 부모 클래스의 멤버변수에 값 세팅		
	}
};

class FatCat : Cat {
private:
	string feature = "속도가 매우 느림";

public:
	FatCat(int full, int energy, bool isFull) : Cat(full, energy, isFull) {
		// Cat(부모 생성자)를 호출 해서 부모 클래스의 멤버변수에 값 세팅		
	}
};

int main() {
	NormalCat noramlCat(50, 0, false);

	FatCat fatCat(100, 0, false);
}

 

Cat을 종류별로 만들어야 한다고 가정했을 때, 

Cat 조상 클래스를 만든다음 공통적인 것들은 조상 클래스에 넣어두고 Cat 종류별로 클래스를 만든 다음 조상 클래스를 상속받으면 공통된 특징들은 이미 추가되어있기 때문에 Cat 종류에 따른 특징들만 구현해 주면 된다. 

새로운 cat 종류가 추가된다 하더라도 조상인 Cat 클래스를 상속받으면 공통적인 부분들은 이미 만들어져 있기 때문에 생산성이 빨라지고 Cat의 공통적인 특징 중 하나가 수정되어야 하는 경우에도 조상 클래스만 수정하면 되기 때문에 반복적인 작업이 줄게 되므로 효율적이다. 

 

3. Polymorphism(다형성)

다형성이란 하나의 메소드나 클래스가 있을 때 이것들이 다양한 방법으로 동작하는 것을 의미한다.

예시를 들자면 한국인이든 영국인이든 "인사"라는 방식은 똑같은데 안녕하세요, Hello 같이 다른 방법으로 표현됨

 

코드적으로 디테일하게 말하자면 조상클래스 타입의 참조변수로 자식클래스의 인스턴스를 다루는 것이라고 할 수 있다.

// 기본 클래스 정의
class Shape {
public:	
	virtual void draw() const {
		std::cout << "기본 도형을 그립니다." << std::endl;
	}
};

// 파생 클래스 1 정의
class Circle : public Shape {
public:	
	void draw() const override {
		std::cout << "원을 그립니다." << std::endl;
	}	
};

// 파생 클래스 2 정의
class Square : public Shape {
public:	
	void draw() const override {
		std::cout << "사각형을 그립니다." << std::endl;
	}
};


int main() {
	// 기본 클래스 포인터를 사용하여 Circle 객체 생성
	Shape* shapePtr1 = new Circle();
	shapePtr1->draw();

	// 기본 클래스 포인터를 사용하여 Square 객체 생성
	Shape* shapePtr2 = new Square();
	shapePtr2->draw();
}

인스턴스의 타입과 참조변수의 타입이 일치하는 것이 보통이지만, 서로 상속관계에 있을 경우 조상 클래스 타입의 참조변수로 자식(파생)클래스의 인스턴스를 참조하도록 하는 것도 가능하다. 

조상타입의 참조변수로 자식 클래스에 새롭게 추가된 기능들은 사용이 불가능하고 조상 클래스에 있는 기능들만 사용가능 하다. 

"draw" 기능은 자식 클래스에 따라서 Overriding(재정의) 되었기 때문에 조상타입의 참조변수로 호출해도 자식 클래스에 구현된 기능이 실행된다. 

 

Q1) 인스턴스를 같은 타입의 참조변수로 참조하는 것과 조상타입의 참조변수로 참조하는 것이 어떤 차이가 있는가?

조상타입의 참조변수로 자식 인스턴스를 참조하게 되면 자식에 새롭게 추가된 멤버 또는 기능들은 사용하지 못하는데 왜? 조상타입의 참조변수로 자식 인스턴스를 참조할 수 있게끔 설계했을까? 

 

 

 

 

4. Abstraction(추상화)

차량을 운전할 때 이를 위한 인터페이스(휠, 페달, ..등)를 사용하는데 휠이나 페달 등의 구현 세부 정보는 노출되어 있지 않음 운전자는 브레이크나 엔진이 어떻게 작동하는지의 세부 사항을 몰라도 차를 운전할 수 있다. 

 

 

'프로그래밍 언어' 카테고리의 다른 글

C# 상수와 열거형  (0) 2024.02.29
C# reflection  (0) 2024.02.28
C# Delegate(대리자)  (0) 2023.11.10
연결 리스트(C++)  (0) 2023.08.29
행맨  (0) 2022.05.25