💙ref.

스콧 마이어스, Effective C++ [3판], 곽용재(역), 프로텍미디어, 2015


1. C++기본 용어

1.1. 선언

선언 (declaration)

  • 코드에 사용되는 ‘어떤 대상’의 이름과 타입을 컴파일러에게 알림
    • 구체적인 세부사항은 기재하지 않음


[code] declaration example
1
2
3
4
5
6
7
extern int x;	// 객체 선언
std::size_t numdigits(int number);	// 함수 선언

class Widget;	// 클래스 선언

template<typename T>	// 템플릿 선언
class GraphNode;
  • int x : built-in(기본제공) 타입도 ‘객체’에 포함

  • std namespace : C++의 표준 라이브러리 구성요소가 모두 포함된 네임스페이스

    • C의 라이브러리와 C++ 라이브러리에 공통된 기능 일부 내장
      • 어떤 헤더를 #include하느냐애 따라 라이브러리 결정
  • size_t : 부호 없는 정수 타입을 typedef로 정의

    • C++에서 개수를 셀 때 size_t 사용

      eg) STL 컨테이너의 원소 개수 등

    • 일반적으로 operator[] 함수를 개발자가 정의할 때도 size_t를 받도록 구현함


1.2. 시그너처

시그너처(Signature)

  • 모든 함수의 선문에 나오는 매개변수 리스트와 반환 타입

    • numDigits 함수의 시그너처 : std::size_t(int)

      eg) int 하나를 취하고 std::size_t를 반환하는 함수

    단, ‘시그너처’의 공식 C++ 정의에서는 함수 반환 타입을 제외한다! 편의성을 위해 포함했다고 말한다.


1.3. 정의

정의(Definition)

  • 선언에서 빠진 구체적인 세부사항을 컴파일러에게 전달
    • 컴파일러는 해당 객체에 대한 메모리 마련
  • 정의 제공 기능
    • 함수/템플릿 정의: 코드 본문 제공
    • 클래스/템플릿 정의: 클래스 혹은 템플릿 멤버 제공


[code] definition example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int x;	// 객체 정의

std::size_t numDigits(int number)	// 함수 정의
{
    std::size_t digitSoFar = 1;
    
    while ((number/10) != 0) ++digitsSoFar;
    // 반환 값: 매개변수에 들어 있는 숫자 개수
    return digitsSoFar;
}

class Widget	// 클래스 정의
{
public:
    Widget();
    ~Widget();
    ...
};

template<typename T>	// 클래스 템플릿 정의
class GraphNode
{
public:
    GraphNode();
    ~GraphNode();
    ...
};


1.4. 초기화

초기화(Initialization)

  • 어떤 객체에 최초의 값을 부여하는 과정
    • 사용자 정의 타입으로 생성한 객체의 경우, 생성자에 의해 초기화
  • 기본 생성자(Default Constructor)
    • 어떤 인자도 주어지지 않은 상태로 호출될 수 있는 생성자
      • 매개변수가 없거나 모든 매개변수가 기본 값을 갖고 있을 경우


[code] Initialization example
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 기본 생성자
class A
{
public:
	A();
};

// 기본 생성자
class B
{
public:
	explicit B(int x = 0, bool b = true);
}

// 기본 생성자x
class C
{
public:
	explicit C(int x);
}
  • explicit : 선언된 생성자는 암시적인 타입 변환을 수행하는 데 쓰이지 않음
    • 개발자가 예상하지 못한 타입 변환 방지
    • 암시적 타입 변환에 생성자가 사용되지 않는다면 explicit선언을 적극 권장함!!


[code] explicit example
1
2
3
4
5
6
1. void doSomething(B bObject);
2. B bObj1;
3. doSomething(bObj1);
4. B bObj2;
5. doSomething(28);
6. doSomething(B(28))
  1. B 타입의 객체를 하나 받는 함수
  2. B 타입의 객체
  3. B 객체를 doSomething으로 넘김
  4. int인자 28로부터 B 객체 생성
  5. 에러! doSomethingB를 취해야 함(단순 int x)
  6. B 클래스의 생성자로 int에서 B로 명시적 변환(캐스팅)


