본문 바로가기

전공 과목/C++

클래스와 생성자

C++ 클래스와 C++ 객체

C++에서 클래스란 객체를 정의하는 틀 혹은 설계또로서, 클래스에 맴버 변수와 멤버 함수를 선언한다. 클래스와 객체 관계는 붕어빵 틀과 붕어빵의 관계와 비슷하다. 붕어빵 틀은 C++ 클래스에, 붕어빵은 C++ 객체에 비유된다. C++ 객체는 C++ 클래스라는 틀에서 찍어내며, 멤버 변수 메모리와 멤버 함수 코드를 실제 가지고 C++ 프로그램이 실행되는 동안 실존하는 실체 혹은 인스턴스(instance)이다. 클래스는 컴파일이 끝나면 사라지지만, 프로그램은 실행중에 객체를 생성하여 멤버 변수에 값을 저장하기도 하고 멤버 함수 코드를 실행하기도 한다.

클래스 만들기

C++에서는 class 키워드를 이용하여 클래스를 선언한다. C++ 클래스는 C 언어의 구조체(struct)와 같이 개발자가 정의하는 새로운 데이터 타입이다. 

위의 그림은 원을 추상화한 Circle 클래스를 보여준다. Circle은 반지름 값을 가지는 radius 멤버 변수와 외부에 원의 면적은 값을 제공하는 getArea() 멤버 함수를 가지고 있다. 위의 그림에서 보이는 것처럼, 클래스는 일반적으로 클래스 선언부(class declaration)과 클래스 구현부(class imolementation)로 나누어 작성된다. 클래스 선언부는 class 키워드로 크래스의 모양을 선언하고, 클래스 구현부는 클래스의 멤버 함수들을 구현한다.

클래스 선언부

클래스는 class 키워드와 클래스 이름으로 선언한다

class Circle { // Circle 이름의 클래스 선언

}; //반드시 세미콜론(;)으로 종료

클래스 멤버

클래스의 멤버는 변수와 함수로 구성된다. 2011년도 C++ 표준부터 멤버 변수는 클래스 선언부에서 다음과 같이 초기화할 수 있다.

class Circle {
public:
	int radius = 5; // 클래스 선언부에서 멤버 변수를 초기화할 수 있음

};

멤버 함수는 원형 형태로 선언되며, 리턴 타입, 메개 변수 리스트 등이 모드 선언되어야 한다.

double getArea() ;

접근 지정자, public

클래스의 일부 멤버들을 다른 크래스와의 통신을 위해 외부에 공개하기도 한다. 멤버를 외부에 공개하려면, 다음과 같이 public 접근 지정다로 선언한다.

class Circle {
public: // 이하의 모든 멤버는 다른 접근 지정자가 선언될 때까지 public 접근 지정
};

접근 지정자가 선언되면, 다른 접근 지정자로 선언될 때까지 모든 멤버에 대해 적용된다. 접근 지정자는 public 외의 private, protected 등 총 3가지 종류가 있다. 그 중 public 접근 지정은 클래스 외부로부터의 접근을 허용한다는 뜻이다. 만일 멤버가 private으로 선언되었따면 외부에서 전혀 접근할 수가 없다. 접근 지정의 디폴트는 private으로, 아무 접근 지정이 없는 멤버는 private으로 처리도니다. protected 접근 지정은 상속 관계에서 적용되므로 나중에 다룬다.

클래스 구현부

클래스 구현부에서는 클래스 선언부에 선언되 멤버 함수의 코드를 구현한다.

2개의 콜론으로 만들어진 범위 지정 연산자(::)를 사용하여 클래스의 이름과 함께 멤버 함수를 기술한다. 이것은 같은 이름의 함수가 다른 클래스에 존재할 수 있기 때문이다.

Circle 클래스의 객체 생성

#include <iostream>
using namespace std;

class Circle {
public:
	int radius;
	double getArea();
};
 
double Circle::getArea() {
	return 3.14*radius*radius;
}

int main()
{
	Circle donut;
	donut.radius = 1; // 객체 donut 생성, donut 객체의 반지름을 1로 설정
	double area = donut.getArea(); // donut의 멤버 변수 접근, donut 객체의 면적 알아내기
	cout << "donut의 면적은 " << area << "입니다." << endl; // donut의 멤버 함수 호출

	Circle pizza;
	pizza.radius = 30;
	area = pizza.getArea();
	cout << "pizza의 면적은 " << area << "입니다." << endl;
	return 0;
}

객체의 멤버 접근

객체의 멤버에 접근하기 위해서는 다음과 같이 객체 이름 뒤에 .(점)을 찍고 그 뒤에 멤버를 쓴다.

donut.radius

이것은 C 언어에서 구조체의 필디를 활용하는 방법과 동일하다. 다음은 donut의 멤버 radius에 1을 쓰는 코드이며,

