본문 바로가기

컴퓨터공학/C, C++

C,C++> 클래스

OOP(Object Oriented Programming)

특징

캡슐화(Encapsulation) :

자료(Data)와 동작(Function)을 하나의 단위로 묶는 것이다. 묶어 놓은 것을 객체(Object)라고 한다. 

정보은폐(Information Hiding) :

외부에 사용하는 기능만 공개하고 나머지는 숨길 수 있는데 정보 은폐라고 한다. 

추상화(Abstraction) : 

현실 사물을 객체로 표현하기 위해 어떤 특징과 동작을 갖고 있는지 조사하는 것을 데이터 모델링이라고 한다. 특징과 동작을 캡슐화하여 객체를 정의한다. 그리고 외부 기능을 공개하고 숨긴다.  캡슐화와 정보 은폐를 하여 인터페이스를 설계하는 것이 추상화이다. 추상화에 의해 외부에서는 객체 인터페이스만 볼 수 있으며 내부 구현은 볼 수 없다. 그래서 사용 방법이 간단하고 외부 조작에 안전해지며 객체는 추상적인 인터페이스를 유지하는 한도 내에서 마음대로 수정할 수 있어 기능 개선이 쉬워진다. 

상속(Inheritance) :

이미 만들어진 클래스를 파생시켜 새로운 클래스를 정의하는 기법이다. 필요 기능을 추가하거나 제거 또는 변경할 수 있다.

다형성(Polymorphism) :

똑같은 호출이라도 상황과 호출하는 객체에 따라서 다른 동작을 할 수 있는 능력을 다형성이라고 한다. 

 

 

 

C++ 확장

개선 사항

범위 연산자 :

지역 변수에 가려진 전역변수 참조

명시적 캐스팅 :

(int)var 형식이 아니라 int(var)형식으로 캐스팅

인라인 함수 :

본체가 호출부에 삽입되는 함수

디폴트 인수 :

실인수가 생략될 때 형식 인수에 적용되는 기본값

함수 오버로딩 :

같은 이름 함수를 여러 개 정의하는 기능

태그가 타입으로 승격 :

구조체 태그로부터 변수를 바로 선언

이름없는 공용체 :

공용체 이름없이 멤버들이 기억 장소를 공유

한 줄 주석 :

//로 줄 끝까지 주석

레퍼런스 :

변수에 대한 별명

bool 타입 :

1바이트 진위형 타입 

 

IOStream 

C++은 객체로 표현하기 때문에 입출력을 담당하는 것도 함수가 아니라 객체이다. 

count는 출력 객체이고 cin은 입력 객체이다. 

#include <iostream>은 C의 stdio.h 에 해당되는 기본 헤더 파일.

unsing namespace std 는 명칭을  저장하는 기억 영역으로 C++에 새로 추가된 기능.

C++ 표준 라이브러리는 std라는 네임 스페이스에 모두 정의되어 있다. 

 

데이터 타입은 객체가 알아서 판단한다. endl은 개행 코드를 의미하며 \n과 기능적으로 동일하다. 

출력은 << 이고 입력은 >> 이다.

print, scanf 함수에 비해 많은 장점이 있다.

1. 사용 방법이 직관적

2. 입출력 객체가 데이터 타입을 자동 판별

3. 입출력 객체 <<, >> 연산자는 여러 가지 기본 타입에 대해 중복 정의되어 있는데 필요한 경우 사용자 정의 타입을 인식하도록 확장할 수 있다. 여기서 사용하는 기술이 연산자 오버로딩이다. 이 기술로 날짜, 시간, 신상 명세 등 복잡한 정볻 ㅗ표준 객체로 입출력할 수 있다. 반변 printf, scanf는 라이브러리가 제공하는 서식만 다룰 수 있다.

 

하지만 요즘 같은 세상에 콘솔로 문자열 출력하는 프로그램을 만들 일은 별로 없어서 ptirnf나 cout는 실습을 위한 확인 기능밖에 없다. 

 

