C++/Effective C++

호환되는 모든 타입을 받아들이는 멤버 함수를 만들려면 멤버 함수 템플릿을 사용해라. 일반화된 복사 생성 연산과 일반화된 대입 연산을 위해 멤버 템플릿을 선언했다 하더라도, 보통의 복사 생성자와 복사 대입 연산자는 직접 선언해야 한다. 호환되는 모든 타입을 받아들이는 데는 멤버 함수를 사용 스마트 포인터는 그냥 포인터처럼 동작하면서도 포인터가 주지 못하는 기능을 갖고 있다. 예를 들면 힙 기반 자원의 삭제를 지원하는 auto_ptr이나 tr1::shared_ptr 객체가 있다. STL 컨테이너의 반복자도 스마트 포인터와 같다. 포인터에도 스마트 포인터로 대신할 수 없는 특징이 있다. 그중 하나가 암시적 변환을 지원하는 점이다. 파생 클래스 포인터는 암시적으로 기본 클래스 포인터로 변환되고, 비상수 객체에 ..
템플릿을 사용하면 비슷비슷한 클래스와 함수가 여러 개 만들어진다. 따라서 템플릿 매개변수에 종속되지 않은 템플릿 코드는 비대화의 원인이 된다. 비타입 템플릿 매개변수로 생기는 코드 비대화의 경우, 템플릿 매개변수를 함수 매개변수 혹은 클래스 데이터 멤버로 대체함으로써 비대화를 없앨 수 있다. 타입 매개변수로 생기는 코드 비대화의 경우, 동일한 이진 표현구조를 가지고 인스턴스화되는 타입들이 한 가지 함수 구현을 공유하게 만듦으로써 비대화를 감소시킬 수 있다. 매개변수에 독립적인 코드는 템플릿에서 분리 템플릿은 코딩 시간 절약, 코드 중복 회피에 효과가 있다. 하지만, 아무 생각 없이 템플릿을 사용하면 똑같은 내용의 코드와 데이터가 여러 개 중복되어 이진 파일로 만들어지는 코드 비대화가 생길 수 있다. 코드..
파생 클래스 템플릿에서 기본 클래스의 이름을 참조할 때는, this-> 를 접두사로 붙이거나 기본 클래스 한정문을 명시적으로 써 주면 된다. 템플릿으로 만들어지는 기본 클래스의 이름에 접근하는 법 메시지 전송 응용프로그램을 만든다고 가정해 보자. 전송용 메시지는 암호화될 수도 있고 비가공텍스트 형태일 수 있다. 만약 어떤 메시지가 어디로 전송될지를 컴파일 도중에 결정할 수 있는 충분한 정보가 있다면, 템플릿 기반의 방법을 쓸 수 있다. class CompanyA { public: ... void sendCleartext(const std::string& msg); void sendEncrypted(const std::string& msg); ... }; class CompanyB { public: .....
템플릿 매개변수를 선언할 때, class 및 typename은 서로 바꾸어 써도 무방하다. 중첩 의존 타입 이름을 식별하는 용도에는 반드시 typename을 사용한다. 단, 중첩 의존 이름이 기본 클래스 리스트에 있거나 멤버 초기화 리스트 내의 기본 클래스 식별자로 있는 경우에는 예외이다. typename의 두 가지 의미 class와 typename은 차이가 없다. template class Widget; template class Widget; 템플릿의 타입 매개변수를 선언할 때는 class와 typename의 뜻이 완전히 똑같다. 하지만 항상 class와 typename이 똑같지 않다. typename을 무조건 사용해야 할 때가 있다. 이 경우가 언제인지를 알아보려면 템플릿 안에서 참조할 수 있는 이..
클래스 및 템플릿은 모두 인터페이스와 다형성을 지원한다. 클래스의 경우, 인터페이스는 명시적이며 함수의 시그니처를 중심으로 구성되어 있다. 다형성은 프로그래밍 실행 중에 가상 함수를 통해 나타난다. 템플릿 매개변수의 경우, 인터페이스는 암시적이며 유효 표현식에 기반을 두어 구성된다. 다형성은 컴파일 중에 템플릿 인스턴스화와 함수 오버로딩 모호성 해결을 통해 나타난다. 템플릿 프로그래밍의 암시적 인터페이스 & 컴파일 타임 다형성 객체 지향 프로그래밍에서 명시적 인터페이스와 런타임 다형성은 매우 중요하다. class Widget { public: Widget(); virtual ~Widget(); virtual std::size_t size() const; virtual void normalize(); vo..
다중 상속은 단일 상속보다 복잡하다. 새로운 모호성 문제를 일으킬 뿐만 아니라 가상 상속이 필요해질 수 있다. 가상 상속을 쓰면 크기 비용, 속도 비용이 늘어나며, 초기화 및 대입 연산의 복잡도가 커진다. 따라서 가상 기본 클래스에는 데이터를 두지 않는 것이 실용적이다. 다중 상속을 적법하게 쓸 수 있는 경우가 있다. 여러 경우 중 하나는 인터페이스 클래스로부터 public 상속을 시킴과 동시에 구현을 돕는 클래스로부터 private 상속을 시키는 것이다. 다중 상속 다중 상속(Multiple inheritance: MI)을 하게 되면 둘 이상의 기본 클래스로부터 똑같은 이름을 물려받을 가능성이 생긴다. 즉, 다중 상속 때문에 모호성이 생길 수 있다. class BorrowbleItem { public:..
private 상속의 의미는 is-implemented-in-terms-of이다. 파생 클래스 쪽에서 기본 클래스의 protected 멤버에 접근해야 할 경우 혹은 상속받은 가상 함수를 재정의해야 할 경우에 private 상속이 의미가 있다. 객체 합성과 달리, private 상속은 공백 기본 클래스 최적화(EBO)를 활성화시킬 수 있다. private 상속 public 상속은 is-a 관계로 나타낸다. 하지만, private 상속은 is-a 관계로 나타내지 않는다. class Person { ... }; class Student: private Person { ... }; void eat(const Person& p); void study(const Student& s); Person p; Studne..
객체 합성의 의미는 public 상속이 가진 의미와 완전히 다르다. 응용 영역에서 객체 합성의 의미는 has-a이다. 구현 영역에서는 is-implemented-in-terms-of의 의미이다. has-a, is-implemented-in-terms-of 객체 합성 어떤 타입의 객체들이 그와 다른 타입의 객체들을 포함하는 경우를 합성이라고 한다. class Address { ... }; class phoneNumber { ... }; class Person { public: ... private: std::string name; Address address; PhoneNumber voiceNumber; PhoneNumber faxNumber; }; Person객체는 string, Address, Phon..
상속받은 기본 매개변수 값은 절대로 재정의해서는 안된다. 기본 매개변수 값은 정적으로 바인딩되는 반면, 가상 함수는 동적으로 바인딩되기 때문이다. 상속받은 기본 매개변수 값 재정의 금지 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:..
hvv_an
'C++/Effective C++' 카테고리의 글 목록 (2 Page)