본문 바로가기
C++

C++ 클래스

by godfeeling 2020. 7. 5.

클래스(class)?

C++에서 클래스(class)란 구조체의 상위 호환으로 이해할 수 있습니다.

 

C++의 구조체는 멤버로 함수를 포함할 수 있기에, C언어의 구조체보다 좀 더 확장된 의미를 가집니다.

 

C++에서 이러한 구조체와 클래스의 차이는 기본 접근 제어의 차이일 뿐, 나머지는 거의 같습니다.

 

 

 

C++에서는 이러한 클래스를 가지고 객체 지향 프로그램을 작성할 수 있습니다.

 

클래스의 멤버 변수를 프로퍼티(property), 멤버 함수를 메소드(method)라고도 합니다.

객체 지향 프로그래밍(OOP, Object-Oriented Programming)

객체 지향 프로그래밍에서는 모든 데이터를 객체(object)로 취급하며, 객체가 바로 프로그래밍의 중심이 됩니다.

 

 

 

객체(object)란 간단히 이야기하자면 실생활에서 우리가 인식할 수 있는 사물로 이해할 수 있습니다.

 

이러한 객체의 상태(state)와 행동(behavior)을 구체화하는 형태의 프로그래밍이 바로 객체 지향 프로그래밍입니다.

 

또한, 이와 같은 객체를 만들어 내기 위한 틀과 같은 개념이 바로 클래스(class)입니다.

 

객체 지향 프로그래밍의 특징

객체 지향 프로그래밍이 가지는 특징은 다음과 같습니다.

 

 

 

1. 추상화(abstraction)

 

2. 캡슐화(encapsulation)

 

3. 정보 은닉(data hiding)

 

4. 상속성(inheritance)

 

5. 다형성(polymorphism)

 

 

 

위와 같은 객체 지향 프로그래밍의 특징을 차례차례 수업을 통해 살펴볼 것입니다.

 

객체의 예

객체(object)

 

- 고양이

 

 

 

멤버 변수(member variable)

 

- cat.name_ = "나비"

 

- cat.family_ = "코리안 숏 헤어"

 

- cat.age_ = 1

 

- cat.weight_ = 0.1

 

 

 

멤버 함수(member function)

 

- cat.Mew()

 

- cat.Eat()

 

- cat.Sleep()

 

- cat.Play()

 

 

 

고양이 객체는 모두 위와 같은 멤버 변수와 멤버 함수를 가지지만, 각 멤버 변수의 값은 인스턴스마다 전부 다를 것입니다.

 

인스턴스(instance)

C++에서 클래스는 구조체와 마찬가지로 사용자가 정의할 수 있는 일종의 타입입니다.

 

따라서 클래스를 사용하기 위해서는 우선 해당 클래스 타입의 객체를 선언해야 합니다.

 

이렇게 선언된 해당 클래스 타입의 객체를 인스턴스(instance)라고 하며, 메모리에 대입된 객체를 의미합니다.

 

 

 

하나의 클래스에서 여러 개의 인스턴스를 생성할 수 있습니다.

 

이러한 인스턴스는 독립된 메모리 공간에 저장된 자신만의 멤버 변수를 가지지만, 멤버 함수는 모든 인스턴스가 공유합니다.

 

클래스의 선언

클래스란 객체 지향 프로그래밍의 특징 중 하나인 추상화(abstraction)를 사용자 정의 타입으로 구현한 것이라 할 수 있습니다.

 

C++에서 이러한 클래스를 선언하는 방법은 구조체를 선언하는 방법과 거의 같습니다.

 

구조체는 struct 키워드를 사용하지만, 클래스는 class 키워드와 접근 제어 지시자를 함께 사용합니다.

 

 

 

C++에서 클래스는 다음과 같이 정의합니다.

 

정의

class 클래스이름

 

{

 

접근제어지시자1:

 

멤버변수1의타입 멤버변수1의이름;

 

멤버변수2의타입 멤버변수2의이름;

 

...

 

멤버함수1의 원형

 

멤버함수2의 원형

 

...

 

};

 

접근 제어 지시자는 객체 지향 프로그래밍의 특징 중 하나인 정보 은닉(data hiding)을 위한 키워드입니다.

 

public 영역은 모든 객체에서 접근할 수 있지만, private 영역은 해당 객체 내의 멤버 변수나 멤버 함수만이 접근할 수 있습니다.

 

이렇게 선언된 클래스의 정의를 가지고 다음과 같이 Book 객체를 선언할 수 있습니다.

 

선언

클래스이름 객체참조변수이름; Book web_book;

 

예제

Book web_book;

 

멤버 함수의 정의

클래스에서 멤버 함수를 정의하는 방법은 일반 함수의 정의와 크게 다르지 않습니다.

 

C++에서는 멤버 함수를 클래스의 선언 안이나 밖에서 모두 정의할 수 있도록 허용합니다.

 

 

 

클래스의 선언 밖에서 멤버 함수를 정의할 때에는 범위 지정 연산자(::)를 사용하여 해당 함수가 어느 클래스에 속하는지를 명시해야 합니다.

 

문법