1.5. 복사 생성자

복사 생성자(Copy Constructor)

  • 객체 초기화를 위해 같은 타입의 다른 객체로부터 초기화할 때 호출되는 함수
    • 값에 의한 객체 전달을 정의하는 함수!


복사 대입 연산자(Copy Assignment Operator)

  • 같은 타입의 다른 객체에 어떤 객체의 값을 복사하는 용도로 쓰이는 함수


[code] copy constructor 1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
class Widget
{
public:
	Widget();	// 기본 생성자
	Widget(const Widget& rhs);	// 복사 생성자
	Widget& operator=(const Widget& rhs);	// 복사 대입 연산자
	...
};

Widget w1;	// 기본 생성자 호출
Widget w2(w1);	// 복사 생성자 호출
w1 = w2;	// 복사 대입 연산자 호출

Widget w3 = w2; // 복사 생성자 (!= 복사 대입 연산자)
  • w1 = w2 != Widget w3 = w2 // 복사 생성자 '='
    • 새로운 객체가 정의되지 않은 상황에서 생성자 호출 불가능
      • 복사 대입 호출
    • 객체가 새로 정의될 때는 생성자가 호출
      • 복사 대입 호출 불가능


[code] copy constructor 2
1
2
3
4
bool hasAcceptableQuality(Widget w);
...
Widget aWidget;
if(hasAcceptableQuality(aWidget)) ...
  • w : hasAcceptableQuality 함수로 매개변수 값이 넘겨짐
    • 실제 호출에서 aWidget => w로 복사

      • 복사 과정에서 Widget의 복사 생성자 사용

      => *'값에 의한 전달(pass-by-value)'* : 복사 생성자 호출


1.6. STL

  • 표준 템플릿 라이브러리

    • 컨테이너, 반복자, 알고리즘 및 이들과 관련된 기능들이 집결한 결정체
    • 해당 기능들이 함수 객체로 구현되어 있음
      • 함수 객체는 함수 호출 연산자 operator()를 오버로드한 클래스로 생성
  • 미정의 동작(undefined behavior)

    • C++으로 사용되는 구문 요소들 중 몇 개는 동작 자체가 정의되어 있지 않음

      => 실행 시간에 어떤 현상이 터질지 확실히 예측 불가능

미정의 동작을 일으키는 예제

1
2
3
4
5
6
7
8
9
10
11
12
int *p = 0;			// p== 널포인터

// 널포인터를 역참조하면 미정의 동작 발생
std::cout << *p;

// name은 크기가 6인 배열임
// 문자열 배열은 반드시 마지막 널문자 고려할 것!!
char name[] = "Darla";

// 유효하지 않은 배열 원소지정번호로 참조하려고 하면 미정의 동작 발생
char c = name[10];


+) C++에서는 인터페이스 기능을 제공하고 있지 않지만 순수 가상 함수를 통해 인터페이스 기능을 구현할 수 있다.

  • 클라이언트(client)
    • 인터페이스를 사용하는 대상
      • 함수를 호출하는 코드, 코드를 작성했거나 유지보수하는 사람 등


2. 교재 참고사항


2.1. 이름짓기에 대한 규약

  • 좌변과 우변의 약자를 각각 lhs, rhs로 지정
    • 일반적으로 이항 연산자(operator==, operator* 등)를 구현하는 함수의 매개변수로 쓰임
      • eg) operator*(a, b) => const Rational operator*(const Rational& lhs, const Rational rhs)l
  • 포인터 이름 선언 시, 타입 T의 객체에 대한 포인터를 pt로 작성
    • “T에 대한 포인터”


포인터 예제 코드

1
2
3
4
5
6
7
Widget *pw;

class Airplane;
Airplane *pa;

class GameCharacter;
GameCharacter *pgc
  • 참조자에 대해서도 유사한 규칙 사용
    • eg) Widget에 대한 참조자 rw


Leave a comment