Search
Duplicate

3장. 클래스와 객체

생성일
2022/04/04 13:50
태그
C++

클래스와 객체

캡슐화 (encapsulation)

객체의 본질적인 특성
객체를 캡슐로 싸서 그 내부를 보호하고 볼 수 없게 함
캡슐에 든 약은 어떤 색인지 성분인지 보이지 않고, 외부로부터 안전
캡슐화의 목적
객체 내 데이터에 대한 보안, 보호, 외부 접근 제한

객체의 일부 요소는 공개된다

객체의 일부분 공개
외부와의 인터페이스 (정보교환 및 통신)를 위해 객체의 일부분 공개
TV 객체의 경우, On/Off 버튼, 밝기 조절, 채널 조정, 음량 조절 등등

C++ 객체는 멤버 함수와 멤버 변수로 구성된다

객체는 상태(state)와 행동(behavior) 으로 구성
TV 객체 사례
상태
0n/Off 속성 - 현재 작동 중인지 표시
채널 - 현재 방송중인 채널
음향 - 현재 출력되는 소리크기
행동
켜기
끄기
채널 증가
채널 감소
음량 증가
음량 줄이기

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

클래스 (붕어빵 틀)
객체를 만들어내기 위해 정의된 설계도, 틀
클래스는 객체가 아님, 실체도 아님
멤버 변수와 멤버 함수 선언
객체 (붕어빵)
객체는 생성될 때 클래스의 모양을 그대로 가지고 탄생
멤버 변수와 멤버 함수로 구성
메모리에 생성, 실체(Instance) 라고도 부름
하나의 클래스 틀에서 찍어낸 여러 개의 객체 생성 가능
객체들은 상호 별도의 공간에 생성

C++ 클래스 만들기

클래스 작성
멤버 변수, 멤버 함수로 구성
클래스 선언부, 클래스 구현부로 구성
클래스 선언부 (class declaration)
class 키워드를 이용하여 클래스를 선언
멤버 변수, 멤버 함수 선언
멤버 변수는 클래스 선언 내에서 초기화할 수 있음
멤버 함수는 원형 형태로 선언
멤버에 대한 접근 권한 지정
private, public, protected 중의 하나
디폴트는 private
public : 다른 모든 클래스나 객체에서 멤버의 접근이 가능함을 표시
클래스 구현부 (class Implementation)
클래스에 정의된 모든 멤버 함수 구현
class Circle { public: int radius; // 멤버 변수 double getArea(); // 멤버 함수 } // 클래스 구현부 double Circle :: getArea() { return 3.14 * radius * radius; }
C++
복사
예제)
#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; // 도넛 객체의 반지름을 1로 생성 double area = donut.getArea(); // 도넛 객체의 면적 알아내기 cout << "donut 면적은 " << area << endl; Circle pizza; pizza.radius = 5; area = pizza.getArea(); cout << "pizza 면적은 " << area << endl; }
C++
복사

객체 생성 및 활용 설명

객체 이름 및 객체 생성
Circle donut;
C++
복사
객체의 멤버 변수 접근
donut.radius = 1;
C++
복사
객체의 멤버 함수 접근
double area = donut.getArea();
C++
복사
예제2)
#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; }
C++
복사

생성자 (Constructor)

객체가 생성되는 시점에서 자동으로 호출되는 멤버 함수
클래스 이름과 동일한 멤버 함수

생성자 함수의 특징

