Books
[Effective C++] 47. 타입에 대한 정보가 필요하다면 특성정보 클래스를 사용하자
[Effective C++] 47. 타입에 대한 정보가 필요하다면 특성정보 클래스를 사용하자
2022.07.15STL은 컨테이너, 반복자, 알고리즘의 템플릿으로 구성되어 있지만, 이 외에 유틸리티라고 불리는 템플릿도 몇 개 들어있다. 이들 중 하나가 advance라는 템플릿인데, 이 템플릿의 역할은 반복자를 지정된 거리만큼 이동시키는 것이다. template void advance(IterT& iter, DistT d); // iter를 d 단위만큼 전진시킨다. d= 0) { while(d--) ++iter; } else { while(d++) --iter; } } } 위 코드가 제대로 되려면 iter타입인 IterT가 임의 접근 반복자 타입인지를 알아야 하는데, 이를 위해서 컴파일 도중 어떤 주어진 타입의 정보를 얻을 수 있게 하는 객체인 특성정보(traits)를 사용한다. 특성정보(traits) 특성정보는 컴..
[Effective C++] 46. 타입 변환이 바람직할 경우에는 비멤버 함수를 클래스 템플릿 안에 정의해 두자
[Effective C++] 46. 타입 변환이 바람직할 경우에는 비멤버 함수를 클래스 템플릿 안에 정의해 두자
2022.07.15모든 매개변수에 대해 암시적 타입 변환이 되도록 만들기 위해서는 비멤버 함수를 사용해야 한다. 템플릿화 한 Rational 클래스 template class Rational { public: Rational(const T& num = 0, const T& deno = 1) : numerator(num), denominator(deno) {} const T Numerator() const { return numerator; } const T Denominator() const { return denominator; } private: T numerator; T denominator; }; template const Rational operator*(const Rational& lhs, const Ratio..
[Effective C++] 43. 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아 두자
[Effective C++] 43. 템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아 두자
2022.07.08템플릿 클래스를 기본 클래스로 파생 시키는 클래스를 구현 할 상황이 생겼다고 가정해보자. class CompanyA { public: void SendClearText(const string& msg); void SendEncrypted(const string& msg); }; class CompanyB { void SendClearText(const string& msg); void SendEncrypted(const string& msg); }; class MsgInfo {}; template class MsgSender { public: void SendClear(const MsgInfo& info) { string msg; Company c; c.SendClearText(msg); //암시적 인터..
[Effective C++] 42. typename의 두 가지 의미를 제대로 파악하자
[Effective C++] 42. typename의 두 가지 의미를 제대로 파악하자
2022.07.08C++에서 템플릿 매개변수의 경우 class와 typename은 완전히 같은 의미이다. template class Widget; template class Widget; 의존이름(dependent name) vs 비의존 이름(non-dependent name) template void print2nd(const C& container) { if (container.size() >= 2) { C::const_iterator iter(container.begin()); ++iter; int value = *iter; cout
[Effective C++] 41. 템플릿 프로그래밍의 천릿길도 암시적 인터페이스와 컴파일 타입 다형성부터
[Effective C++] 41. 템플릿 프로그래밍의 천릿길도 암시적 인터페이스와 컴파일 타입 다형성부터
2022.07.08클래스의 특성 객체 지향 프로그래밍을 이루는 축은 명시적 인터페이스와 런타임 다형성이다. class Widget { public: Widget(); virtual ~Widget(); virtual size_t size() const; virtual void normalize(); void swap(Widget& other); }; void Func(Widget& w) { if(w.size() > 10) { Widget temp(w); temp.normalize(); temp.swap(w); } } 명시적 인터페이스 Func 함수의 매개변수인 w는 Widget 클래스의 객체이므로 w는 Widget 인터페이스를 지원해야 한다. 이 인터페이스를 소스코드(Widget 클래스가 있는 헤더파일 등)에서 찾으면 확인..
[Effective C++] 40. 다중 상속은 심사숙고해서 사용하자
[Effective C++] 40. 다중 상속은 심사숙고해서 사용하자
2022.07.03다중 상속의 의미 둘 이상의 클래스로부터 상속을 받는 것 다중 상속의 문제점 함수 호출의 모호성 둘 이상의 기본 클래스로부터 똑같은 이름(함수, typedef 등)을 물려받을 가능성이 생긴다는 점이다. 즉, 모호성이 생긴다는 것인데 아래의 예제를 봐보자. class BorrowableItem { public: void checkOut(); ... }; class ElectronicGadget { private: bool checkOut() const; ... }; class MP3Player:public BorrowableItem, public ElectronicGadget {...}; MP3Player mp; mp.checkOut(); // 모호성 발생! 이것은 중복된 함수 호출 중 하나를 골라내는 C..
[Effective C++] 39. private 상속은 심사숙고해서 구사하자
[Effective C++] 39. private 상속은 심사숙고해서 구사하자
2022.07.03private 상속 public 상속은 is-a관계로 나타낸다. 이 관계는 Student가 Person으로부터 public 상속으로 파생된 상태의 클래스 계통이 주어지면 함수 호출을 성공시키기 위해 컴파일러가 Student를 Person으로 암시적 변환을 수행하는 예를 통해 잘 설명이 된다.(항목 32 참고) 그럼 private 상속은 뭘 의미하는 것일까? class Person {...}; class Student: private Person {...}; // private 상속 void eat(const Person& p); void study(const Student& s); Person p; Student s; eat(p); // OK eat(s); // Error, Student는 Person의..
[Effective C++] 38. "has-a(..는..를 가짐)" 혹은 "is-implemented-in-terms-of(..는..를 써서 구현됨)"를 모형화할 때는 객체 합성을 사용하자
[Effective C++] 38. "has-a(..는..를 가짐)" 혹은 "is-implemented-in-terms-of(..는..를 써서 구현됨)"를 모형화할 때는 객체 합성을 사용하자
2022.07.03합성 항목 32에서 public 상속의 의미는 "is-a(.. 는.. 의 일종이다)"라는 사실을 알았다. 객체의 합성 또한 두 가지 의미를 가지고 있는데, "has-a(.. 는.. 를 가짐)"과 "is-implemented-in-terms-of(.. 는.. 를 써서 구현됨)"을 뜻할 수도 있다. Has-a(.. 는.. 를 가짐) class Address {...}; class PhoneNumber {...}; class Person { public: ... private: std::string name; Address address; PhoneNumber voiceNumber; }; 위의 예시를 보면 Person은 name과 address, voiceNumber 등을 가지고 있다. 이렇게 소유의 개념이 ..
[Effective C++] 37. 어떤 함수에 대해서도 상속받은 기본 매개변수 값은 절대로 재정의하지 말자
[Effective C++] 37. 어떤 함수에 대해서도 상속받은 기본 매개변수 값은 절대로 재정의하지 말자
2022.07.02바인딩(binding) 프로그램 소스에 쓰인 각종 내부 요소, 이름, 식별자들에 대해 값 혹은 속성을 확정하는 과정을 일컫는다. 이 과정이 빌드 중에 이루어지면 정적 바인딩이라고 하고, 실행 중에 이루어지면 동적 바인딩이라고 한다. 공식적으로, 정적 바인딩은 선행 바인딩이란 다른 이름으로도 알려져 있고 동적 바인딩은 지연 바인딩이란 이름으로도 알려져 있다. 기본 매개변수 값을 가진 가상 함수를 상속하는 경우 가상 함수는 동적으로 바인딩되지만, 기본 매개변수 값은 정적으로 바인딩된다. 객체의 정적 타입(static type)은 프로그램 소스 안에 놓는 선언문을 통해 그 객체가 갖는 타입이다. 아래의 클래스 계통을 보자. class Shape { public: enum ShapeColor( Red, Gree..
[Effective C++] 36. 상속받은 비가상 함수를 파생 클래스에서 재정의하는 것은 절대 금물!
[Effective C++] 36. 상속받은 비가상 함수를 파생 클래스에서 재정의하는 것은 절대 금물!
2022.07.02결론부터 얘기하면, 상속받은 비가상 함수를 파생 클래스에서 재정의 하지 말자는 것이다. 상속받은 비가상 함수를 파생 클래스에서 재정의한 아래의 예시를 보자. class B { public: void mf(); ... }; class D: public B { public: void mf(); ... }; --- D x; B *pB = &x; pB->mf(); // B::mf()를 호출 D *pD = &x; pD->mf(); // D::mf()를 호출 이렇게 두 가지 동작을 하게 되는 이유는 B::mf 및 D::mf 등의 비가상 함수는 정적 바인딩(static binding)으로 묶이기 때문이다. 즉, pB는 'B에 대한 포인터' 타입으로 선언되었기 때문에 pB를 통해 호출되는 비가상 함수는 항상 B 클래스..
[Effective C++] 35. 가상 함수 대신 쓸 것들도 생각해 두는 자세를 시시때때로 길러 두자
[Effective C++] 35. 가상 함수 대신 쓸 것들도 생각해 두는 자세를 시시때때로 길러 두자
2022.06.26순수 가상 함수가 아닌 가상 함수로 선언되어 있다는 것은 기본 구현이 제공된다는 사실을 34장을 통해 알 수 있었다. 하지만, 정작 다른 작동을 해야 할 때 까먹고 재정의를 하지 않으면 디버깅이 아주 힘들어질 것이다. 이번 장은 이러한 문제를 해결하기 위해 가상 함수를 대체할 무언가가 필요하다는 내용을 담고 있다. 비가상 인터페이스(Non-Virtual Interface: NVI) 관용구를 통한 템플릿 메서드 패턴 가상 함수는 반드시 private 멤버로 두어야 한다고 주장하는 사람들이 제안하는 설계이다.(가상 함수 은폐론) 이 이론에 따르면, healthValue는 public 비가상 함수로 선언하고 내부적으로 실제 동작을 맡은 private 가상 함수를 호출하는 식으로 구현해야 한다. 아래의 코드를 ..
[Effecitve C++] 34. 인터페이스 상속과 구현 상속의 차이를 제대로 파악하고 구별하자
[Effecitve C++] 34. 인터페이스 상속과 구현 상속의 차이를 제대로 파악하고 구별하자
2022.06.25public 상속의 두 가지 개념 1. 함수 인터페이스 상속 2. 함수 구현 상속 이 둘의 차이는 함수 선언과 함수 정의의 차이와 맥을 같이 한다. 아래의 예시를 보자. class Shape { public: virtual void draw() const = 0; // 순수 가상 함수 virtual void error(const std::string& msg); // 단순 가상 함수 int objectID() const; // 비가상 함수 }; class Rectangle: public Shape{}; class Ellipse: public Shape{}; Shape a; // 에러. 인스턴스를 만들 수 없음 Shape는 추상 클래스이다. 왜냐하면 멤버 함수인 draw()가 순수 가상 함수이기 때문이다...