서적 정리/Effective C++56 46.타입 변환이 바람직한 경우에는 비멤버 함수를 클래스 템플릿 안에 정의해 두자 모든 매개변수에 대해 암시적 타입 변환이 되도록 만들기 위해서는 비멤버 함수밖에 방법이 없다. template class Rational { public: Rational(const T& numerator = 0, const T& denominator = 1) : n(numerator), d(denominator) {} const T Numerator() const { return n; } const T Denominator() const { return d; } private: T n, d; }; template const Rational operator*(const Rational& lhs, Rational& rhs); //비멤버 함수 int main() { Rational oneHalf(1, 2);.. 2021. 12. 25. 45."호환되는 모든 타입"을 받아들이는 데는 멤버 함수 템플릿이 직방! 스마트 포인터(smart pointer)는 포인터처럼 동작하면서 힙 기반 자원인 동적 할당할 때 자동으로 삭제해주는 편리함이 있다. 하지만 포인터는 스마트 포인터로 대신할 수 없는 특징이 있다. 그 중 하나가 암시적 변환(implicit conversion)이다. 파생 클래스 포인터는 암시적으로 기본 클래스로 변환되고, 비상수 객체에 대한 포인터는 상수 객체에 대한 포인터로 암시적 변환이 가능하든 것이다. class Top {}; class Middle : public Top {}; class Bottom : public Middle {}; int main() { Top* pt1 = new Middle; //Middle* -> Top* 변환 Top* pt2 = new Bottom; //Bottom* ->.. 2021. 12. 24. 44.매개변수에 독립적인 코드는 템플릿으로부터 분리시키자 템플릿은 코딩 시간 절약, 코드 중복 회피가 가능하게 해주는 기능이다. 하지만, 아무생각없이 템플릿을 사용하면 코드 비대화(code bloat)가 초래될 수 있다. 똑같은 내용의 코드와 데이터가 여러 개로 중복되어 이전 파일로 생성될 수 있다는 뜻이다. 소스 코드만 보면 단정해 보이지만, 목적 코드는 비대해 질 수 있다. 우리는 템플릿으로 인해 코드 비대화를 예방할 방법을 숙지해야 한다. 공통성 및 가변성 분석(commonality and variability analysis) 만약 현재 만들고 있는 클래스의 어떤 부분이 다른 클래스의 어떤 부분과 똑같다는 사실을 발견한다면, 그 공통 부분을 양쪽에 두지 않는 것이 합리적인 코딩이다. 즉, 공통 부분을 별도의 새로운 클래스에 옮긴 후, 클래스 상속 혹은 .. 2021. 12. 24. 43.템플릿으로 만들어진 기본 클래스 안의 이름에 접근하는 방법을 알아 두자 템플릿 클래스를 기본 클래스로 파생 시키는 클래스를 구현 할 상황이 생긴다. 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); //암시적 인터페이스 } v.. 2021. 12. 23. 42.typename의 두 가지 의미를 제대로 파악하자 처음 알게된 사실인데 템플릿을 선언할 때 두 가지 방식이 있다고 한다. template class Widget; template class Widget; C++에서 템플릿 매개변수의 경우 class 와 typename은 완전히 같은 의미이다. 의존 이름(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 2021. 12. 23. 41.템플릿 프로그래밍의 천릿길도 암시적 인터페이스와 컴파일 타임 다형성부터 명시적 인터페이스와 런타임 다형성 객체 지향 프로그래밍(Obejct-Oriented Programming : OOP)을 이루는 축은 명시적 인터페이스(explicit interface)와 런타임 다형성(runtime polymorphism)이다. 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는 .. 2021. 12. 22. 40.다중 상속은 심사숙고해서 사용하자 학원이든 학교든 다중 상속(multiple inheritance : MI)는 피하라고 배웠다. 둘 이상의 기본 클래스로부터 똑같은 이름을 상속받을 경우 모호성이 발생하기 때문이다. class A { void Check(); }; class B { bool Check(); }; class C : public A, public B { }; int main() { C c; c.Check(); //에러 system("Pause"); return 0; } 컴파일러는 어떤 함수가 접근 가능한 함수인지 알아보기 전에 호출에 의해 최적으로 일치하는(best-math) 함수인지를 먼저 확인한다. 최적 일치 함수를 찾은 후 함수의 접근가능성을 점검한다는 애기이다. 모호성을 해소하려면, 호출할 기본 클래스의 함수를 명시적으.. 2021. 12. 22. 39.private 상속은 심사숙고해서 구사하자 지금까지 내가 설계한 클래스에서 상속을 사용하면 public 상속만 사용했던 것 같다. 상속이라 하면 기본 클래스의 모든 것을 받으니 public 상속으로 대부분 처리가 가능해서 그랬던 것 같다. 이번에는 private 상속으로 해보겠다. class Person {}; class Student : private Person {}; void eat(const Person& p); int main() { Person p; Student s; eat(p); //문제x eat(s); //에러 system("Pause"); return 0; } eat 함수는 Person 클래스를 매개변수로 갖고 있다. public 상속이였다면 Student 객체는 eat 함수의 매개변수로 사용할 수 있었겠지만, private 상.. 2021. 12. 22. 38."has-a(...는 ...를 가짐)" 혹은 "is-implemented-in-terms-of(...는 ...를 써서 구현됨)"를 모형화할 때는 객체 합성을 사용하자 합성(composition)이란 어떤 타입의 객체들이 그와 다른 타입의 객체들을 포함하고 있을 경우 그 타입들 사이의 관계를 일컫는다. 포트폴리오에 히트박스, 애니메이션, 모델 등 클래스를 모두 포함시킨 캐릭터 클래스를 생각하면 된다. class Address{}; class PhoneNumber{}; class Person { private: string name; Address address; PhoneNumber voiceNumber; PhoneNumber faxNumber; }; string, Address, PhoneNumber를 합성하여 Person 클래스를 구현하였다. public 상속은 is-a(...는 ...의 일종이다)라는 의미인데, 객체 합성 역시 같은 의미를 갖는다. 실제로는 뜻을 .. 2021. 12. 22. 이전 1 2 3 4 5 ··· 7 다음