일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- meta table
- lua for windows
- QT TCP
- 엑스퍼트생일축하해
- C++ API
- object
- C API
- 프리미어 영상저장
- 월세
- 티몬삼겹살데이
- file open
- Lua
- lua setup
- TCP/IP
- FILE TRANSFER
- #신혼부부 #결혼준비 #신혼부부희망타운신혼부부특별공급
- 엑스퍼트2주년
- 중소규모택지
- QTcpServer
- file write
- #부동산전자거래 #부동산전자계약 #부동산계약 #부동산전자계약방법 #부동산전자계약하는법 #부동산계약방법 #부동산중개수수료 #부동산중개수수료아끼기 #부동산복비아끼기
- 국토교통부
- 프리미어 영상변환
- lua install
- 수도권주택공급
- 찾다죽는줄
- 청량리역한양수자인192
- lua interpreter
- file read
- 등록임대주택
- Today
- Total
Value Creator의 IT(프로그래밍 / 전자제품)
#3 [C++] 생성자, 소멸자, 접근지정자 본문
#생성자란?
공을 만드는 기계로 예를 든다. 어떤 공을 만드는 기계가 있는데 이 기계는 페인트를 넣으면 그 페인트에 해당하는 색깔의 공이 생산된다. 페인트를 넣지 않는다면 기본적인 흰공이 생산된다.
이와 같은 개념으로 클래스(class)는 객체가 생성될 때 자동으로 실행되는 생성자(constructor)라는 특정 멤버 함수를 통해 객체를 초기화시켜 여러 기능을 수행한다.
앞서 했던 원(Circle) 클래스로 예를 든다.
#ifndef CIRCLE_H
#define CIRCLE_H
#include<iostream>
using namespace std;
class Circle
{
double pi = 3.14;
public:
Circle() { radius = 1; }//생성자 1
Circle(int r) { radius = r;}//생성자 2
int radius;
double getArea();
};
#endif
우선 생성자란 객체가 생성 되었을 때 필요한 초기 작업을 위해서이다.
특징으로는 생성자 함수는 각 객체마다 객체가 생성되는 시점에 오직 한번만 자동으로 실행 된다는 것이다.
그리고 생성자는 함수의 클래스 이름과 동일하게 작성되어야한다. 그렇지 않을 시에는 생성자로 인식하지 않는다.
또한 생성자는 함수의 원형에 리턴타입을 선언하면 안된다.
생성자는 함수이지만 리턴타입을 설정하지 않는다.
위와같이 Circle();이런식으로 만들어야지, 앞에 void Circle(); 이런식이던가 int Circle();이런 식으로 리턴타입을 설정하면
컴파일 오류가 발생한다.
생성자는 중복 가능하다.
위의 생성자 1과 생성자 2와 같이 생성자는 중복이 가능하다.
다만 생성자가 객체로서 생성될때 중복실행되지 않기 때문에 매개변수나 타입이 서로 다르게 선언되어야 한다.
위의 생성자 1은 매개변수가 없는 생성자, 즉 아무것도 입력되어 있지 않는 기본 생성자이다.
생성자 2는 매개변수가 있는 생성자이다.
이것을 메인 함수로서 구현하면 아래와 같은 결과가 나온다.
#include"Circle.h"
int main()
{
Circle pizza;
pizza.radius = 3;
double area = pizza.getArea();
cout << "pizza 면적은" << area << endl;
cout << "Circle : " << Circle().getArea() << " : 기본생성자 입니다." << endl;
cout << "Circle(9) : " << Circle(9).getArea() << " : 매개변수가 있는 생성자입니다." << endl;
}
Circle()과 Circle(9)는 위와 같이 작동된다.
이것을 Circle donut, Circle candy(9)로 선언하여 작동시키면 마찬가지의 결과가 나온다.
생성자는 꼭 있어야만 한다. 하지만 전에 앞서 만들었던 Circle(원)클래스는 생성자가 없었다. 그럼에도 컴파일 에러가 없이 잘 호출되었다. 그 이유는 기본생성자가 없는 클래스에서는 컴파일러가 자동적으로 기본 생성자를 만들어 삽입하고 그것을 호출하도록 되어있기 때문이다.
하지만 기본생성자를 자동으로 생성해준다 하여도 위의 생성자 1과 같이 {radius = 1;}이런 설정이 없기 때문에 따로 radius값이 설정되어있지 않을때 실행시키면 컴파일 에러가 난다. 헤더파일에서 기본적으로 radius값을 설정하지 않았기 때문이다.
또한 기본생성자를 만들지 않고 생성자 1,2 이렇게 2개 있는게 아니라 매개변수가 있는 생성자2만 만들었다고 가정했을때 Circle donut(9);는 문제없이 컴파일이 되지만 Circle donut;은 컴파일 에러가 난다.
생성자를 만들어 놨을 경우에는 자동으로 컴파일러가 생성자를 만들지 않는다.
이미 Circle(int r)이라는 생성자가 있기 때문이다.
그렇기에 매개 변수가 있는 생성자를 만들었을 경우, 매개변수가 없는 생성자, 즉 기본생성자를 만들도록 하자.
#소멸자란?
모든 것은시작이 있으면 끝이 있는 것과 같이, C++의 객체도 실행을 했으면 수행이 끝났을 시 없어진다. 즉 메모리가 반환된다.
객체생성시 생성자 함수가 실행되는 것처럼 객체 소멸시 소멸자 함수가 반드시 실행되는데 소멸자는 객체가 소멸되는 시점에서 자동으로 호출되는 클래스의 멤버함수다.
소멸자는 '~'에 '생성자의 이름'을 붙여 '~생성자'로 만들어진다. 소멸자는 만들지 않아도 자동으로 컴파일러가 만들어 자동으로 실행된다. 이때, 기본 소멸자는 아무것도 수행하지 않고 단순 리턴하도록 만들어준다.
그럼 자동으로 만들어주는데 왜 소멸자를 따로 만드는가의 생각이 든다.
그 이유는 객체가 소멸할 때, 동적으로 할당받은 메모리를 운영체제에게 돌려주거나, 소멸할 때 따로 그때마다 특정 기능을 수행하도록 만들기 위해서이다.
소멸자의 특징은 아래와 같다.
1. 소멸자는 생성자와 같이 리턴타입이 없으며 어떤값도 리턴하지 않는다.
2. 소멸자는 생성자와 달리 오직 한개만 존재하며 매개 변수를 가지지 않는다.
3. 소멸자가 선언되어 있지 않으면 기본 소멸자가 자동으로 생성된다.(기능은 위에 설명과 같다.)
계속 만들었던 Circle 클래스로 예를 들어보자
#ifndef CIRCLE_H
#define CIRCLE_H
#include<iostream>
using namespace std;
class Circle
{
double pi = 3.14;
public:
Circle() { radius = 1; }//생성자 1
Circle(int r) { radius = r;}//생성자 2
~Circle() { cout << "반지름이 " << radius << "인 원의 소멸" << endl; }//소멸자와 그 기능 구현
int radius;
double getArea();
};
위의 소스에는 이제 '~Circle()'이라는 소멸자가 선언되었다.
그리고 그 기능으로는 반지름이 ~인 원의 소멸이다.
그리고 이것을 메인 함수에 실행시키기전에 설정해야되는 것이있다.
#include"Circle.h"
int main()
{
Circle pizza;
pizza.radius = 3;
double area = pizza.getArea();
cout << "pizza 면적은" << area << endl;
Circle donut, candy(9);
cout << "donut : " << donut.getArea() << " : 기본생성자 입니다." << endl;
cout << "candy(9) : " << candy.getArea() << " : 매개변수가 있는 생성자입니다." << endl;
return 0;//메인 함수의 종료.
}
메인함수의 종료 설정인 return 0;다.
소멸자는 메인함수가 종료되어야 실행되는 것이라 위와같이 return 0를 선언해 주어야한다.
그렇다면 결과는 아래와 같다.
따로 호출을 하지 않아도 자동으로 실행되는 것을 알수 있다.
주목할 점은 이곳에서 소멸자의 실행 순서이다.
소멸자는 생성자와는 반대의 순서를 지닌다.
함수를 실행할때, 반지름이 3인 pizza가 먼저 생성되고, 그다음 기본생성자 1인 donut, 그다음 반지름이 9인 candy가 생성되었다.
즉 pizza>>donut>>candy 순으로 생성되었기 때문에
candy>>donut>>pizza순으로 소멸이 진행된것이다.
이것은 지역객체와 전역객체에서도 적용이된다.
메인함수가 실행될때 전역객체부터 생성한뒤 그다음 지역객체를 생성하기 때문에 지역객체를 소멸한뒤 전역객체를 소멸한다.
#접근 지정자
접근지정자로는 아래와 같은 3가지의 종류가 있다.
private - 비공개
public - 공개
protected - 보호
이것은 멤버에 대한 접근 지정인데 설정하는 방법은 클래스 내부에서 선언할때
해당 접근지정자 다음 ' : '를 찍으면 된다.
class example
{
private:
//클래스 내의 멤버함수만이 접근가능
public:
//클래스 내외 모든 함수에서 접근가능
protected:
//클래스 내의 멤버와 상속받은 파생 클래스에서만 접근가능
}
참고로 별도로 접근지정을 설정하지 않을 경우의 기본 접근 지정은 private으로 선언된다. 이것은 캡슐화의 기본 원칙이 비공개이기 떄문이다.
따라서 앞서 만든 Circle클래스에서 따로 설정안한 int radius는 private멤버로 설정되었다고 보면된다.
클래스를 만들 때 변수의 멤버는 private로 지정하는 것이 제일 바람직하다. public으로 할 경우 짤때는 편하겠다만 여기저기서 마음대로 접근해서 수정할 수 있기 때문에 보안상의 문제가 생긴다. 그렇기 때문에 자주 수정되지 않거나 중요한 경우, 또는 수정되지 않기를 바라는 변수들은 private로 설정하는 것이 좋다.
예를 들면 원을 구하는 클래스에서 모든 원의 원주율은 3.14로 같다. 그렇다면 이 원주율은 private로 설정해 보호하는 것이 좋다.
반면에 생성자는 무조건 public으로 선언해야한다.
private는 클래스 외부에서 수정을 막는 접근지정자인데 그렇게 되면 외부에서 객체를 생성할 수 없기 때문이다. 따라서 외부에서 객체를 생성하기 위해서는 public으로 선언해야한다.
하지만 그렇다고 무조건 public만으로 선언하지는 않는다. 떄에 따라서는 외부에서 객체를 생성할 수 없게 하기 위해 private로 선언하기도 하며 자식 클래스에서만 생성자를 호출하도록 protected로 선언하기도 한다.
'1. 프로그래밍 > 5) C++' 카테고리의 다른 글
#6 [C++] 예제 : RAM 구현해보기 (0) | 2019.07.26 |
---|---|
#5 [C++] 예제 : 랜덤 정수 10개 생성 클래스 만들기 (0) | 2019.07.26 |
#4 [C++] 구조체, 객체 포인터, 객체 배열 (0) | 2019.07.26 |
#2 클래스 생성 예제 (0) | 2019.07.24 |
#1 C++ 기초(객체지향, 캡슐화, 상속성, 다형성) (0) | 2019.07.24 |