new

new와 delete는 C의 malloc, free에 대응하는 C++의 메모리 할당 연산자이다. 

포인터 = new 타입[(초기값)];

new 다음 할당 대상 타입을 밝히면 sizeof(타입)만큼 메모리가 할당되고 할당된 포인터가 리턴된다. 

delete연산자로 할당된 메모리를 해제해야 하는데 할당만 하고 해제하지 않으면 메모리 누수가 발생한다.

delete는 null 포인터를 삭제하는 것이 가능하다. null 포인터를 삭제해도 에러가 안 난다. 

 

new/delete는 malloc/free와 동일하지만 차이점도 많이 있다. 

1. malloc/free는 라이브러리가 제공하는 함수인데 new/delete는 언어가 제공하는 연산자이다. 별도 헤더 파일을 포함할 필요 없이 언제든지 사용 가능하다. 이 연산자를 쓴다고 프로그램이 커지는 것도 아니다 연산자라서 사용자 정의 타입에 의해 오버로딩할 수 있다.

2. malloc 함수는 필요한 메모리양을 바이트 단위로 지정하고 void *을 리턴한다. 그래서 sizeof연산자와 캐스트 연산자 도움이 필요하다. 하지만 new는 할당할 타입을 지정하고 해당 타입 포인터를 리턴하므로 sizeof와 캐스트 연산자가 필요없다. 

3. malloc은 메모리 할당이 목적이라서 초기값을 줄 수 없다. 그러나 new연산자는 동적 생성 변수 초기값을 지정할 수 있다. 할당과 동시에 초괴화를 할 수 있다. 

4. new 연산자로 객체 할당할 때 생성자가 자동 호출된다. 

 

 

배열 할당할 때 new []로 했으면 delete []로 할 것. new와 delete는 짝이고 new [] 와 delete []도 짝이다. 

 

new/delete의 가장 큰 장점은 객체가 생성, 파괴할 때 생성자와 파괴자가 호출된다는 점이다. 

 

꼭 new/delete만 쓸 필요 없으며 malloc/free도 편리한 점이 있다. 예를 들면 malloc으로 할당한 메모리를 realloc으로 재할당할 수 있지만 new는 이런 기능이 없어서 새로 할당하고 복사하고 원래 메모리르 해제하는 과정을 해야 한다. 

그래서 재할당할 때 번지가 바뀌며 축소할 때도 번지가 바뀐다. 또한 실행 중 할당 블록 크기를 조사하는 _msize 기능이 없다. 할당 대상이 객체가 아니고 재할당을 자주 한다면 malloc/free를 쓴다. 객체 할당할 때는 new/delete를 쓴다.

 

 

구조체의 확장 

멤버함수 

C++에서 구조체는 멤버 변수(Field)와 멤버 함수(Method)로 구성된다. 

구조체 선언문에 함수 본체 코드를 직접 작성할 수 있지만 함수 코드가 길고 멤버 함수가 수십개라면 구조체 선언문이 너무 길어져서 보기 힘들고 관리하기 어렵다. 그래서 C++ 구조체 선언문에서 함수 원형만 작성하고 본체는 구조체 바깥에 따로 작성하는 방법을 사용한다.

struct Position 
{
	int x;
    int y;
    char ch;
    void OutPosition();
 };
 
 void Position::OutPosition()
 {
 	gotoxy(x, y);
    putch(ch);
 }

리턴 타입 소속구조체::멤버함수(인수)

{ 본체 }

 

함수 본체가 구조체 선언 내부에 있건 외부에 있건 함수가 구조체에 포함된다는 사실은 변함이 없다. 

다만 본체 정의 위치에 따라 멤버 함수 호출되는 방법상 차이가 생긴다. 

