C++ 고급 문법 (17) — private 상속(private Inheritance)
public 상속은 "파생 클래스는 기반 클래스의 일종이다(is-a)"를 뜻해서, 파생 객체를 기반 참조로 넘길 수 있고 기반의 public 인터페이스가 그대로 노출된다. private 상속은 의미가 다르다. 기반 클래스의 구현을 가져다 쓰지만 외부에는…
public 상속은 "파생 클래스는 기반 클래스의 일종이다(is-a)"를 뜻해서, 파생 객체를 기반 참조로 넘길 수 있고 기반의 public 인터페이스가 그대로 노출된다. private 상속은 의미가 다르다. 기반 클래스의 구현을 가져다 쓰지만 외부에는…
생성자를 public이 아닌 곳에 두면 "누가 이 객체를 만들 수 있는가"를 클래스가 직접 정할 수 있다. protected 생성자는 파생 클래스만 기반 부분을 만들게 해서, 순수 가상 함수 없이도 기반 클래스를…
new Widget(7)은 메모리를 할당하는 동시에 생성자를 호출한다. 이 한 줄 안에는 메모리를 얻는 operator new 함수 호출과 그 위에서 객체를 만드는 생성자 호출이 순서대로 들어 있다. 두 단계를 분리해서 보면…
send(1024)가 컴파일되고 1024바이트짜리 버퍼가 전송된다. send는 Buffer를 받는 함수인데, Buffer에 크기를 받는 생성자가 있어서 컴파일러가 임시 객체를 만들어 넘긴 것이다. C++은 생성자와 변환 연산자를 통해 사용자 타입 사이에도 암시적 변환(implicit…
new로 만든 객체는 누군가 정확히 한 번 delete해야 한다. 함수 중간에 return이나 예외가 끼면 해제가 빠지고, 두 곳에서 해제하면 이중 해제가 된다. 스마트 포인터(smart pointer)는 이 "누가 언제 해제하는가"를 타입으로…
로그를 백만 줄 쓰는 코드에서 std::endl을 '\n'으로 바꾸기만 했는데 실행 시간이 수십 배 줄어든다. std::endl은 줄바꿈과 함께 버퍼를 비우는(flush) 조작자이고, flush는 매번 시스템 호출로 이어진다. std::cout에는 이 밖에도 C stdio와의…
벡터 덧셈을 add(a, b) 대신 a + b로 쓰고, 사용자 타입을 std::set에 넣으려면 연산자 오버로딩(operator overloading)이 필요하다. 연산자는 이름이 operator+인 함수일 뿐이지만, 멤버로 둘지 비멤버로 둘지, 무엇을 반환할지에 따라 대칭성·성능·의미가…
qsort, signal, pthread_create처럼 C 라이브러리는 동작을 바꿀 때 함수의 주소를 받는다. C++에서도 C 라이브러리와 연동하거나, 명령 이름과 처리 함수를 표로 묶거나, 플러그인 진입점을 받을 때 함수 포인터(function pointer)를 그대로 쓴다.…
복사 생성자를 따로 쓰지 않아도 Buffer b = a;는 컴파일된다. 컴파일러가 멤버를 하나씩 복사하는 기본 복사 생성자를 만들어주기 때문이다. 멤버가 값 타입이면 이것으로 충분하지만, 생 포인터로 자원을 소유하고 있으면 포인터…
함수 인자를 const T&로 받도록 바꿨더니 그 안에서 부르던 getter가 전부 컴파일 에러를 낸다. getter에 const를 붙이지 않았기 때문이다. 멤버 함수 뒤의 const는 "이 함수는 객체 상태를 바꾸지 않는다"는 약속이다.…