원래는 <sstream>
을 포스팅할 예정이었지만, 순서를 조금 바꿨다.
왜 클래스를 사용하는지 수업을 들으면서 생각해봤다. 클래스는 구조체랑 다르다. 가장 큰 차이를 뽑자면 '정보 은닉'이다. 객체마다 정보를 숨기고 드러내면서 서로 얽힌다. 구조체는 멤버 데이터를 전부 드러내지만, 클래스는 일부만 드러낸다. 이는 동작을 이해하기 쉬워진다.
Feature | struct | class |
---|---|---|
Default member access | Public | Private (by default) |
Inheritance | Only public inheritance | Public and private inheritance |
Semantics | Typically used for simpler data structures | Typically used for more complex data types with behavior |
Data representation | Can include data members and member functions | Can include data members, member functions, and operator overloads |
클래스를 보기 전에 객체와 클래스, 인스턴스의 차이를 볼 필요가 있다. 객체는 추상적인 모든 것, 이를테면 변수, 함수가 있다. 클래스는 객체를 '구성(혹은 디자인)'하기 위한 도구이다. 인스턴스는 객체가 코드 상에 실제로 나타난 것이다. 객체가 개념이라면 인스턴스는 실물로 생각할 수 있다. 하지만 흔히 객체와 인스턴스는 동의어로 사용한다. 앞으로도 객체와 인스턴스를 동일시할 예정이다.
C++에는 생성자가 있다. 객체가 선언(declare)되면 생성자가 객체를 찍어낸다. int a;
로 변수를 선언했다면 이미 int 생성자가 어떤 값을 a에 넣었다. 이 값이 의미가 없지만 말이다. 다음 코드를 보자.
#include <iostream>
int main() {
int a;
std::cout << a << std::endl;
}
a
에 아무 값도 넣지 않았음에도 0
이 출력된다. int 생성자는 a
가 선언되면서 정수형 0
을 생성해서 a
에 넣었다.
메소드는 객체 지향 프로그래밍에서 사용되는 개념이다. 객체가 동작하기 위한 방법이다. 위 예시에서 int
형 변수에 사용되는 사칙연산 등이 int
의 메소드이다.
기본적인 클래스는 다음과 같이 선언한다.
class ClassName { // 클래스 이름
private:
// 클래스 내부에서만 참조(reference)할 수 있는 '객체'
public:
// 클래스 외부에서 사용할 수 있는 메소드
};
위 코드에서 구조체와 다른 점을 확인할 수 있다. private
, public
이다. private
와 public
의 차이는 주석 내용과 같이 참조할 수 있는 범위(scope)이다. 다음 코드를 보면,
#include <iostream>
class Point {
private:
int x, y;
};
int main() {
Point p;
std::cout << p.x << std::endl;
return 0;
}
std::cout << p.x << std::endl;
에서 메인 함수에서 p.x
로 접근하려고 한다. 위 코드를 실행하면 다음과 같은 에러가 발생한다.
위 코드에서 private
를 public
으로 바꾸면 값이 출력된다.
클래스도 다른 변수형과 마찬가지로 생성자가 있다. 하지만 int a = 3;
과 같이 선언과 동시에 초기화(initialize)하기 위해서 생성자를 직접 만들 수 있다.
class ClassName {
private:
// 멤버 변수
public:
ClassName(초기화 내용) {
// 멤버 변수 초기화
}
...
};
앞선 예시에서 생성자를 직접 만든다면 다음과 같다.
...
class Point {
private:
int x, y;
public:
Point(int x_, int y_) { // private 내부 x, y와 구분지어 주기 위함
x = x_; y = y_;
}
};
...
Point p(3, 4);
...
위 내용을 풀어서 보자면
클래스 객체
p
에는 private 멤버 변수x
,y
가 있다. 이x
와y
는Point p(3, 4);
에서 각각3
과4
로 초기화됐다.
로 표현할 수 있다.
클래스 메소드, 다른 말로 클래스 멤버 함수는 클래스 내부에서 선언된다.
class ClassName {
private:
// 멤버 변수
public:
int method1(매개변수); // 선언만
void method2(){ // 선언 및 동작 구현
// 함수 내용
}
};
원의 넓이와 둘레, 중심 좌표 위치를 클래스로 구현했다.
#include <iostream>
#define PI 3.14
class Circle {
private:
int cx, cy;
int r;
public:
Circle(int a, int b, int R){
cx = a; cy = b; r = R;
}
double area(){
return r * r * PI;
}
double circum(){
return 2 * r * PI;
}
void printCenter(){
std::cout << "(" << cx << ", " <<
cy << ")" << std::endl;
}
void moveCenter(int a, int b){
cx = a; cy = b;
}
};
int main() {
Circle c(3, 4, 2);
std::cout << "Circle Area: " << c.area() << std::endl;
std::cout << "Circle Circumference: " << c.circum() << std::endl;
c.printCenter();
c.moveCenter(100, 100);
c.printCenter();
return 0;
}
다른 소스 파일에서 클래스 멤버 함수 동작을 구현할 때는 다음과 같이 한다.
var_type ClassName::method(argument) { ...
위 코드를 main.cpp
, Circle.h
, Circle.cpp
로 분할하면 다음과 같다.
main.cpp
#include "Circle.h" // C와 같이 stdlib 폴더 속 헤더가 아닌 헤더는 ""
int main() {
Circle c(3, 4, 2);
std::cout << "Circle Area: " << c.area() << std::endl;
std::cout << "Circle Circumference: " << c.circum() << std::endl;
c.printCenter();
c.moveCenter(100, 100);
c.printCenter();
return 0;
}
Circle.h
#include <iostream>
#define PI 3.14
class Circle {
private:
int cx, cy;
int r;
public:
Circle(int a, int b, int R);
double area();
double circum();
void printCenter();
void moveCenter(int a, int b);
};
Circle.cpp
#include "Circle.h"
Circle::Circle(int a, int b, int R) { // 생성자는 return x
cx = a; cy = b; r = R;
}
double Circle::area() {
return r * r * PI;
}
double Circle::circum() {
return 2 * r * PI;
}
void Circle::printCenter() {
std::cout << "(" << cx << ", " << cy << ")" << std::endl;
}
void Circle::moveCenter() {
cx = a; cy = b;
}