C++에서의 구조체

이번 강의에서는 C에서 C++로 확장하는 문을 열어볼게요.



강의들은 모두 무료입니다. 단, 저작권은 키클 코딩랩 에 있으며, 무단 복제 및 배포를 엄금합니다.
이를 어길 시, 본 사이트의 서버가 미국에 있으므로, 미국법에 의해 처벌될 수도 있습니다.




C에서 C++로의 확장

C 언어가 개발된 이후 C++가 개발이 되는데요. C++는 C 문법의 대부분을 그대로 계승함과 동시에, 새로운 기법을 도입함으로써 C 언어를 확장하게 된답니다. 그 확장을 가능하게 하는 출발점을 공부해 볼게요. 그것은 바로 구조체(Structure) 안에 함수를 구현하는 것이랍니다.

원하는 폴더/디렉토리를 만들고 gedit 문서 편집기를 이용하여 "lec15_strt.cpp"라는 이름의 C++ 파일을 만들어 볼게요. C++로의 확장을 공부할 것이기 때문에, 확장자가 "cpp"인 C++ 파일을 만든 것이랍니다. 그리고, 아래처럼 강의 구조체로 데이터의 묶음 만들기에서 코딩한 내용을 주석 부분만 빼고 복사해서 붙여 넣어 볼게요.

lec15_strt.cpp
#include <stdio.h>

struct Person {
	char *name;
	int age;
};

int main () {
	struct Person prs0;
	struct Person prs1;

	prs0.name = "Heungbu";
	prs0.age = 47;	
	prs1.name = "Nolbu";
	prs1.age = 54;

	printf("Person0: %s, %d\n", prs0.name, prs0.age);
	printf("Person1: %s, %d\n", prs1.name, prs1.age);
}

구조체 안에 함수를 코딩하기 전에, 해야할 일이 있어요. 그것은 표준 입출력 라이브러리의 헤더파일인 "stdio.h"를 아래 줄1과 같이 "cstdio"로 바꾸는 거예요.
C++에서는 헤더파일의 확장자인 ".h"를 안 붙이는 것이 원칙이예요 (붙여도 상관은 없답니다). 그리고, 표준 입출력 라이브러리(stdio)는 원래 C를 위해서 구현된 것이기 때문에, 그것을 명확히 표시하기 위해서 헤더파일 이름 맨 앞에 "c"를 붙여준답니다. 그래서, "cstdio"가 된 것이죠. 하지만, 사실 기존의 헤더파일 이름인 "stdio.h"를 사용해도 문제는 없구요, 이것을 강조하기 위해서 주석(Comment) 처리를 하기는 했지만, 줄1 뒤에 "// #include <stdio.h>"를 그대로 놔두었답니다. "//" 표시를 어떤 줄에 삽입하면, 그 해당 줄에서 "//" 뒤에 있는 모든 코드는 효력을 잃게 되어 컴파일도 되지 않고 실행도 되지 않는답니다. 한 줄을 통째로 주석처리 하고자 하면, 해당 줄의 맨 앞에 "//"를 삽입하면 되지요.

lec15_strt.cpp
#include <cstdio> // #include <stdio.h>

struct Person {
	char *name;
	int age;
};

int main () {
	struct Person prs0;
	struct Person prs1;

	prs0.name = "Heungbu";
	prs0.age = 47;	
	prs1.name = "Nolbu";
	prs1.age = 54;

	printf("Person0: %s, %d\n", prs0.name, prs0.age);
	printf("Person1: %s, %d\n", prs1.name, prs1.age);
}




구조체(Structure) 안의 함수(Function)

앞에서, 구조체(Structure) 안에 함수를 구현하는 것은 C++로의 확장을 가능하게 하는 출발점이라고 했지요. 그렇다면, 구조체 안에 함수를 구현하는 것이 왜 중요하고 필요한 걸까요? 그 답을 같이 생각해 볼까요?
구조체는 어떤 개체의 고유한 속성들을 묶어놓는 기법이라고 했지요? 그리고, 강의 구조체로 데이터의 묶음 만들기에서, 그 개체의 예로 "사람(Person)"을 이용하여, 사람의 속성인 "나이"와 "이름"을 구조체에 포함시켜서 코딩을 했었죠. 하지만, 사람을 사람답게 만드는 기능들인 "말하기"나 "걷기" 등은 구조체에 포함시키지 않았지요. 사실, 안 한게 아니라, 못 한 것이었답니다. 어떤 "기능"을 코딩으로 구현할 때 사용하는 기법이 함수(Function)인 것 기억하지요? 그런데, C에서는 구조체에 함수를 구현하는 것을 허용하지 않는 답니다. 그래서, 우리가 "말하기"나 "걷기" 등 사람을 사람답게 만들어 주는 기능을 구조체에 코딩할 수 없었던 것이지요. 즉, C에서는 "사람"이라는 개체를 온전한 개체로 구현할 수 없는 것이고, C++는 구조체 안의 함수 구현을 허용함으로써 그것을 가능하게 해준것이지요.

C++로의 확장으로 가능해진 "구조체 안의 함수 구현"을 통해, 속성과 기능을 모두 갖춘 "온전한 개체"를 구현할 수 있게 되었다는 점을 잊지마세요. 그럼, 이것을 "사람(Person)" 구조체 예를 통해 직접 체험해 볼까요? 아래처럼 구조체에 사람의 기능을 하나 추가로 코딩해 볼게요.

