세상의 모든 것은 객체이다
TV, 의자, 책, 집, 카메라, 컴퓨터등... 모든 것은 객체이다.
객체는 캡슐화된다
캡슐화란?
객체의 본질적인 특성
객체를 캡슐로 싸서 그 내부를 보호하고 볼 수 없게 한다.
객체는 상태(state)와 행동(behavior)으로 구성된다
TV 객체 사례
상태
on/off 속성, 채널, 음량
행동
켜기, 끄기, 음량 줄이기, 채널 변경하기
C++ 클래스와 C++ 객체
클래스
- 객체를 만들어내기 위해 정의된 설계도, 틀
- 클래스는 객체가 아니다. 실체도 아니다.
- 클래스 내부에는 멤버변수와 멤버 함수를 선언할 수 있다.
객체
- 객체는 생성될 때 클래스의 모양을 그대로 가지고 탄생된다.
- 멤버변수와 멤버함수로 구성한다.
- 메모리에 생성되어 실체(instance)라고도 부른다.
- 하나의 클래스 틀에서 찍어낸 여러 개의 객체 생성 가능
- 객체들은 상호 별도의 공간에 생성된다.
C++ 클래스 만들기
클래스 작성
멤버변수와 멤버함수로 구성
클래스 선언부와 클래스 구현부로 구성된다.
클래스 선언부
class 키워드를 이용하여 클래스를 선언한다.
멤버변수와 멤버함수를 선언한다.
멤버에 대한 접근 권한 지정
- private, public, protected 중 하나를 선택한다.
- 디폴트는 private 이다.
- public은 다른 모든 클래스나 객체에서 멤버의 접근이 가능함을 표시
클래스 구현부
클래스에 정의된 모든 멤버 함수를 구현하는 부분이다.
이제 예제를 통해 알아보자.
#include <iostream>
using namespace std;
int a = 10;
void show() {
cout << "쇼" << endl;
}
class Circle {
public:
int radius;
double getArea();
};
double Circle::getArea() {
return 3.14 * radius * radius;
}
int main() {
Circle donut;
donut.radius = 1;
double area = donut.getArea();
cout << "donut 면적은 : " << area << endl;
return 0;
}
위 예제에서,
class Circle {
public:
int radius;
double getArea();
};
이 부분은 클래스 선언부이다.
double Circle::getArea() {
return 3.14 * radius * radius;
}
이 부분은 클래스 구현부이다.
getArea 라는 함수를 구현했다.
:: 은 범위지정 연산자로, 어떤 클래스의 함수인지 알려주는 역할을 한다.
비슷한 맥락으로 쓰이는 Rectangle class도 만들어보겠다.
#include <iostream>
using namespace std;
class Circle {
public:
int radius;
double getArea();
};
double Circle::getArea() {
return 3.14 * radius * radius;
}
class Rectangle {
public:
int width, height;
int getArea();
};
int Rectangle::getArea() {
return width * height;
}
int main() {
Circle donut;
donut.radius = 1;
double area = donut.getArea();
cout << "donut 면적은 : " << area << endl;
Rectangle rect;
rect.width = 3;
rect.height = 3;
cout << "사각형의 면적은 : " << rect.getArea() << endl;
return 0;
}
생성자(constructor)
- 객체가 생성되는 시점에서 자동으로 호출되는 멤버 함수
- 클래스 이름과 동일한 멤버 함수
객체가 생성될 때 객체가 필요한 초기화를 위해 생성자를 이용한다.
방금 한 예제를 다시 들고 와보자.
내가 donut 이 아니라 pizza 객체를 만들 것인데,
아까와 같이 선언하는 것이 아닌
Circle pizza(30);
이런 식으로 반지름의 길이를 매개변수로 해서 넘긴다고 가정해보자.
이렇게 된다면, 우리는 class 에 생성자를 추가해주어야한다.
class Circle {
public:
int radius;
Circle();
Circle(int r);
double getArea();
};
Circle::Circle() {
radius = 1;
}
Circle::Circle(int r) {
radius = r;
}
double Circle::getArea() {
return 3.14 * radius * radius;
}
위는 각각 클래스의 선언부와 구현부이다.
Circle(); 과 Circle(int r); 이 추가된 것을 확인할 수 있다.
클래스의 이름과 같은 생성자가 생성된 것이다.
생성자는 타입이 없는 형태로 구현부에 쓰면 된다.
Circle::Circle(int r){} 로 인해
pizza 객체가 만들어지는 순간 pizza 객체의 radius 는 넘겨지는 파라미터 값으로 초기화 된다.
이렇게 객체가 생성되는 시점에 자동으로 호출되어 객체를 초기화 시켜주는 함수를
생성자라고 칭한다.
소멸자
객체가 소멸되는 시점에서 자동으로 호출되는 함수이다.
오직 한번만 자동 호출되고, 임의로 호출할 수 없다.
객체 메모리 소멸 직전 호출된다.
소멸자는 객체가 사라질 때 마무리 작업을 위해 있다.
소멸자 함수의 이름은 클래스 이름 앞에 ~를 붙인다.
소멸자는 리턴타입이 없고, 어떤 값도 리턴하면 안된다.
소멸자는 한 클래스 내에 오직 한개만 존재한다.
class Rectangle {
public:
int width, height;
Rectangle();
Rectangle(int w);
Rectangle(int w, int h);
~Rectangle();
int getArea();
int getArea2();
bool isSquare();
};
Rectangle::~Rectangle() {
cout << "넓이가 " << getArea() << "인 나 이제 그만 사라진다" << endl;
}
소멸자는 위와 같이 이름 앞에 ~ 를 붙인다.
C++ 에서는 가장 나중에 생성된 객체가 가장 먼저 소멸된다.
class Rectangle {
public:
int width, height;
Rectangle();
Rectangle(int w);
Rectangle(int w, int h);
~Rectangle();
int getArea();
int getArea2();
bool isSquare();
};
Rectangle::Rectangle() {
width = 1;
height = 1;
}
Rectangle::Rectangle(int w) {
width = w;
height = w;
}
Rectangle::Rectangle(int w, int h) {
width = w;
height = h;
}
Rectangle::~Rectangle() {
cout << "넓이가 " << getArea() << "인 나 이제 그만 사라진다" << endl;
}
bool Rectangle::isSquare() {
if (width == height) {
cout << "넓이 : "<<getArea()<<" 둘레 : "<<getArea2()<<" ";
return true;
}
return false;
}
int Rectangle::getArea() {
return width * height;
}
int Rectangle::getArea2() {
return (width+height)*2;
}
int main() {
Rectangle rect1;
Rectangle rect2(3, 5);
Rectangle rect3(3);
if (rect1.isSquare()) cout << "rect1은 정사각형이다. 넓이 : " << rect1.getArea() << " 둘레 : " << rect1.getArea2() << endl;
if (rect2.isSquare()) cout << "rect2는 정사각형이다. 넓이 : " << rect2.getArea() << " 둘레 : " << rect2.getArea2() << endl;
if (rect3.isSquare()) cout << "rect3는 정사각형이다. 넓이 : " << rect2.getArea() << " 둘레 : " << rect3.getArea2() << endl;
}
위 코드의 결과는 아래와 같다.
인라인(inline) 함수
작은 크기의 함수를 호출하게 되면, 함수 실행 시간에 비해서
호출을 위해 소요되는 추가적인 시간 오버헤드가 상대적으로 커진다.
이를 위해 인라인 함수라는 개념이 등장했다.
inline 키워드로 선언된 함수이다.
인라인 함수를 호출하는 곳에 인라인 함수 코드를 확장해 삽입한다.
매크로와 유사한데, 코드 확장 후 인라인 함수는 사라진다.
인라인 함수를 호출하면,
함수 호출에 따른 오버헤드는 존재하지 않는다.
또한 프로그램의 실행 속도가 개선된다.
자주 호출되는 짧은 코드의 함수 호출에 대한 시간 소모를 줄일 수 있기 때문이다.
'Archive > Develop' 카테고리의 다른 글
[ CodeUp ] Python 함수 | 1526 번 풀이 (0) | 2021.03.24 |
---|---|
[ Django ] Django-bootstrap4 설치하기 (0) | 2021.03.24 |
[ Django ] DB 연동(makemigrations, migrate) (0) | 2021.03.22 |
Numpy 라이브러리 활용하기 (배열 연산) (0) | 2021.03.22 |
Numpy 라이브러리 활용하기 (숫자연산, 수학연산, 조건연산) | numpy 사인 코사인 (0) | 2021.03.22 |