Effective C++ 3판12 항목 12. 객체의 모든 부분을 빠짐없이 복사하자. 내용 객체의 안쪽 부분을 캡슐화한 객체 지향 시스템 중 설계가 잘 된 것들을 보면, 객체를 복사 하는 함수가 딱 두개만 있는 것을 볼 수 있다. 이 둘을 복사 생성자와 복사 대입 연산자라 하고, 이 둘을 통틀어 객체 복사 함수(copying function)라 부른다. 컴파일러가 생성한 복사 함수는 기본적인 요구에 충실하다. 복사되는 객체가 갖고 있는 데이터를 빠짐없이 복사한다. 주의점 만약 컴파일러가 만든 기본 동작에 마음에 안들어 직접 복사 함수를 선언한다면 다음과 같은 것들을 지켜야 한다. 기존 클래스에 멤버를 추가하면 복사 함수를 수정 해줘야 한다. 파생 클래스에서 기본 클래스의 복사 함수를 호출 하도록 만들어야 한다. CBase { ... } CTest { private: INT m_iMembe.. 2009. 2. 17. 항목 11. operator=에서는 자기대입에 대한 처리가 빠지지 않도록 하자 내용 자기대입(self assignment) : 어떤 객체가 자기 자신에 대해 대입 연산자를 적용 하는 것을 말한다. a[i] = a[j]; 또는 *px = *py; 는 자기대입의 가능성을 가지고 있는 문장이다. 어뜻 보기에 명확하지 않은 이러한 자기대입이 생기는 이유는 여러 곳에서 하나의 객체를 참조하는 상태, 즉 중복참조(aliasing)라고 불리는 것 때문이다. 그렇기 때문에, 같은 타입으로 만들어진 객체 여러개를 참조자 혹은 포인터로 물어 놓고 동작하는 코드를 작성할 떄는 같은 객체가 사용 될 가능성을 고려 하는것이 일반적으로 바람직한 자세이다. 해결법 operator=의 첫머리에서 일치성 검사(identity test)를 통해 자기대입을 점검한다. 자기대입의 경우 많이 일어나는 것이 아니기 때문.. 2009. 2. 17. 항목 10. 대입 연산자는 *this 참조자를 반환하게 하자 이유 일종의 관례이므로 관례를 지키는 것이 좋다. 내용 C++의 대입 연산은 x = y = z = 15; 처럼 여러 개가 사슬 처럼 엮일 수 있다. 이처럼 대입 연산이 사슬처럼 엮이려면 대입 연산잔가 좌변 인자에 대한 참조자를 반환하도록 구현이 되어 있다. 이런 구현은 일종의 관례(convention)인데, 나름대로 만드는 클래스에 대입 연산자가 혹 들어간다면 이 관례를 지키는 것이 좋다. 이것만은 잊지 말자! - 대입 연산자는 *this의 참조자를 반환하도록 만들자. 관련링크 http://ikpil.tistory.com/412 http://redinlife.egloos.com/1604282 2009. 2. 15. 항목 9. 객체 생성 및 소멸 과정 중에는 절대로 가상 함수를 호출하지 말자. 이유 1. 호출한 결과가 원하는 대로 돌아가지 않을 것이다. 2. 제대로 돌아간다 해도 폭탄을 가지고 있는 것과 같다. 설명 파생 클래스 객체가 생성될 때 그 객체의 기본 클래스 부분이 파생 클래스 부분보다 먼저 호출된다. 그렇기에 기본 클래스의 생성자가 호출될 동안에는, 가상 함수는 절대로 파생 클래스 쪽으로 내려가지 않는다. 기본 클래스 생성자는 파생 클래스 생성자보다 먼저 실행되기 때문에, 기본 클래스 생성자가 돌아가고 있을 때 파생 클래스 데이터 멤버는 아직 초기화 된 상태가 아닌 것이 핵심이다. 객체가 소멸 될 때는 파생 클래스의 소멸자가 일단 호출되고 파생 클래스만의 데이터 멤버는 정의되지 않은 값으로 가정하기 때문에, C++은 이들을 없는 것처럼 취급하고 진행한다. 기본 클래스 소멸자에 진입.. 2009. 2. 15. 항목 8. 예외가 소멸자를 떠나지 못하도록 붙들여 놓자. class DBConnection { public: static DBConnection create(); void close();}; 위의 DBConnection 객체에 대해 사용자가 cloase를 직접 호출해야 하는 설계이다. 사용자의 망각을 사전에 차단하는 좋은 방법이라면 DBConnection에 대한 자원관리 클래스를 만들어서 그 클래스의 소멸자에서 close를 호출하게 만드는 것이다. class DBConn { // DBConnection 객체를 관리하는 클래스 public: ... ~DBConn() // 데이터베이스 연결이 항상 닫히도록 확실히 챙겨주는 함수 { db.cloase(); } private: DBConnection db; }; 위의 두 클래스를 활용하여 다음과 같은 프로그래밍이 가능.. 2008. 7. 10. 항목 7. 다형성을가진 기본 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자. C++의 규정에 의하면, 기본 클래스 포인터를 통해 파생 클래스 객체가 삭제될 때 그 기본 클래스에 비가상 소멸자가 들어 있으면 플그램 동작은 미정의 사항이라 되어 있다. 대게 그 객체의 파생 클래스 부분이 소멸되지 않게 된다. 가상 소멸자를 선언하는 것은 그 클래스에 가상 함수가 하나라도 들어 있는 경우에만 한정하자. (이부분은 뭐라 정리하기 힘들다 이해는 했는데 내용 정리가 힘들다 추후 다시 정리 예정) 이것만은 잊지 말자! - 다형성을 가진 기본 클래스에는 반드시 가상 소멸자를 선언해야 한다. 즉, 어떤 크랠스가 가상 함수를 하나라도 갖고 있으면, 이 클래스의 소멸자도 가상 소멸자이어야 한다. - 기본 클래스로 설계되지 않았거나 다형성을 갖도록 설계되지 않는 클래스에는 가상 소멸자를 선언하지 말아야.. 2008. 7. 1.