전체 글 보기 (54) 썸네일형 리스트형 항목 23: 함수보다는 비멤버 비프렌드 함수와 더 가까워지자 웹브라우저를 나타내는 클래스가 하나 있다고 가정해보자. 웹브라우저면 많은 함수를 지원할 것인데, 캐시를 비우는 함수, 방문기록을 없애는 함수, 쿠키를 없애는 함수 등등… 그 중에는 이 모든 것을 한꺼번에 지원하는 함수도 있을 것이다. clearEverything()와 clearBrowser() 둘 중 누가 더 괜찮을까? 정답을 먼저 알려주자면 비멤버함수쪽이 낫다. =================================================== 객체 지향 법칙중에 이런 이야기가 있다. 데이터와 그 데이터를 기반으로 동작하는 함수는 한 데 묶여 있어야 하며 => 이 대목 때문에 멤버 함수가 더 낫다고 얘기한다. 객체 지향이 할 수 있는 만큼 데이터를 캡슐화하라고 주장하고 있지만, 멤버함수 버전 .. 항목 22: 데이터 맴버가 선언될 곳은 private 영역임을 명심하자. 데이터 맴버가 왜 public, protected가 되면 안되는지 알아보자. 일단 public이 왜 안되냐. 문법적 일관성(항목 18 참고) 만약 데이터 맴버가 public이 아니라면, 사용자 쪽에서 어떤 객체에 접근할 수 있는 유일한 수단은 맴버 함수 뿐이다. 어떤 클래스의 public 인터페이스에 있는 것들이 전부 함수뿐이라면, 그 클래스의 맴버에 접근하고 싶을 때는 무조건 괄호를 붙여야하니 이와 관련된 생각을 안할 수 있다. 접근 제어 이게 별로 와닿지 않는 사람도 있을건데, 함수를 사용하면 데이터 맴버의 접근성에 대해 훨씬 정교한 제어를 할 수 있다. 만일 어떤 데이터 맴버를 public으로 내놓았다면 모두가 이 맴버에 대해 읽기,쓰기,접근 권한을 가질 것인데, 이 값을 읽고 쓰는 함수가 있으면 .. 항목 21: 함에서 객체를 반환해야 할 경우에 참조자를 반환하려고 들지 말자. 유리수를 나타내는 객체가 있다고 생각해보자. operator*는 값을 반환함 => 객체의 생성, 소멸에 비용이 들어감 => 그래서 이걸 참조자로 반환하고 싶다. => 가능? 참조자는 그냥 메모리공간에 붙이는 또다른 이름이다. 즉 이미 존재하는 메모리 공간에 또 다른 이름을 붙이는 것이다. 만약 참조자로 반환하고 싶으면 반드시 이미 존재하는 Rational 객체의 참조자여야 한다. 이때 이 객체에는 곱셈에 대한 결과가 저장되어야 한다. 함수 수준에서 새로운 객체를 만든 방법은 딱 2가지이다. 스택에서 만듬(지역변수) 힙에서 만듬(동적 할당 메모리) 우선 전자의 방법부터 보자. 컴파일러도 병신같은 코드라고 주의를 주고 있다. 생성자가 호출되는게 싫어서 참조자를 반환할려는데 result가 생성된다? 노답, 그.. 항목 20: '값에 의한 전달'보다는 '상수 객체 참조자에 의한 전달' 방식을 택하는 편이 대개 낫다. 기본적으로 C++ : call by value 임 => 함수 매개변수는 실제 인자의 copy를 통해 초기화되며, 어떤 함수를 호출한 쪽은 그 함수가 반환한 값의 copy를 돌려받는다. copy => 복사 생성자로 만듬. 이 점 때문에 call by value == high cost 왜 high cost냐? 만약 Person이라는 base class를 상속받는 Student라는 dervied class가 있다고 생각했을 때, bool validateStduent(Student s); 이런 함수가 있다고 치자. 여기에 Student plato; bool platoIsStudent = validateStudent(plato); 여기서 매개변수 s를 초기화 하기 위해 s(plato) 이런식으로 Student의 .. 항목 19: 클래스 설계는 타입 설계와 똑같이 취급하자. 클래스 정의 => 사실 type 정의임 어떤 클래스를 설계할 때는 type을 하나 만든다고 생각하고 최대한 열심히 만들자. 클래스를 설계할 때 여러 고민들이 생기는데.. 새로 정의한 타입의 객체 생성 및 소멸은 어떻게 이루어져야 하나? 이 부분이 어떻게 되느냐에 따라 생성자, 소멸자의 설계가 바뀐다. 그 뿐 아니라 메모리 할당 함수(operator new, operator new[], operator delete, operator delete[])를 직접 작성할 경우에는 이들 함수의 설계에도 영향을 미친다. 객체 초기화는 객체 대입과 어떻게 달라야 하는가? 생성자 vs 대입 연산자의 차이를 결정짓는 요소이다. 초기화와 대입을 햇갈리지 않는 것이 가장 중요한데, 각각에 해당하는 함수 호출이 아예 다르기 때.. 항목 18: 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자 인터페이스 = 함수, 클래스, 템플릿 ….. 이걸 설계 신조로 삼자. "제대로 쓰기엔 쉽고, 엉터리로 쓰기엔 어렵게" 이걸 설계 신조로 삼자. 예를 들어, 날짜를 나타내는 어떤 클래스에 넣을 생성자를 설계하고 있다고 가정하자. 별 문제 없어보인다. 근데 인터페이스 설계 => 개발자의 눈이 아니라 사용자의 눈으로 봐야됨. 사용자가 어떤 실수를 저지를까? 가령 매개변수의 전달 순서가 잘못될 여지가 있다. Date d(30,3,1995); int가 될 수 있기 때문에(항목 2 참조) 타입의 안정성이 떨어진다는 단점이 있다, 타입 안전성이 신경 쓰인다면, 유효한 Month의 집합을 미리 정의해 두어도 괜찮다. 왜 굳이 객체가 아닌 함수로 했나? 이렇게 하면 안되나?? 다른 번역 단위에서 쓰일 경우 문제가 될 여.. 항목 17: new로 생성한 객체를 스마트 포인터에 저장하는 코드는 별도의 한 문장으로 만들자. 처리 우선순위를 알려 주는 함수가 하나 있고, 동적으로 할당된 Widget 객체(자원)에 대해 어떤 우선순위에 따라 처리를 적용하는 함수가 하나 있다고 가정해보자. 자원 관리에는 자원 관리 객체를 사용하는 것이 좋다 => Widget 객체에 대해 스마트 포인터를 사용하도록 만들었다. 이렇게 만들어진 processWidget을 호출해보자. tr1::shared_ptr의 생성자는 explicit으로 되어있기 때문에, 암시적 형 변환이 일어나지 않는다. 그래서 명시적 변환을 해줘야 한다. 이제 컴파일은 잘 되지만, 이 문장은 자원을 흘릴 가능성이 있다.(아니 자원 관리 객체를 쓰는데도 왜 자원이 샘?) 일단 첫번째 인자는 크게 두 개로 나눠어져 있음 "new Widget" 표현식을 쓰는 부분 tr1::shar.. 항목 16: new 및 delete를 사용할 때는 형태를 반드시 맞추자. std::string *stringArray = new std::string[100]; … delete stringArray; 여기서 잘못된 점이 보이냐? => 이 프로그램은 무조건 미정의 동작을 한다. 왜 why => stringArray가 가르키는 100개의 string 객체 중에 99개는 제대로 소멸 과정을 거치지 못할 것이기 때문이다. 우리가 new 연산자를 사용해서 표현식을 꾸미게 되면(즉, new로 어떤 객체를 동적 할당하면), 두 가지의 내부 동작이 진행된다. 메모리가 할당된다. 할당된 메모리에 대해 한 개 이상의 생성자가 호출된다. delete 표현식을 쓸 경우에는 기존에 할당된 메모리에 대해 한 개 이상의 소멸자가 호출된다. 메모리가 해제된다.(이때 operator delete라는 이름의.. 항목 15: 자원 관리 클래스에서 관리하는 자원은 외부에서 접근할 수 있도록 하자 자원 관리 클래스 == good class 실수로 터질 수 있는 자원 누출은 튼튼히 막아 주는 보호벽 역할을 한다. 똑바로 설계된 시스템이면 당연히 자원 누출은 없어야 한다. 하지만 세상은 만만치 않다. 현장에서 열심히 쓰이고 있는 수많은 API들이 자원을 직접 참조하도록 되있어서, 자원 관리 객체를 넘어가서 직접 자원을 주물러야 하는 일이 있을 수 밖에 없다… 우리는 dayHeld를 다음과 같이 쓰고 싶은데 타입이 안맞음 타입을 맞추는 방법 : 명시적, 암시적 반환 명시적: RAII 클래스(shared_ptr)는 get() 이라는 함수를 제공함, 이 함수를 사용하면 각 타입으로 만든 스마트 포인터 객체에 들어 있는 실제 포인터(의 사본)을 얻을 수 있다. 암시적: 제대로된 스마트 포인터들은 다 역참조 .. 이전 1 2 3 4 5 6 다음