반환타입 클래스이름::멤버함수이름(매개변수목록) { 함수의 몸체; }

 

 

 

다음 예제는 클래스 선언 밖에서 Book 클래스의 Move() 멤버 함수를 정의하는 예제입니다.

 

예제

void Book::Move(int page) { current_page_ = page; }

 

 

 

만약 멤버 함수가 클래스의 선언 안에서 정의되면, 이 함수는 인라인 함수로 처리되어 위와 같이 범위 지정 연산자를 사용하여 소속 클래스를 명시할 필요가 없게 됩니다.

 

또한, 클래스 선언 밖에서 정의된 멤버 함수도 inline 키워드를 사용하여 인라인 함수로 처리할 수 있습니다.

 

멤버 함수는 클래스의 선언 안이나 밖에서 모두 정의할 수 있지만, 클래스가 일단 선언된 후에 멤버 함수를 추가할 수는 없습니다.

 

 

이처럼 하나의 클래스에서 생성된 인스턴스는 각각 독립된 메모리 공간에 저장된 자신만의 멤버 변수를 가지지만, 멤버 함수는 모든 인스턴스가 공유하게 됩니다.

 

멤버 함수의 호출

C++에서 위와 같이 정의한 멤버 함수를 호출하는 방법은 구조체의 경우와 같습니다.

 

멤버 함수는 멤버 참조 연산자(.)를 사용하여 호출할 수 있습니다.

 

 

 

멤버 함수를 호출하는 방법은 다음과 같습니다.

 

문법

1. 객체이름.멤버함수이름(); // 매개변수가 없는 멤버 함수의 호출

 

2. 객체이름.멤버함수이름(전달할인수목록); // 매개변수가 있는 멤버 함수의 호출

 

예제

web_book.Move(30);

 

 

정보 은닉(data hiding)

C++에서 구조체의 모든 멤버는 외부에서 언제나 접근할 수 있습니다.

 

하지만 클래스는 객체 지향 프로그래밍의 기본 규칙 중 하나인 정보 은닉에 대해서도 생각해야만 합니다.

 

 

 

정보 은닉(data hiding)이란 사용자가 굳이 알 필요가 없는 정보는 사용자로부터 숨겨야 한다는 개념입니다.

 

그렇게 함으로써 사용자는 언제나 최소한의 정보만으로 프로그램을 손쉽게 사용할 수 있게 됩니다.

 

접근 제어(access control)

C++에서는 이러한 정보 은닉을 위해 접근 제어(access control)라는 기능을 제공하고 있습니다.

 

접근 제어란 접근 제어 지시자를 사용해 클래스 외부에서의 직접적인 접근을 허용하지 않는 멤버를 설정할 수 있도록 하여, 정보 은닉을 구체화하는 것을 의미합니다.

 

 

 

C++에서는 다음과 같은 세 가지의 접근 제어 지시자를 제공합니다.

 

 

 

1. public

 

2. private

 

3. protected

 

클래스의 기본 접근 제어 권한은 private이며, 구조체 및 공용체는 public입니다.

public 접근 제어 지시자

public 접근 제어 지시자를 사용하여 선언된 클래스 멤버는 외부로 공개되며, 해당 객체를 사용하는 프로그램 어디에서나 직접 접근할 수 있습니다.

 

따라서 public 멤버 함수는 해당 객체의 private 멤버와 프로그램 사이의 인터페이스(interface) 역할을 하게 됩니다.

 

프로그램은 이러한 public 멤버 함수를 통해 해당 객체의 private 멤버에도 접근할 수 있습니다.

 

C++ 클래스 선언 시 public 접근 제어 지시자는 다음과 같이 지정할 수 있습니다.

 

예제

class Book

 

{

 

public:

 

string title_; // 책의 제목

 

int total_page_; // 총 페이지

 

double percent_; // 해당 책을 읽은 정도

 

void Move(int page); // 현재 페이지를 전달받은 페이지로 이동시킴.

 

void Open(); // 현재 페이지로 책을 엶.

 

void Read(); // 현재 페이지에서 다음 페이지로 넘어감.

 

};

 

private 접근 제어 지시자

private 접근 제어 지시자를 사용하여 선언된 클래스 멤버는 외부에 공개되지 않으며, 외부에서 직접 접근할 수도 없습니다.

 

프로그램은 private 멤버에 직접 접근할 수 없으며, 해당 객체의 public 멤버 함수를 통해서만 접근할 수 있습니다.

 

 

 

클래스의 기본 접근 제어 권한은 private로 설정되어 있으므로, 클래스 선언 시 private 접근 제어 지시자는 생략할 수 있습니다.

 

일반적으로 private 멤버는 public 인터페이스를 직접 구성하지 않는 클래스의 세부적인 동작을 구현하는 데 사용됩니다.

 

C++ 클래스 선언 시 private 접근 제어 지시자는 다음과 같이 지정할 수 있습니다.

 

예제

class Book {

 

private: // 생략 가능함.

 

int current_page_; // 현재 페이지

 

void set_percent(); // 해당 책을 읽은 정도를 구함.

 

public:

 

string title_;

 

int total_page_;

 

double percent_;

 

void Move(int page);

 

void Open();

 

void Read();

 

};

 