lec15_strt.cpp
#include <cstdio> // #include <stdio.h>

struct Person {
	char *name;
	int age;
	
	int introduce() {
		printf("My name is %s.\n", name);
		return age;
	}
};

int main () {
	Person prs0;
	struct Person prs1;

	prs0.name = "Heungbu";
	prs0.age = 47;	
	prs1.name = "Nolbu";
	prs1.age = 54;

	printf("I'm %d years old\n", prs0.introduce());
	printf("I'm %d years old\n", prs1.introduce());
}

줄7~줄10에, 사람의 기능 중 하나라고 할 수 있는 "자기 소개하기"를 "introduce"라는 이름의 함수로 구현했답니다. 이 함수는, 줄8에서 Person 구조체의 name 속성에 저장되어 있는 이름 문자열을 출력하고, 줄9에서 age에 저장되어 있는 값을 함수가 호출된 곳에 되돌려(return)주고 있답니다. 속성 age가 정수형이기 때문에 줄7에서 함수의 리턴 데이터타입이 정수형(int)이지요.
줄14~줄15에서는, 두 개의 "구조체 Person 타입" 변수를 선언하고 있는데요. 줄14에서 보듯이, C++에서는 "struct" 키워드를 사용하지 않아도 된답니다.
(C++에서 확장된 구조체의 설명은 문법노트에서도 볼 수 있어요.)

줄17~줄20은 예전의 코드와 다른 것이 없답니다.
줄14~줄15처럼, Person 구조체 데이터타입의 변수 prs0와 prs1를 선언하면, 각 구조체 변수는 name과 age 속성을 각각 따로 가지게 된답니다.
그래서, 줄17~줄18에서는, 접근 연산자 "."를 이용하여 Person 구조체 변수 prs0의 name과 age 속성에 흥부의 영문이름과 나이를 저장하고 있어요.
줄19~줄20에서는, prs1의 name과 age 속성에 놀부의 영문이름과 나이를 저장하고 있지요.

줄22에서는, 줄7~줄10에 정의된 introduce() 함수에서 되돌려(return)받는 prs0의 나이(age)를 출력하고 있답니다. 구조체 안의 함수에 접근할 때에도, 속성에 접근할 때와 마찬가지로 접근 연산자 "."를 이용한다는 점 주목해 주세요. 또 하나 주목할 것은, printf()에서 나이를 받아오기 위해 introduce() 함수를 호출하고 있다는 것이예요. 그러므로, introduce()가 먼저 실행이 되고, introduce()의 리턴값을 이용하여 printf()가 실행된답니다. 결과적으로, 터미널(Terminal)에는 줄8에 코딩된대로 이름이 먼저 출력되고, 그 다음에 나이가 출력된다는 것을 예상할 수 있답니다.
줄23에서는, 줄22에서와 같은 원리로 prs1, 즉, 놀부의 나이(age)를 introduce()에게서 받아 출력하고 있답니다. 그리고, 역시 introduce()가 먼저 실행 되기 때문에, 터미널(Terminal)에는 놀부의 이름이 먼저 출력되고 그 다음에 나이가 출력된다는 것을 예상할 수 있지요.





컴파일 후 실행하기

이제, 파일을 저장하고 gedit 편집기 닫기를 하세요.
그리고, 아래 줄1처럼 컴파일하면, 줄2~줄8과 같은 경고(Warning) 메세지를 볼지도 몰라요. 이 경고는 문자열을 다룰때 C++는 문자형 포인터(char *)를 사용하지 않기를 바란다는 의미로, 나중에 자세히 공부할 기회가 있을 거예요. 여하튼, 이 문구는 경고일 뿐이지, 문법(Syntax) 에러(Error)는 아니랍니다. 고로, 실행하는데 아무 문제가 없다는 것이죠. 줄9처럼 실행해 보면, 앞서 예상했던대로 각각 흥부와 놀부의 이름과 나이가 순서대로 출력되는 것을 볼 수 있지요.

.../my_folder$ gcc lec15_strt.cpp
lec15_strt.cpp: In function ‘int main()’:
lec15_strt.cpp:17:12: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
  prs0.name = "Heungbu";
            ^
lec15_strt.cpp:19:12: warning: deprecated conversion from string constant to ‘char*’ [-Wwrite-strings]
  prs1.name = "Nolbu";
            ^
.../my_folder$ ./a.out
My name is Heungbu.
I'm 47 years old
My name is Nolbu.
I'm 54 years old
.../my_folder$

강의에서 작성된 소스 코드 (source code)를 다운받으려면, 다음 링크를 클릭하세요: lec15_strt.cpp

혹시, 이해가 잘 안되는 부분에 대한 질문이 있거나 다루어 줬으면 하는 주제가 있으면, 화면 오른쪽 하단에 "질문하기" 버튼을 이용해 주세요.






발자취

2019-09-11 "키클 코딩랩 - 미국 공학박사 아빠의 코딩 연구소"로 이름 변경
2019-06-28 코딩 교실 공개
2019-03-18 코딩 교실 제작 시작

바로가기
Python 배움터
C/C++ 배움터
About
Contact
Privacy Policy
강의목록
질문하기
처음으로