생성자의 목적
객체가 생성될 때 객체가 필요한 초기화를 위해
멤버 변수 값 초기화, 메모리 할당, 파일 열기, 네트워크 연걸 등
생성자 이름
반드시 클래스 이름과 동일
생성자는 리턴 타입을 선언하지 않는다
리턴 타입 없다. void 타입도 안된다
객체 생성 시 오직 한번만 호출
자동으로 호출됨, 임의로 호출할 수 없음
각 객체마다 생성자 실행
생성자는 중복 가능
생성자는 한 클래스 내에 여러 개 가능
중복된 생성자 중 하나만 실행
생성자가 선언되어 있지 않으면, 기본 생성자 자동으로 생성
기본 생성자 - 매개변수 없는 생성자
컴파일러에 의해 자동 생성
예제 - 생성자)
#include <iostream> using namespace std; class Circle { public: int radius; Circle(); // 매개변수 없는 생성자 Circle(int r); // 매개변수 있는 생성자 double getArea(); }; Circle :: Circle() { radius = 1; cout << "반지름 " << radius << " 원 생성" << endl; } Circle :: Circle(int r) { radius = r; cout << "반지름 " << radius << " 원 생성" << endl; } double Circle :: getArea() { return 3.14 * radius * radius; } int main() { Circle donut; // 매개변수 없는 생성자 호출 double area = donut.getArea(); cout << "donut 의 면적은 " << area << endl; Circle pizza(30); // 매개변수 있는 생성자 호출 area = pizza.getArea(); cout << "pizza 의 면적은 " << area << endl; }
C++
복사

생성자가 다른 생성자 호출 (위임 생성자)

여러 생성자에 중복 작성된 코드의 간소화
타겟 생성자와 이를 호출하는 위임 생성자로 나누어 작성
타겟 생성자 : 객체 초기화를 전담하는 생성자
위임 생성자 : 타겟 생성자를 호출하는 생성자, 객체 초기화를 타겟 생성자에 위임
Circle :: Circle() { radius = 1; cout << "반지름 " << radius << " 원 생성" << endl; } Circle :: Circle(int r) { radius = r; cout << "반지름 " << radius << " 원 생성" << endl; } // 여러 생성자에 코드 중복
C++
복사
→ 간소화된 코드
//위임 생성자 Circle::Circle() : Circle(1) { } //Circle(int r) 의 생성자 호출 //타겟 생성자 Circle::Circle(int r) { radius = r; cout << "반지름 " << radius << " 원 생성" << endl; }
C++
복사
→ 간소화된 코드로 예제 작성
#include <iostream> using namespace std; class Circle { public: int radius; Circle(); // 매개변수 없는 생성자 Circle(int r); // 매개변수 있는 생성자 double getArea(); }; Circle :: Circle() : Circle(1) {} // 위임 생성자 Circle :: Circle(int r) { // 타겟 생성자 radius = r; cout << "반지름 " << radius << " 원 생성" << endl; } double Circle :: getArea() { return 3.14 * radius * radius; } int main() { Circle donut; // 매개변수 없는 생성자 호출 double area = donut.getArea(); cout << "donut 의 면적은 " << area << endl; Circle pizza(30); // 매개변수 있는 생성자 호출 area = pizza.getArea(); cout << "pizza 의 면적은 " << area << endl; }
C++
복사

다양한 생성자의 멤버 변수 초기화 방법

