요약
이 수업은 함수를 다루는 강좌의 5단원을 마무리한다. 함수의 선언에서 재귀에 이르는 개념의 사슬을, 호출 스택, 계약, 매개변수의 전달, 변수의 유효 범위와 수명, 단계적 세분화에 의한 설계를 거쳐 다시 세운다. 그 가운데 어느 언어에서나 통하는 것과 C++에 고유한 것을 구별한다. 단원의 정의되지 않은 동작을 모으면서, 컴파일러가 경고하는 것, 새니타이저가 멈추는 것, 아무도 알려 주지 않는 것을 함께 싣는다. 마무리 평가에서 입문 평가의 기능을 되풀이한다. 그리고 단원 전체를 엮는 여섯 도전 과제로 끝난다.
학습 목표
- 문제를 함수들로 분해하되, 각 함수에 인터페이스와 계약(사전 조건과 사후 조건)을 주고, 각각을 따로 테스트한다.
- 각 매개변수의 전달 방식과 결과를 반환하는 방식을 고르고, 그 선택을 정당화한다.
- 문제를 재귀로 풀고, 그 정확성을 귀납법으로, 그 종료를 감소하는 척도로 증명하며, 호출 횟수로 그 비용을 어림한다.
- 단원의 정의되지 않은 동작(
return문이 없는 경로, 댕글링 참조, 오버플로가 나는 결과, 바닥난 스택)을 알아보고, 그것이 없는 프로그램으로 다시 쓴다. - 단원에서 배운 것 가운데 어느 언어에서나 통하는 것과 C++에 고유한 것을 구별한다.
단원에서 이룬 것
이 단원은 문제를 이름 붙은 부분들로 분해하되 각 부분에 인터페이스와 계약을 주는 법과, 문제를 재귀로 푸는 법을 가르치려 했다. 이 목적은 도입 수업이 이미 아는 것으로 선언한 것에만 기대어 이루어졌다. 4단원의 반복문과 그 불변식과 변량, 1.1강의 명세, 그리고 2단원의 메모리 모형이다. 복사한 반복문이 엉뚱한 수의 약수를 더하던 친화수 프로그램은, 이제 계약에 비추어 한 번만 검증된 함수 하나로 쓰인다.
함수
함수 수업은 함수를 선언하고, 정의하고, 호출하는 법을 가르쳤고, 세 시점을 구별했다. 컴파일할 때 각 호출은 그보다 앞에 나온 선언에 비추어 검사된다. 링크할 때 정의를 찾는다. 실행할 때 인자를 계산하고, 호출 스택에 프레임을 만들고, 제어가 본체로 넘어간다. void 타입이 아닌 함수가 return 문 없이 끝에 이르는 것은 정의되지 않은 동작임을 보였고, 계약, 곧 사전 조건과 사후 조건으로 마무리했다. 계약은 호출하는 쪽과 함수 사이에 책임을 나눈다.
매개변수와 유효 범위
매개변수와 유효 범위 수업은 데이터가 어떤 길로 들어오고 결과가 어떤 길로 나가는지를 살폈다. 값으로 전달된 매개변수는 복사본이고, 참조로 전달된 매개변수는 호출하는 쪽 칸의 두 번째 이름이며, 상수 참조는 복사하지 않고 읽는다. 여기서 선택의 규칙(작은 것은 값, 읽기만 하는 큰 것은 상수 참조, 수정 자체가 목적일 때만 참조)이 나오고, 여러 결과에는 std::pair 타입과 std::tuple 타입을 구조적 바인딩과 함께 쓴다. 이름의 유효 범위(텍스트의 성질)와 변수의 수명(실행의 성질)을 구별했고, 자기 칸보다 오래 사는 참조로 끝났다.
함수로 설계하기
함수로 설계하기 수업은 단계적 세분화로 어떤 함수를 쓸지 결정하는 법을 가르쳤다. 선언만 된 함수들을 호출하는 짧은 main 함수를 쓰고 각 함수로 내려가는 것이며, 그러면 분해는 나무로 그려진다. 좋은 인터페이스의 기준과 “함수 하나에 작업 하나”라는 규칙을 그 징후(이름 속의 접속사, 한 화면에 들어가지 않는 함수, 플래그) 및 전역 변수 같은 숨은 효과와 함께 정했고, 오버로딩을 그 우선순위와 모호한 호출과 함께 소개했으며, 4단원의 알고리즘을 따로 테스트한 함수들로 다시 썼다.
재귀
재귀 수업은 함수가 문제의 더 작은 사례를 풀기 위해 자기 자신을 호출할 수 있음을 가르쳤다. 더 작은 호출이 올바르다고 가정하여 귀납법으로 정확성을 증명했고, 감소하는 자연수 척도로 종료를 증명했다. 쌓였다가 걷히는 프레임을 스택에서 따라갔고, 스택이 어떻게 바닥나는지 보였다. 결과의 자료형이 스택보다 훨씬 먼저 오버플로가 난다는 점을 경고했다. 그리고 피보나치 수의 재귀 버전과 반복 버전을 비교했다. 번의 호출 대 29 번의 덧셈이다(의 경우).
콘텐츠를 불러오는 중…