C++ 배경
옛날에는 소규모, 개인 프로젝트라서 C언어로도 충분히 프로젝트를 진행할 수 있었지만,
산업이 발전하면서 여러가지 형태의 응용프로그램들이 나타나다보니 C의 한계가 드러나기 시작했다.
그래서 C를 발전시켜서 C++/ C++++(=C#) 이 탄생하게되었다.
C는 절차지향 -> 한줄씩 단계별로 컴파일
C++은 객체지향 -> 부품들을 하나씩 조립하는 형식으로 컴파일
클래스
C++의 클래스는 C언어의 구조체에서의 개념과 비슷하다.
C에서 구조체는 멤버 변수만 가질 수 있다.
C++ 구조체는 멤버 변수, 멤버 함수를 가질 수 있다. 이것을 클래스라고 부른다.
따라서 클래스는 구조체가 발전된 형태라고 볼 수 있다.
(참고로 C에서의 함수는 객체지향에서 메서드와 같은 개념이라고 볼 수 있다)
생성자 : 클래스를 초기화 시키는 친구
소멸자 : 생성자를 소멸시키는 친구
객체 지향 언어의 특징
캡슐화 : 묶어놓는 것
추상화 : 나타내는 것(머릿속에 있는것을 컴퓨터로 나타내는 것)
은폐 : 숨기는 것(멤버 접근 지정자를 사용), 보통 멤버 변수가 중요해서 변수를 은폐시킴.
다형성 : 여기서도쓰고 저기서도 쓰는것(오버로딩 이라고도 부름)
상속 : 쉽게말해 재사용임.
C언어의 확장
C에 비해서 C++은 어떤 장점을 가지는지 알아보도록하자.
우선 C언어 코드의 확장자를 cpp로 저장해서 예제를 작성해보자.
cursor.h 헤더파일 추가
#include <windows.h>
#include <time.h>
#define randomize() srand((unsigned)time(NULL))
#define random(n) (rand() % (n))
#define delay(n) Sleep(n)
#define clrscr() system("cls")
#define gotoxy(x,y) { COORD Cur = {x, y}; \
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),Cur);}
#define showcursor(bShow) { CONSOLE_CURSOR_INFO CurInfo = {20, bShow}; \
SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE),&CurInfo); }
randnumOop.cpp 소스파일 추가
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include "cursor.h"
class RandNum
{
private:
int num;
public:
RandNum()
{
randomize();
}
void Generate()
{
num = random(100) + 1;
}
BOOL Compare(int input)
{
if (input == num)
{
printf("맞췄습니다.\n");
return TRUE;
}
else if (input > num)
{
printf("입력한 숫자보다 더 작습니다.\n");
}
else
{
printf("입력한 숫자보다 더 큽니다.\n");
}
return FALSE;
}
};
class Ask
{
private:
int input;
public:
void Prompt()
{
printf("\n제가 만든 숫자를 맞춰 보세요.\n");
}
BOOL AskUser()
{
printf("숫자를 입력하세요(끝낼 때는 999) : ");
scanf("%d", &input);
if (input == 999)
{
return TRUE;
}
return FALSE;
}
int GetInput()
{
return input;
}
};
int main()
{
RandNum R;
Ask A;
for (;;)
{
R.Generate();
A.Prompt();
for (;;)
{
if (A.AskUser())
{
exit(0);
}
if (R.Compare(A.GetInput()))
{
break;
}
}
}
}
해당예제는 객체지향으로 랜덤한 숫자를 사용자가 맞춰보는 예제이다.
객체 지향은 부품 조립식이며 부품이 되는 객체를 얼마나 잘 조립해서 만드느냐가 관건이다.
훌륭한 부품을 만드는것이 어려운 일이지만 한번만 잘 만들어 놓으면 많은 사람이 편리하게 활용할 수 있다.
객체지향의 기본 철학은 재활용성이며, 비슷한 코드를 매번 만들지 말고 딱 한번 제대로 만들어놓고 적극적으로 재활용하는 것이 중요하다.
bool형
C는 별도의 진위형이 없어서 조건문에 참과 거짓을 판별할때 정수를 대신 사용했다.
거짓은 0으로 확정적이나, 0 이외에는 모두 참이어서 일관되지 못해서 불편하게 사용했었는데,
C++는 bool 타입을 도입하여 true, false로 진위형을 표현할 수 있다.
// 파일명 : bool.cpp
#include <stdio.h>
int main()
{
int age = 25;
bool isAdult = age > 19;
if (isAdult)
{
puts("성인입니다");
}
}
태그
C++은 태그를 하나의 타입으로 인정하기때문에 태그명으로 변수를 선언할 수 있다.
C는 반드시 태그앞에 enum, struct 키워드를 붙이지만,
C++은 태그명 자체를 타입으로 인정한다.(클래스도 하나의 타입으로 인정한다)
// 파일명 : tagtype.cpp
#include <stdio.h>
int main()
{
enum origin {EAST, WEST, SOUTH, NORTH};
// enum origin mark = WEST;
origin mark = WEST;
printf("%d 방향\n", mark);
struct SHuman
{
char name[12];
int age;
double height;
};
// struct SHuman kim = { "홍길동", 30, 200.4 };
SHuman kim = { "홍길동", 30, 200.4 };
printf("이름 = %s, 나이 = %d\n", kim.name, kim.age);
}
C에서는 주석처리된 부분처럼
enum origin mark = WEST;
struct SHuman kim = { "홍길동", 30, 200.4 }; 를
붙여줘야하는데 C++에서는 붙이지않아도 일반 변수처럼 사용할 수 있다.
명시적캐스팅
C 형식 : (타입)변수
C++ 형식 : 타입(변수)
C++은 단일 변수를 캐스팅할때는 별 차이가 없지만 수식을 캐스팅할때는 괄호가 필요없다.
C 형식 : (float)(a+b)
C++형식: float(a+b)
대신, 함수와 헷갈릴수도있는데, 이름이 기본 자료형이니까 캐스팅을 하고있다는 점을 구분하면 될 것이다.
new 연산자
new 연산자는 데이터를 메모리에 할당해주는 연산자이다.
C에서는 malloc() - free() => 함수
C++ 에서는 new - delete => 연산자
C++은 연산자이기때문에 별도의 헤더 파일을 포함할 필요가 없다.
new 연산자는 객체 할당시 생성자를 호출하고, delete 연산자는 객체를 해제할때 소멸자를 호출한다.
new 연산자를통한 동적할당 예제
// 파일이름 : newdelete.cpp
#include <stdio.h>
int main()
{
int* pi, *pj;
pi = new int;
pj = new int(10); // 생성자를 호출하는 '연산자'이므로 바로 초기화 가능함.
*pi = 123; // 할당한 후에 초기화
printf("*pi = %d\n", *pi);
printf("*pj = %d\n", *pj);
delete pi;
delete pj;
}
C언어 malloc은 할당받은 주소값만 리턴할 수 있고 초기화는 불가능하지만,
C++ new 연산자는 할당시키면서 초기화가 가능하다는 차이점이있다.
우선 C의 동적할당을 살펴보자.
pi = (int*)malloc(sizeof(int));
*pi = 123;
printf("*pi = %d\n", *pi);
free(pi);
malloc 함수는 바이트 단위로 할당량을 지정하므로 sizeof 연산자가 필요하고 void* 를 리턴하므로 캐스트 연산자도 반드시 사용해야한다.
이에 반해 위의 예제처럼 new 연산자는 할당할 때부터 타입을 지정하므로 크기를 밝힐 필요가 없고 캐스팅할 필요도 없으며, 사용자 정의타입도 할당할 수 있다.
또,
C언어는 역참조 에러를 없애기위해 NULL일때(메모리 할당못받으면 NULL을 반환) 조건문을 따로 걸어줬었는데,
C++도 할당에 실패하면 NULL을 리턴하는데, 단일 변수 할당에 실패하는 경우는 거의 없다고 볼 수 있다.
그리고 위의 예제 코드를 실행했을때도 초록줄(경고)가 뜨지않았는데, 그만큼 내부적으로 안정적이라는 점을 알 수 있다.
배열을 메모리에 동적할당하는 방법
#include <stdio.h>
int main()
{
int* ar;
ar = new int[5];
// ar = (int*)malloc(sizeof(int) * 5) // C에서의 배열 동적할당
for (int i = 0; i < 5; i++)
{
ar[i] = i;
}
for (int i = 0; i < 5; i++)
{
printf("%d번째 = %d\n", i, ar[i]);
}
delete[] ar;
}
new int[5] 구문에 의해 정수형 변수 5개를 저장할 수 있는 20바이트의 메모리가 할당되며 그 자리에 포인터 변수로 받으면 정수형 배열이 된다.
배열을 할당할 때는 기본값으로 초기화되며 별도의 초기값을 지정할 필요는 없다.
new[] 연산자로 생성자를 호출했으니 delete[]로 전체 요소를 한꺼번에 해제할 수 있다.
셀프테스트) 크기 100의 실수형 배열을 할당하고 50번째 요소에 3.14를 대입하여 출력
#include <stdio.h>
int main()
{
double* ar;
ar = new double[100];
ar[50] = 3.14;
printf("ar[50] : %.2f \n", ar[50]);
}
'개발자과정준비 > C++' 카테고리의 다른 글
[C++] 여러가지 생성자(디폴트, 복사, 초기화리스트, 변환) (0) | 2021.06.03 |
---|---|
[C++] 생성자, 소멸자(파괴자) (0) | 2021.06.02 |
[C++] 클래스 (0) | 2021.06.01 |
[C++] 디폴트 인수, 오버로딩, 인라인 함수 (0) | 2021.05.31 |
[C++] C++을 시작해보자(입출력, 레퍼런스) (0) | 2021.05.29 |