1.
생성자 코드에서 멤버 변수 초기화
Point::Point() {x = 0; y = 0;} Point::Point(int a, int b) {x = a; y = b;}
C++
복사
2.
생성자 서두에 초기값으로 초기화
// 멤버변수 x, y를 0으로 초기화 Point::Point() : x(0), y(0){ } // 멤버변수 x=a로, y=b로 초기화 Point::Point(int a, int b) : x(a), y(b) { // 콜론(:) 이하 부분을 밑줄에 써도 됨 }
C++
복사
3.
클래스 선언부에서 직접 초기화
class Point { // 클래스 선언부에서 x, y를 0으로 직접 초기화 int x = 0, y= 0; public: }
C++
복사
예제 3-5, 멤버변수의 초기화와 위임 생성자 활용
#include <iostream> using namespace std; class Point { int x, y; public: Point(); Point(int a, int b); void show() { cout << "(" << x << ", " << y << ")" << endl;} }; Point::Point() : Point(0, 0){} //위임 생성자 Point::Point(int a, int b) // 타겟 생성자 : x(a), y(b) {} int main() { Point origin; Point target(10, 20); origin.show(); target.show(); }
C++
복사

기본 생성자

1.
생성자는 꼭 있어야 하는가?
a.
Yes, C++ 컴파일러는 객체가 생성될 때, 생성자를 반드시 호출
2.
기본 생성자란?
클래스에 생성자가 하나도 선언되어 있지 않은 경우, 컴파일러가 대신 삽입해주는 생성자
매개변수 없는 생성자
디폴트 생성자라고도 부름

기본 생성자가 자동으로 생성되는 경우

생성자가 하나도 작성되어 있지 않은 클래스의 경우
컴파일러가 기본 생성자 자동으로 생성
만약 생성자가 하나라도 선언된 클래스의 경우
컴파일러는 기본 생성자를 자동으로 생성하지 않는다
예제 3-6)
#include <iostream> using namespace std; class Rectangle { int width, height; public: Rectangle(); Rectangle(int w, int h); Rectangle(int length); bool isSquare(); }; Rectangle::Rectangle() { width = height = 1; } Rectangle::Rectangle(int w, int h) { width = w; height = h; } Rectangle::Rectangle(int length) { width = height = length; } // 정사각형이면 true를 리턴하는 멤버 함수 bool Rectangle::isSquare() { if (width == height) return true; else return false; } int main() { Rectangle rect1; Rectangle rect2(3, 5); Rectangle rect3(3); if (rect1.isSquare()) cout << "rect1 은 정사각형이다." << endl; if (rect2.isSquare()) cout << "rect2 는 정사각형이다." << endl; if (rect3.isSquare()) cout << "rect3 은 정사각형이다." << endl; }
C++
복사

소멸자

객체가 소멸되는 시점에서 자동으로 호출되는 함수
오직 한번만 자동 호출, 임의로 호출할 수 없음
객체 메모리 소멸 직전 호출된다

소멸자 특징

소멸자의 목적
객체가 사라질 때 마무리 작업을 위함
실행 도중 동적으로 할당 받은 메모리 해제
파일 저장 및 닫기
네트워크 닫기 등
소멸자 함수의 이름은 클래스 이름 앞에 ~를 붙인다
Circle::~Circle() {...}
C++
복사
소멸자는 리턴 타입이 없고, 어떤 값도 리턴하면 안됨
리턴 타입 선언 불가
중복 불가능
소멸자는 한 클래스 내에 오직 한 개만 작성 가능
소멸자는 매개 변수 없는 함수
소멸자가 선언되어 있지 않으면, 기본 소멸자가 자동 생성
컴파일러에 의해 기본 소멸자 코드 생성
컴파일러가 생성한 기본 소멸자 → 아무것도 하지않고 단순 리턴만
Circle.h
#include <string> using namespace std; class Circle { //클래스 선언부 public: //접근지정자 int radius; //멤버 변수 std::string name; Circle(); //매개변수가 없는 생성자도 만들어야 Circle(int r); //생성자 Circle(string n, int r); Circle(string n); ~Circle(); //소멸자 double getArea(); //멤버 함수 void print(); };
C++
복사
Circle.cpp
#include <iostream> #include "Circle.h" using namespace std; //클래스 구현부 double Circle::getArea() { return 3.14 * radius * radius; } void Circle::print() { // cout << "넓이는 " << getArea() << endl; cout << name << "의 넓이는 " << getArea() << endl; } Circle::Circle() : Circle("", 0) { // radius = 0; // name = ""; } Circle::Circle(int r) : Circle("", r) { // radius = r; // name = ""; } Circle::Circle(string n, int r) : name(n), radius(r) { // name = n; // radius = r; } Circle::Circle(string n) : Circle(n, 0) { // name = n; // radius = 0; } Circle::~Circle() { cout << "반지름" << radius << "원 소멸" << endl; }
C++
복사

