★Object Oriented Programming★
ㅁ 객체지향 언어
추상화, 캡슐화, 상속, 다형성을 사용하여 유연성과 모듈성, 명료함 재사용성을 제공하는 부가된 특징을 가지고 있는 강력한 절차형 언어
- 모든 객체의 속성과 행동을 결합시킴으로써 실제 세계를 반영하는 방법으로 프로그램 구성
- 객체의 관점에서 생각하고, 프로그램은 상호작용하는 객체들의 모임으로 볼 수 있음
ㅁ 객체
명확히 확인이 가능한 실제 세계에서의 존재물을 대표하는 것. 책상, 원, 대여 등
- 객체는 자신만의 특성과 상태, 행동을 갖는다.
* 상태(정적) : 현재 값을 가지고 있는 데이터 필드(= 속성)에 의해 표현됨 → 변수
* 행동(동적) : 일련의 함수에 의해 정의된다. 객체에 대한 함수를 호출하는 것은 객체에게 어떤 일을 수행하도록 요구하는 것 → 함수
** 예) 원 객체 : 상태-radius,행동-getArea()
→ 객체는 상태와 행동 모두를 가짐
→ 상태는 객체 자체를 정의하고, 행동은 객체가 무엇을 할 것인지를 정의하는 것이다.
ㅇ 클래스와 객체
- 클래스 : 객체의 데이터와 함수가 무엇이 될지를 결정하는 템플릿이며 설계도
- 객체 : 클래스의 인스턴스
→ 클래스의 여러 가지 인스턴스를 만듦 = 실체화
ㅇ 생성자
class Circle { // 클래스; 아직 객체 아님
public :
double radius; // 데이터필드(속성)
/* 생성자(오버로딩) */
Circle()
{ // 인수 없는 생성자
radius = 1;
}
Circle(double newRadius)
{ // 인수 있는 생성자
radius = newRadius;
}
/* 일반 함수 */
double getArea()
{
return radius * radius * 3.14159;
}
};
- 특별한 유형의 함수
- 새로운 객체가 생성될 때 호출됨
- 일반적으로 객체의 데이터 필드에 초기 값을 주는 초기화 과정을 수행하기 위해 설계됨
- 클래스 이름과 같음
- 여러 개의 생성자 사용 가능; 오버로딩
* 오버로딩을 통해 초기 데이터 값을 갖는 객체에 대해 쉽게 구성 가능
- 인수 없는 생성자 / 인수 있는 생성자
- 기본 생성자 : 인수 없는 생성자 + 비어 있는 바디 → 어떠한 생성자도 선언하지 않을 경우에만 자동적으로 주어짐
※ 일반함수와의 차이점
1. 생성자는 클래스와 같은 이름을 가짐
2. 생성자는 반환 값 유형을 가지지 않음 (void 주의)
3. 생성자는 객체가 생성될 때 호출된다. 객체를 초기화하는 역할.
※ 생성자 초기화 목록
생성자에서 필드를 초기화하는 작업만을 할 때는 다음과 같이 나타낼 수 있음
ClassName(parameterList) : datafield1(value1), datafield(value2)
{
// 생성자가 할 일
}
ㅇ 객체이름
- 객체 생성시 이름 할당할 가능
- 객체 생성시 생성자가 호출됨 (객체 생성 = 생성자 호출)
→ 따라서 객체 생성시 생성자를 이용할 수 있음
* 인수 없는 생성자 → 클래스명 변수명()
* 인수 있는 생성자 → 클래스명 변수명(인수);
- 객체 이름으로 접근 가능!
* .을 이용하여 데이터 접근 및 함수 호출
int main()
{
// 다른 데이터 필드. 같은 함수 공유
Circle circle1; // 인수없는 생성자
Circle circle2(5.0); // 인수있는 생성자
// circle1의 radius와 getArea()값 출력
cout << "Radius: " << circle1.radius <<" Area: " << circle1.getArea();
// circle2의 radius를 100으로 변경하고
circle2.radius=100;
// radius와 getArea 값 출력
cout << "Radius: " << circle2.radius <<" Area: " << circle2.getArea();
return 0;
}
* 객체 복사 : circle1 = circle2
- 복사 후에도 여전히 두 개의 객체(함수는 계속해서 공유)
* 익명객체 : 종종 객체를 생성하고 단지 한 번만 객체를 사용하는 경우(객체가 후에 참조되지 않을 때) 이름없이 사용
- 클래스명(), 클래스명(인수) // circle1= Circle(5);
* 클래스 멤버로서 데이터 필드를 선언할 때는 초기화가 불가, 생성자에서만 초기화 가능!
* 객체의 배열
- 일반 변수와 같음, 단지 객체단위일 뿐
Circle circleArray[10];
Circle circleArray[3] = {Circle(3), Circle(4), Circle(5)}; // 인수있는 생성자로 배열 초기화
ㅁ 헤더파일 분리 선언
- 같은 파일 안에서 main 함수와 함께 클래스를 선언하면 다른 프로그램에서는 이들 클래스를 사용할 수 없게 됨
- 클래스를 재사용하기 위해서 분리된 헤더파일 선언!
ㅇ 클래스 선언 (.h)
클래스 안에 어떤 데이터와 함수가 있는지를 컴파일러에게 알려주는 것
- 모든 데이터 필드, 생성자 원형, 함수 원형 선언
/* Circle.h 헤더 */
class Circle
{
public :
// 멤버변수
double radius;
// 생성자
Circle() ;
Circle(double);
// 멤버함수
double getArea();
};
<circle.h>
ㅇ 클래스 구현(.cpp)
함수가 어떻게 동작하는 지를 컴파일러에게 알려주는 것
- 생성자와 함수도 구현
#include "Circle.h" // 헤더포함
// 생성자; 멤버변수 초기화
Circle::Circle() {
radius = 1;
}
Circle::Circle(double newRadius) {
radius= newRadius;
}
double Circle::getArea() {
// 멤버함수 구현
return radius* radius * 3.14159;
};
<circle.cpp>
/* 메인함수 */
#include <iostream>
#include "Circle.h"
using namespace std;
int main() {
Circle circle1;
Circle circle2(5.0);
...
return 0;
}
<TestCircleWithDeclaration.cpp (client)>
ㅇ 이항영역결정연산자
- Triangle::getArea() : Triangle 클래스에 정의되어있는 getArea()
ㅇ 포인터를 사용한 객체 멤버 접근
Circle circle1;
Circle *pCircle = &circle1; 인 경우
- circle1.radius / (*pCircle).radius / pCircle -> radius와 같이 접근 가능
* 힙에서의 동적 객체 생성
- 스택 안에서 생성된 객체는 함수가 반환될 때 스택에서 삭제됨
- 함수가 반환될 때 객체를 남겨놓기 위해서는 힙에 동적으로 생성해야 함(new연산자 사용)
ClassName *pObject = new ClassName();
ClassName *pObject = new ClassName(인수);
- 동적으로 할당한 객체를 확실하게 삭제하기 위해서는 delete연산자
delete pObejct;
ㅇ 데이터 캡슐화
- public은 직접 수정이 가능
예) cricle1.radius=5;
→ 데이터가 함부로 수정될 수 있음
→ 클래스를 유지하기 어렵게 하고 버그도 발생하기 쉽게 만듦
→ 데이터필드 캡슐화 : 속성에 대한 직접적인 수정을 피하기 위해 private 접근지시자 사용!
* public : 모든 데이터 필드, 생성자, 함수가 클래스의 객체로부터 접근될 수 있다는 것을 나타냄(↔ private)
* private : 클래스 밖에서는 직접 참조를 통하여 접근할 수 없음
- get함수(게터, 접근자) : 해당 변수를 호출하는 함수
- set함수(세터, 변경자) : 변수를 직접 수정하는 변수
class Circle
{
public :
Circle();
Circle(double);
double getArea();
double getRadius();
void setRadius();
// private으로 선언하여 데이터 캡슐화
private :
double radius;
};
<circle.h>
#include "Circle.h"
Circle::Circle()
{
radius = 1;
}
Circle::Circle(double newRadius)
{
radius= newRadius;
}
double Circle::getArea()
{
return radius* radius * 3.14159;
}
double Circle::getRadius()
{
return raidus;
}
void Circle::setRadius(double newRadius)
{
radius =(newRadius >=0) ? newRadius :0;
}
<circle.cpp>
#include <iostream>
#include "Circle.h"
using namespace std;
int main()
{
Circle circle1;
Circle circle2(5.0);
// radius가 private으로 선언되었으므로
// set함수를 이용하여 radius를 100으로 변경해야함
circle2.setRadius(100);
// radius와 getArea 값 출력
cout<< "Radius : " << circle2.getRadius << " Area: " << circle2.getArea();
return 0;
}
<TestCircleWithDeclaration.cpp (client)>
ㅇ this 포인터
숨겨진 데이터 필드를 호출 개체로 참조할 수 있도록 특별히 제작된 포인터
Circle::Circle(double radius)
{
// private인 radius 접근
this->radius = radius;
(*this).radius = radius; // 동일 표현
}
ㅇ 객체를 함수로 전달하는 법
1) 값에 의한 전달
2) 참조에 의한 전달
3) 포인터를 통한 참조에 의한 전달
'컴퓨터공학과 > Programming' 카테고리의 다른 글
[C++]최대공약수 구하기(3가지 방법, 유클리드 호제법) (0) | 2020.05.05 |
---|---|
[C++] 누구나 쉽게, 리팩토링(클린코드)-⑤ NULL체크를 위한 널 객체 (0) | 2020.04.18 |
[C++] 누구나 쉽게, 리팩토링(클린코드)-④ 상속 (개념과 특징) (0) | 2020.04.13 |
[C++] 누구나 쉽게, 리팩토링(클린코드)-③ 캐스팅/형변환 종류 및 방법 (0) | 2020.04.08 |
[C++] 누구나 쉽게, 리팩토링(클린코드)-② 인터페이스 (1) | 2020.04.07 |