항목 18. 인터페이스 설계는 제대로 쓰기엔 쉽게, 엉터리로 쓰기엔 어렵게 하자
인터페이스를 사용하는데 결과 코드 가 사용자가 생각한 대로 동작하지 않는다 면 그 코드는 컴파일 되지 않아야 한다.
날짜를 나타내는 Date
클래스는 두 가지 문제를 야기할 수 있다.
class Date {
public:
Date (int month, int day, int year);
}
매개변수의 전달 순서 가 잘못될 여지가 있다.
month : 3, day : 30
을 month : 30, day : 3
으로 입력할 가능성이 있다.
매개변수에 비정상 적인 값이 들어갈 여지가 있다.
day : 30
을 day : 50
으로 입력할 가능성이 있다.
일, 월, 연을 구분하는 간단한 랩퍼 타입 을 만들고 이 타입을 Date
생성자 안에 들 수 있다.
타입에 제약을 부여 하여 타입을 통해 할 수 있는 일들을 묶는다.
struct Day {
explicit Day (int d) : val(d){}
int val;
};
struct Month {
explicit Month (int d) : val(d){}
int val;
};
struct Year {
explicit Year (int d) : val(d){}
int val;
};
class Date {
public:
Date (const Month& m, const Day& d, const Year& y);
};
Date d (23 , 12 , 1993 ); // 에러 : 타입이 틀림
Date d (Day(23 ), Month(12 ), Year(1993 )); // 에러 : 타입이 틀림
Date d (Month(12 ), Day(23 ), Year(1993 )); // 컴파일 성공
일관성 있는 인터페이스를 제공하기 위해서는 기본 제공 타입 과 어긋나는 동작을 피해야 한다.
좋은 인터페이스를 만들어 주는 요인중 하나는 일관성 이다.
모든 STL
컨테이너는 크기를 반환하는 size
란 멤버 함수를 통해 일관성을 제공한다.
사용자 쪽에서 암기를 통해 제대로 쓸 수 있는 인터페이스는 잘못 쓰기 쉽다.
객체 생성 시에 어떤 동적 링크 라이브러리의 new
를 썻는데 그 객체를 삭제할 떄는 이전의 DLL과 다른 DLL 에 있는 delete
를 썼을경우 발생한다.
new/delete
가 실행되는 DLL
이 달라서 꼬이게 되면 런타임 에러가 발생한다.
shared_ptr
을 사용하면 문제를 피할 수 있다.
클래스의 기본 삭제자는 shared_ptr
이 생성된 DLL
과 동일한 DLL
에서 delete
를 사용하도록 만들어져 있기 때문이다.
shared_ptr
은 다른 DLL
들 사이에 이리저리 넘겨지더라도 교차 DLL
문제를 걱정하지 않아도 된다.