목록C++ (40)
방프리
항목 26 : 변수 정의는 늦출 수 있는 데까지 늦추는 근성을 발휘하자 - 하나의 변수를 호출하면 반드시 그 변수를 위한 생성자와 소멸자가 호출되기 마련입니다. 가끔 코딩을 하다보면 반드시 사용하진 않더라도 필요한 변수들을 볼 수 있습니다. 가령 일정 길이 이상의 비밀번호에 대해서만 암호화를 진행하는 코드를 짠다고 한다면 이렇게 작성하는 분들도 계실 것 입니다. std::string encryptPassword(const std::string& password) { using namespace std; string encrypted; //비밀번호가 길 때를 대비해 암호화 변수를 만듭니다. if( password.length() < MinimumPasswordLength ) { throw logic_err..
항목 25 : 예외를 던지지 않는 swap에 대한 지원도 생각해보자 - swap은 개발자들도 다들 알다싶히 값을 서로 교환하는 알고리즘을 말합니다. 딱히 알고리즘이라고 말하기도 뭐한... 그런 함수이죠 가장 기초적인 함수가 왜 이 항목에서 등장할까요? 필자는 STL에 이 함수가 포함된 이래, 예외 안전성 프로그래밍에선 없어선 안될 감초 역활로써, 자기 대입 현상의 가능성에 대처하기 위한 대표적인 매커니즘으로서 널리 사랑받아왔다고 설명합니다. 그러면서 이 swap 함수를 사용하면서 비용을 복사라는 비용을 지불하게 되는데 이 항목에서 그 비용을 지불하지 않는 방법을 설명해줍니다. 바로 다른 타입의 실제 데이터를 가리키는 포인터가 주성분인 타입의 객체(pimpl)을 소개해주는데요. 이런 객체 전용의 함수를 제..
항목 24 : 타입 변환이 모든 매개변수에 대해 적용되어야 한다면 비멤버 함수를 선언하자. - 클래스를 생성하고 그 클래스에 대한 연산자를 오버라이딩할 때 항상 멤버 함수를 오버라이딩을 해왔습니다. 그로인해 이러한 연산 코드도 가능했죠. ex) class Point { private: int x, y; public : Point(); ~Point(); const Point operator*(const Point& arg); }; 하지만 이 함수가 모든 곳에 적용이 되진 않습니다. 가령 ex) Point p1, p2; p2 = 2 * p1; // 에러 발생! 이러한 코드가 있다면 Point 클래스의 재정의 된 *이 아닌 상수 2의 * 연산자가 되어버리기 때문입니다. 즉, 곱셈의 주체가 클래스 객체가 아니라..
항목 23 : 멤버 함수보다는 비멤버 비프렌드 함수와 더 가까워지자 -객체지향적으로 생각한다면 멤버 함수는 가장 뛰어난 함수입니다. 관련 클래스의 데이터를 기반으로 동작하기도 하고, 관련 클래스에 묶여있기 때문입니다. 하지만 이는 잘못된 정보라고 필자는 말합니다. 멤버 함수의 남용은 객체지향의 기본 3대 요소 중 하나인 캡슐화를 해칠 가능성이 매우 크다고 합니다. 또한 비멤버 함수를 사용하면 패키징 유연성이 높아지는 장점도 가질 수 있습니다. 한마디로 멤버 함수가 적으면 적을 수록 해당 클래스의 멤버 변수에 접근하는 빈도가 점점 줄어든다는 뜻입니다. 비프렌드 함수도 마찬가지 입니다. 프렌드 함수를 사용하게 되면 해당 클래스의 멤버 변수를 private로 선언하더라도 접근이 가능해지기 때문에 캡슐화의 의도..
항목 22 : 데이터 멤버가 선언될 곳은 private 영역임을 명심하자! C++에서 클래스를 배울 때 초반에 배우는 것으로 접근지정자( 접근 한정자라고도 합니다.)를 배우게 됩니다. 즉, 멤버변수 혹은 멤버함수에 접근할 수 있는 객체를 제한하는 것이죠. 총 3가지 키워드가 있으며 각각 private, protected, public이 있습니다. 이 부분에서 데이터 멤버(멤버변수)가 public이 되면 안되는 이유를 먼저 살펴보겠습니다. (1) 문법적 일관성 유지 유지보수 기간이 길어질 수록 코드의 양은 반드시 늘어납니다. 양이 많아질 수록 문제되는 것이 사람이 코딩하는 것이기 때문에실수할 확률이 커지지요. 이 실수를 줄이는 방법은 굉장히 다양한데 문법적 일관성도 그 중 하나입니다. 멤버변수, 멤버함수 ..
항목 21 : 함수에서 객체를 반환해야할 경우에 참조자를 반환하려고 들지 말자 일반적인 데이터 타입에서 사용되는 연산자(operator)는 미리 정의되어 있지만, 사용자가 정의한 클래스의 경우 연산자가 정해져 있지 않습니다. 이 덕분에 직접 operator 키워드를 통해 연산자를 재정의해서 사용하지요. 이 때 프로그래머들이 쉽게 실수할 수 있는 간단한 예를 살펴보며 하나씩 문제점을 짚어보겠습니다. (공통으로 사용되는 변수) Rational a(1, 2); // a = 1/2 Rational b(3, 5); // b = 3/5 Rational c = a * b; // c는 3/10이어야 합니다. 예제1) const Rational& operator* (const Rational& lhs, const Rat..
항목 20 : '값에 의한 전달'보다는 '상수객체 참조자에 의한 전달' 방식을 택하는 편이 대개 낫다. 보통 함수의 매개변수값으로 값을 전달할 때 이런 방식으로 많이 사용합니다. void CheckStudent( Student s ) { ... // 학생인지 아닌지 확인하는 소스 } 흔한 C++ 기본 서적에서도 많이 사용하고 있고, 실제로도 많이 사용하고 있습니다. 이번 항목은 이 흔한 코드를 좀 더 최적화를 할 수 있게 만드는데에 목적이 있습니다. 바로 값 복사입니다. 무슨 값 복사라는 사람들을 위해 매개변수로 전달되는 Student 타입의 변수 s가 호출되는 과정을 알아보겠습니다. int main(void) { Student m_cStudent; CheckStudent( m_cStudent ); } ..
항목 19 : 클래스 설계는 타입 설계와 똑같이 취급하자 좋은 클래스를 설계할 때 다음의 사항을 고려해보는 것이 좋습니다. (1) 새로 정의한 타입의 객체 생성 및 소멸은 어떻게 이루어져야 하는가? - 이 부분이 어떻게 되느냐에 따라 클래스 생성자 및 소멸자의 설계가 바뀝니다. 그 뿐 아니라 메모리 할당 함수를 직접 작성할 경우에는 이들 함수의 설계에도 영향을 미칩니다. (2) 객체 초기화는 객체 대입과 어떻게 달라야 하는가? - 각각 해당하는 함수의 호출이 다르기 때문에 초기화와 대입 간의 차이점에 대해 알고 있어야 합니다. (3) 새로운 타입으로 만든 객체가 값에 의해 전달되는 경우에 어떤 의미를 줄 것인가? - 복사 생성자를 유의하고 있으면 됩니다. (4) 새로운 타입이 가질 수 있는 적법한 값에 ..