protected 접근 제어 지시자

C++ 클래스는 private 멤버로 정보를 은닉하고, public 멤버로 사용자나 프로그램과의 인터페이스를 구축합니다.

 

여기에 파생 클래스(derived class)와 관련된 접근 제어 지시자가 하나 더 존재합니다.

 

protected 멤버는 파생 클래스에 대해서는 public 멤버처럼 취급되며, 외부에서는 private 멤버처럼 취급됩니다.

 

 

 

protected 멤버에 접근할 수 있는 영역은 다음과 같습니다.

 

 

 

1. 이 멤버를 선언한 클래스의 멤버 함수

 

2. 이 멤버를 선언한 클래스의 프렌드

 

3. 이 멤버를 선언한 클래스에서 public 또는 protected 접근 제어로 파생된 클래스

 

 

멤버 함수의 공유

C++에서 하나의 클래스에서 생성된 인스턴스는 각각 독립된 메모리 공간에 저장된 자신만의 멤버 변수를 가지지만, 멤버 함수는 모든 인스턴스가 공유합니다.

 

 

 

따라서 Book 클래스를 이용해 두 개의 인스턴스를 생성해도, TickerBook()이라는 멤버 함수는 하나만이 존재합니다.

 

, 더 두꺼운 책의 이름을 출력해 주는 TickerBook() 멤버 함수는 두 인스턴스가 같이 공유하게 됩니다.

 

 

 

ThickerBook() 멤버 함수의 정의는 다음과 같습니다.

 

정의

const Book& Book::ThickerBook(const Book& comp_book)

 

{

 

if (comp_book.total_page_ > total_page_)

 

{

 

return comp_book;

 

}

 

else

 

{

 

return ???; // 자신을 호출한 인스턴스를 반환하는데 알 수가 없음.

 

}

 

}

 

 

 

그리고 ThickerBook() 멤버 함수는 다음과 같이 호출될 것입니다.

 

예제

web_book.ThickerBook(html_book);

 

 

 

이때 ThickerBook() 멤버 함수는 자신을 호출한 객체가 web_book 객체임을 인수를 통해 전달받아야만 합니다.

 

그래야만 else 문에서의 반환값을 정확히 명시할 수 있기 때문입니다.

 

this 포인터

위와 같은 이유로 C++에서는 모든 멤버 함수가 자신만의 this 포인터를 가지고 있습니다.

 

this 포인터는 해당 멤버 함수를 호출한 객체를 가리키게 되며, 호출된 멤버 함수의 숨은 인수로 전달됩니다.

 

이렇게 하면 호출된 멤버 함수는 자신을 호출한 객체가 무엇인지 정확히 파악할 수 있습니다.

 

 

 

this 포인터를 사용하여 위의 ThickerBook() 멤버 함수를 다시 정의하면 다음과 같습니다.

 

정의

const Book& Book::ThickerBook(const Book& comp_book)

 

{

 

if (comp_book.total_page_ > total_page_)

 

{

 

return comp_book;

 

}

 

else

 

{

 

return *this; // 자신을 호출한 인스턴스를 반환함.

 

}

 

}

 

 

this는 포인터이므로, 반환할 때에는 참조 연산자(*)를 사용하여 호출한 객체 그 자체를 반환해야 합니다.

 

 

예제

int main(void)

 

{

 

Book web_book("HTMLCSS", 350);

 

Book html_book("HTML 레퍼런스", 200);

 

 

 

cout << web_book.ThickerBook(html_book).title_; // 더 두꺼운 책의 이름을 출력함.

 

return 0;

 

}

 

 

 

Book::Book(const string& title, int total_page)

 

{

 

title_ = title;

 

total_page_ = total_page;

 

current_page_ = 0;

 

set_percent();

 

}

 

 

 

void Book::set_percent() { percent_ = (double) current_page_ / total_page_ * 100; }

 

 

 

const Book& Book::ThickerBook(const Book& comp_book)

 

{

 

if (comp_book.total_page_ > this->total_page_)

 

{

 

return comp_book;

 

}

 

else

 

{

 

return *this;

 

}

 

}

 

this 포인터는 암시적으로도 사용될 수 있지만, 가급적 화살표(->) 연산자를 통해 명시적으로 사용하는 것이 좋습니다.

this 포인터의 특징

C++에서 this 포인터는 다음과 같은 특징을 가집니다.

 

 

 

1. this 포인터는 클래스, 구조체 또는 열거체 타입의 비정적 멤버 함수에서만 사용할 수 있습니다.

 

2. 정적(static) 멤버 함수는 this 포인터를 가지지 않습니다.

 

3. this 포인터는 언제나 포인터 상수이며, 따라서 값을 재할당할 수 없습니다.

'C++' 카테고리의 다른 글

C++ 연산자 오버로딩  (0) 2020.07.05
C++ 생성자 & 소멸자  (0) 2020.07.05
C++ 범위  (0) 2020.07.05
C++ 함수  (0) 2020.07.05
C++ 함수기본  (0) 2020.07.05

댓글