생성자 / 소멸자 실행 순서

객체가 선언된 위치에 따른 분류
지역 객체
함수 내에 선언된 객체로서, 함수가 종료하면 소멸된다.
전역 객체
함수의 바깥에 선언된 객체로서, 프로그램이 종료할 때 소멸된다.
객체 생성 순서
전역 객체는 프로그램에 선언된 순서로 생성
지역 객체는 함수가 호출되는 순간에 순서대로 생성
객체 소멸 순서
함수가 종료하면, 지역 객체가 생성된 순서의 역순으로 소멸
프로그램이 종료하면, 전역 객체가 생성된 순서의 역순으로 소멸
new 를 이용하여 동적으로 생성된 객체의 경우
new 를 실행하는 순간 객체 생성
delete 연산자를 실행할 때 객체 소멸

접근 지정자

캡슐화의 목적
객체 보호, 보안
C++ 에서 객체의 캡슐화 전략
객체의 상태를 나타내는 데이터 멤버(멤버 변수) 에 대한 보호
중요한 멤버는 다른 클래스나 객체에서 접근할 수 없도록 보호
외부와의 인터페이슬르 위해서 일부 멤버는 외부에 접근 허용
멤버에 대한 3가지 접근 지정자
private
동일한 클래스의 멤버함수에만 제한함
public
모든 다른 클래스에 허용
protected
클래스 자신과 상속받은 자식 클래스에만 허용
멤버 변수 ⇒ private 지정이 바람직하다

함수 호출에 따른 시간 오버헤드

→ 작은 크기의 함수를 호출하면, 함수 실행 시간에 비해, 호출을 위해 소요되는 부가적인 시간 오버헤드가 상대적으로 크다

인라인 함수

인라인 함수
inline 키워드로 선언된 함수
인라인 함수에 대한 처리
인라인 함수를 호출하는 곳에, 인라인 함수 코드를 확장 삽입
매크로와 유사
코드 확장 후 인라인 함수는 사라짐
인라인 함수 호출
함수 호출에 따른 오버헤드는 존재하지 않음
프로그램의 실행 속도가 개선
컴파일러에 의해 이루어진다
컴파일러가 판단하여 inline 요구를 수용할 지 결정한다
컴파일러는 inline 처리 후, 확장된 C++ 소스 파일을 컴파일 한다
recursion, 긴 함수, static 변수, 반복문 등을 가진 함수는 X
인라인 함수의 목적
C++ 프로그램의 실행 속도 향상
자주 호출되는 짧은 코드의 함수 호출에 대한 시간 소모를 줄임
C++ 에는 짧은 코드의 멤버 함수가 많기 떄문
장점 : 프로그램의 실행 시간이 빨라진다
단점 : 인라인 함수 코드의 삽입으로 컴파일된 전체 코드 크기가 증가한다
짧은 코드의 함수를 인라인으로 선언하는 것이 좋다

자동 인라인 함수

클래스 선언부에 구현된 멤버 함수
inline으로 선언할 필요 없다
컴파일러에 의해 자동으로 인라인 처리
생성자를 포함, 모든 함수가 자동 인라인 함수 가능
C++ 구조체
C++ 구조체
상속, 멤버, 접근 지정 등 모든 것이 클래스와 동일
클래스와 유일하게 다른 점
구조체의 디폴트 접근 지정 - public
클래스의 디폴트 접근 지정 - private
C++ 에서 구조체를 수용한 이유
C언어와의 호환성 때문
C의 구조체 100% 호환 수용
C 소스를 그대로 가져댜 쓰기 위해
구조체 객체 생성
struct 키워드 생략
구조체 이용하여 헤드파일 구성
#include <string> using namespace std; struct StructCircle { //클래스 선언부 private: //접근지정자 int radius; //멤버 변수 public: StructCircle(int r) {radius = r;} // 구조체의 생성자 double getArea(); //멤버 함수 };
C++
복사