내부 정의 : 인라인 속성을 가진다. 실제 함수가 호출되는 게 아니라 멤버 함수를 호출하는 코드가 함수 본체 코드로 대체된다. 

외부 정의 : 일반 함수 호출과 마찬가지로 멤버 함수를 호출한다. 스택을 경유하여 인수를 넘기고 제어 분기가 발생한다. 

 

인라인 함수는 호출 부담이 없어서 속도가 빠르지만 여러 번 호출할 경우 실행 파일 크기가 증가한다. 

그래서 멤버 변수 값을 읽기만 하거나 단순 연산문일 때 내부 정의를 하고 그렇지 않으면 외부 정의를 하는게 좋다. 

외부 정의 하면서 인라인으로 만들고 싶으면 inline 키워드를 함수 원형 앞이나 정의부 앞에 쓰면 된다. 

내부 정의하면 이 함수는 무조건 인라인 속성을 가진다.

외부 정의하면서 인라인으로 지정할 수 있지만 내부 정의하면서 일반 함수로 만드는 문법은 없다. 

왜냐하면 컴파일러가 선언문만 읽고 마음대로 함수 본체 코드를 생성할 수 없는데 만약 생성된다면 헤더파일에 정의된 클래스 선언문을 읽을 때마다 함수가 중복 생성될 것이다. 컴파일러는 선언문을 기억했다가 함수가 호출될 때 클래스 내부에 선언된 함수 본체코드를 호출부에 기록할 수 밖에 없으며 따라서 내부 정의는 무조건 인라인이다. 

 

공용체도 멤버 함수를 가질 수 있다.

그러나 공용체는 기억 장소만 공유하고 어떤 멤버가 저장되어 있는지 알지 못해서 정적 멤버를 가질 수 없다.

멤버가 생성자, 파괴자를 정의할 수 없는 등 여러 가지 복잡한 제약이 있다. 

멤버 함수를 가지는 공용체는 무척 드물며 일부러 예를 만들지 않는 한 실용성이 별로 없다. 

 

 

액세스 지정 

구조체 또는 클래스의 멤버에 대한 외부 참조를 허가할 건지 금지할 건지 지정할 수 있다. 

private : 외부에서 액세스할 수 없으며 구조체 멤버 함수만 액세스할 수 있다. 외부에서는 private 멤버를 읽을 수 없고 존재 자체도 알려지지 않는다. 

public : 이 속성을 가지는 멤버는 외부로 공개되어 누구나 읽고 쓸 수 있고 함수는 호출할 수 있다. 자신의 속성이나 동작을 외부로 공개하는 수단이 되며 public 멤버를 소위 인터페이스라고 한다. 

protected : private처럼 외부에서 액세스할 수 없으나 상속된 파생 클래스는 액세스할 수 있다. 

 

액세스 지정자는 구조체 선언문 내에서만 사용된다.

다른 액세스 지정자가 나올 때까지 이 속성이 적용된다. 지정자 사이가 한 블록이 지정된다. 

액세스 지정자 순서 제약은 없으며 여러 번 중복될 수 있다. 

가급적 같은 액세스 속성을 멤버는 한 곳에 모으는 곳이 보기 좋다. 

통상 private, protected, public 순서로 선언한다. 

액세스 지정자를 사용하여 특정 멤버를 숨길 수 있는 OOP 기능을 정보 은폐라고 한다. 

 

 

클래스

class

C++ 구조체는 멤버 함수를 포함할 수 있다는 면에서 C 구조체에 비해 의미가 확장되었다. 

이 확장된 의미의 구조체에 새로운 이름을 붙였는데 그것이 바로 클래스이다. 

구조체라는 용어를 사용해도 문제 없겠지만 C의 전통적인 구조체와 C++의 확장된 구조체 차이를 명확하게 구분하고 싶었고 그래서 이름을 붙인 것이다. 

결국 OOP의 핵심이라고 할 수 있는 클래스는 확장된 구조체라고 정의할 수 있다. 

