전체 글

상속받은 기본 매개변수 값은 절대로 재정의해서는 안된다. 기본 매개변수 값은 정적으로 바인딩되는 반면, 가상 함수는 동적으로 바인딩되기 때문이다. 상속받은 기본 매개변수 값 재정의 금지 C++에서 상속받을 수 있는 함수의 종류는 가상 함수와 비가상 함수로 두 가지이다. 가상 함수는 동적으로 바인딩되고 비가상 함수는 정적으로 바인딩된다. (정적 바인딩은 선행 바인딩, 동적 바인딩은 지연 바인딩이라고도 불린다.) 또한, 기본 매개변수 값도 정적으로 바인딩된다. class Shpae { public: enum ShapeColor { Red, Green, Blue }; virtual void draw(ShpaeColor color = Red) const = 0; ... }; class Rectangle: pub..
상속받은 비가상 함수를 재정의하는 일은 절대로 하지 마라. 상속받은 비가상 함수 재정의 금지 상속받은 비가상 함수를 재정의하는 일은 절대로 해서는 안된다. class B { public: void mf(); ... }; class D: public B { ... }; D 클래스가 B 클래스로부터 public 상속되어 파생되었고, B 클래스에는 mf라는 이름의 public 멤버 함수가 정의되어 있다고 가정해 보자. D x; // D타입 객체 B *pB = &x; pB->mf(); // B::mf 문제없이 동작할 것이다. 하지만, mf함수를 상속한다면 문제가 발생한다. class D: public B { public: void mf(); ... }; D x; B *pB = &x; pB->mf(); // B:..
가상 함수 대신에 쓸 수 있는 다른 방법으로 NVI 관용구 및 전략 패턴이 있다. 이 중 NVI 관용구는 그 자체가 템플릿 메서드 패턴의 한 예이다. 객체에 필요한 기능을 멤버 함수로부터 클래스 외부의 비멤버 함수로 옮기면, 그 비멤버 함수는 그 클래스의 public 멤버가 아닌 것들을 접근할 수 없다는 단점이 생긴다. tr1::function 객체는 일반화된 함수 포인터처럼 동작한다. 이 객체는 주어진 대상 시그니처와 호환되는 모든 함수 호출성 개체를 지원한다. 가상 함수 대체 방법 가상 함수 대신 사용할 방법들이 몇 가지 있다. 게임 캐릭터 클래스를 설계하는 상황을 가정해 보자. class GameCharacter { public: virtual int healthValue() const; ... }..
인터페이스 상속은 구현 상속과 다르다. public 상속에서, 파생 클래스는 항상 기본 클래스의 인터페이스를 모두 물려받는다. 순수 가상 함수는 인터페이스 상속만을 허용한다. 단순 가상 함수는 인터페이스 상속과 더불어 기본 구현의 상속도 가능하도록 지정한다. 비가상 함수는 인터페이스 상속과 더불어 필수 구현의 상속도 가하도록 지정한다. 인터페이스 상속과 구현 상속의 차이 상속은 크게 두 가지로 나눌 수 있다. 하나는 함수 인터페이스의 상속이고, 또 하나는 함수 구현의 상속이다. 클래스 설계자의 입장에서 보면, 멤버 함수의 인터페이스만을 파생 클래스에 상속받고 싶을 때가 있다. 어쩔 때는 함수의 인터페이스 및 구현을 모두 상속받고 그 상속받은 구현이 오버라이드가 가능하게 만들고 싶을 때도 있다. 반대로, ..
파생 클래스의 이름은 기본 클래스의 이름을 가린다. public 상속에서는 이런 이름 가림 현상은 바람직하지 않다. 가려진 이름을 다시 볼 수 있게 하는 방법으로, using 선언 혹은 전달 함수를 쓸 수 있다. 상속된 이름이 숨겨지는 것을 피해라 상속과 관련된 이름 가리기 현상을 보기 전, 이해를 돕기 위해 기본 변수에 대한 이름 가리기 규칙을 살펴보자. int x; void someFunc() { double x; std::cin >> x; } 값을 읽어 x에 넣는 위의 문장에서 실제로 참조하는 x는 전역 변수 x가 아니라 지역 변수 x이다. 이유는 안쪽 유효범위에 있는 이름이 바깥쪽 유효범위에 있는 이름을 가리기 때문이다. 컴파일러가 someFunc의 유효범위 안에서 x라는 이름을 만나면, 일단 그..
public 상속의 의미는 is-a이다. 기본 클래스에 적용되는 모든 것들이 파생 클래스에 그대로 적용되어야 한다. 왜냐하면 모든 파생 클래스 객체는 기본 클래스 객체의 일종이기 때문이다. public 상속 모형은 반드시 is-a public 상속은 is-a이다. 이 사실을 무조건 기억해야 한다. B(Base) 클래스로부터 D(Derived) 클래스를 파생시켰다면, D 타입으로 만들어진 모든 객체는 B타입의 객체이지만, 그 반대는 되지 않는다. 다시 말해 B는 D보다 더 일반적인 개념을 나타내며, D는 B보다 더 특수한 개념을 나타낸다. B타입의 객체가 쓰일 수 있는 곳에는 D타입의 객체가 쓰일 수 있다. D타입의 모든 객체는 B타입의 객체도 되기 때문이다. C++은 public 상속의 문법은 다음과 같..
컴파일 의존성을 최소화하는 작업의 배경이 되는 가장 기본적인 아이디어는 정의 대신에 선언에 의존하게 만드는 것이다. 이러한 방법으로는 핸들클래스와 인터페이스 클래스이다. 라이브러리 헤더는 그 자체로 모든 것을 갖추어야 하며 선언부만 갖고 있는 형태여야 한다. 이 규칙은 템플릿의 여부와 관계없이 동일하게 적용해야 한다. 파일 사이의 컴파일 의존성을 최대로 줄이자 C++은 헤더와 구현부를 두 파일로 분리하여 구현하는 것이 일반적이다. 프로그램의 규모가 커지면 여러 개의 파일이 존재할 것이다. 그러다 보면 파일들 사이의 컴파일 의존성이 올라가 빌드 속도도 느려지고 에러가 발생할 여지가 생긴다. class Person { public: Person(const std::string& name, const Date..
hvv_an
이미난