donut.radius = 1; // donut 객체의 radius 멤버에 1 기록

다음은 donut의 getArea() 멤버 함수를 호출하는 코드이다.

double area = donut.getArea(); /// donut 객체의 면적 알아내기

이 코드의 실행 겨로가 getArea()가 리턴한 값이 area에 저장된다. donut 객체는 main()에 의해 생성되었으므로 area 변수와 함께 main()의 스택에 존재된다.

#include <iostream>
using namespace std;

class Rectangle {
public:
	int width;
	int height;
	double getArea();
};

double Rectangle::getArea() {
	return width*height;
}

int main()
{
	Rectangle rect;
	rect.width = 3;
	rect.height = 5;
	cout << "사각형의 면적은 " << rect.getArea() << "입니다." << endl;
 
	return 0;
}

생성자

C++ 객체를 생성할 때 객체를 초기화할 수 있다. 클래스는 객체가 생성될 대 자동으로 실행되는 생성자(constructor)라는 특별한 멤버 함수를 통해 객체를 초기화한다. 한 클래스에 여러 개의 생성자를 둘 수 있으나, 이 중 하나만 실행된다.

생성자의 특징

생성자의 목적은 객체가 생성될 때 필요한 초기 작업을 위함이다.

예를 들어 멤버 변수의 값을 특정 박으로 설정하거나, 메모리를 동적 할당 받거나, 파일을 열거나 , 네트워크를 연결하는 등 객체를 사용하기 전에 필요한 조치를 할 수 있도록 하기 위함이다.

생서자 함수는 오직 한 번만 실행된다.

생성자 함수는 각 객체마다 객체가 생성되는 시점에 오직 한 번만 자동으로 실행된다.

생성자 함수의 이름은 클래스 이름과 동일하게 작성되어야 한다.

생성자 함수의 이름은 반드시 클래스 이름과 동일하게 작성되어야 한다. 이로 인해 생성자는 다른 멤버 함수와 쉽게 구분된다.

생성자 함수의 원형에 리턴 타입을 선언하지 않는다.

 

class Circle {
	Circle(); // 정상적인 생성자 선언, 리턴 타입 선언하지 않음
    void Circle(int r); // 컴파일 오류, 생성자는 리턴 타입 없음
    int Circle(double r); // 컴파일 오류, 생성자는 리턴 타입 없음
    
   };

생성자 함수는 함수 실행을 종료하기 위해 return 문을 사용할 수 있다. 그러나 어떤 값도 리턴하면 안된다.

Circle::Circle() {

	return; // 생성자 함수를 종료하는 정상적인 리턴문
}
Circle::Circle() {
	
    return 0; // 컴파일 오류, 생성자 함수는 값을 리턴해서는 안됨.

생성자는 중복 가능하다

생성자는 한 클래스에 여러 개 만들 수 있다. 물론 매개 변수 개수나 타입이 서로 다르게 선언되어야 한다.

Circle(); // 매개 변수 없는 생성자
Circle(int r); // 매개 변수 있는 생성자

여러 생성자를 작성 가능하게 하는 것은 사용하자 다양한 방법으로 객체를 새성하도록 함에 있다.

객체 생성과 생성자 실행

#include <iostream>

class Circle {
public:
	int radius;
	Circle(); // 기본 생성자
	Circle(int r); // 매개 변수 있는 생성자
	double getArea();
};

Circle::Circle() {
	radius = 1; // 반지름 값 초기화
	std::cout << "반지름 " << radius << " 원 생성" << std::endl;
}

Circle::Circle(int r)
{
	radius = r;
	std::cout << "반지름 " << radius << " 원 생성" << std::endl;
}

double Circle::getArea() {
	return 3.14*radius*radius;
}

int main() {
	Circle donut; // 매개 변수 없는 생성자 호출
	double area = donut.getArea();
	std::cout << "donut 면적은 " << area << std::endl;

	Circle pizza(30); // 매개 변수 있는 생성자 호출, 30이 r에 전달됨
	area = pizza.getArea();
	std::cout << "pizza 면적은 " << area << std::endl;
}

객체의 생성은 객체 크기의 공간을 할달한 후, 객체 내의 생성자 함수가 실행되는 과정으로 나누어진다. donut 객체와 pizza 객체는 서로 별도의 공간을 할당받고, radius 멤버 변수 역시 각 객체의 공간에 별도로 생성된다. 그러므로 dinut 객체의 Circle() 생성자는 donut의 radius 멤버를 1로 설정하며, pizza 객체의 Circle(int r) 생성자는 radius 멤버를 30으로 설정한다.

 

'전공 과목 > C++' 카테고리의 다른 글

위임 생성자  (0) 2019.09.22
C++의 입력과 문자열  (0) 2019.09.06
C++의 출력 cout  (0) 2019.09.03