C의 전통적인 구조체는 타입이 다른 변수의 집합이며 C++의 확장된 구조체, 즉 클래스는 여기에 함수를 추가한 것이다.

 

구조체 선언문에 struct 키워드를 class라는 새로운 키워드로 바꾸면 클래스가 된다. 

확장된 구조체와 클래스의 유일한 차이점은 멤버에 대한 디폴트 액세스 지정뿐이다. 

구조체는 멤버함수를 가질 수 없는 것으로 잘못 아는 사람이 있는데 그렇지 않다. 

구조체도 멤버 함수, 생성자, 파괴자를 가질 수 있고 상속도 가능하며 클래스가 쓰이는 모든 곳에서 쓸 수 있다. 

단지 아무런 액세스 지정없이 멤버를 선언할 때 이 멤버에 어떤 액세스 지정이 적용되는지만 다를 뿐이다. 

 

구조체 디폴트 액세스 지정은 public이고 클래스의 디폴트 액세스 지정은 private이다. 

클래스는 객체 안정성을 위해 외부에서 함부로 건드리지 못하도록 멤버를 숨기는 경향이 있다. 

그에 비해 구조체는 공개하는 경향이 있다. 

물론 디폴트가 그럴 뿐 양쪽 모두 지정자로 공개 여부를 변경할 수 있다. 

이 외에 구조체와 클래스는 어떠한 차이점도 없다. 

 

전통적인 구조체 의미를 확장하면서 자연스럽게 클래스라는 새로운 개념이 소개되었다.

구조체 선언문과 비슷하되 struct 키워드 대신 class 키워드를 쓰고 멤버 선언문 중간에 액세스 지정이 온다는 것만 다르다.

class 이름 

{

액세스 지정:

멤버 변수;

멤버 함수;

...

};

 

인스턴스 

클래스는 어디까지나 타입일 뿐 그 자체가 정보를 저장하는 변수는 아니다. 

구조체를 선언한다고 구조체 변수가 생기는 것이 아닌 것처럼 클래스를 선언한다고 실제로 값을 기억할 수 있는 메모리가 할당되지 않는다. 클래스 선언은 어떤 타입의 어떤 멤버들이 포함되어 있는지를 컴파일러에게 알리는 역할만 할 뿐이다.

클래스 형 변수를 선언해야 실제 메모리가 할당된다. 

선언문에 의해 생성된 클래스형 변수를 인스턴스(Instance)라고 한다. 

인스턴스는 클래스가 메모리에 구현된 실체이며 우리가 지금까지 변수라고 불렸던 개념과 동일하다. 

클래스가 표현하는 정보를 실제로 기억하고 관리하는 주체가 바로 인스턴스이다. 

 

독립된 정보 저장을 위해 멤버 변수는 각 인스턴스들이 따로 가진다.

그러나 멤버 함수는 클래스에 속한 모든 인스턴스들이 공유한다. 

인스턴스 상태는 달라질 수 있어도 동작은 모두 동일하기 때문에 인스턴스별로 따로 가질 필요는 없다. 

 

인스턴스의 다른 표현은 Object이다.

인스턴스와 오브젝트는 클래스형 변수라는 같은 대상을 가리키지만 사용되는 문맥은 다르다.

인스턴스는 클래스가 메모리상에 구현된 실체라는 뜻으로 사용된다.

오브젝트는 프로그램을 구성하는 독립적인 부품이라는 뜻으로 사용된다. 

우리말로 인스턴스는 실체이고 오브젝트는 객체나 개체라고 부른다.

'컴퓨터공학 > C, C++' 카테고리의 다른 글

C,C++> 캡슐화  (0) 2022.08.09
C,C++> 생성자  (0) 2022.08.08
C,C++> 기타 내용  (0) 2022.08.03
C,C++> 파일 입출력  (0) 2022.07.28
C,C++> 함수 고급  (0) 2022.07.27