본문 바로가기

카테고리124

전문가를 위한 C++ | Chapter 09 클래스와 객체 마스터하기(하) 9.3 메서드의 종류 C++에서 제공하는 메서드의 종류는 다양하다. 이 절에서 하나씩 자세히 소개한다. 9.3.1 static 메서드 메서드도 데이터 멤버처럼 객체 단위가 아닌 클래스 단위로 적용되는 것이 있다. 이를 정적(static) 메서드라 부른다. 예를 들어 8장에서 정의한 SpreadsheetCell 클래스를 살펴보자. 여기서 stringToDouble와 doubleToString 헬퍼 메서드는 객체 정보에 접근하지 않기 때문에 다음과 같이 static으로 선언할 수 있다. /* static 메서드 */ class SpreadsheetCell { private: static std::string doubleToString(double inValue); static double stringToDo.. 2022. 1. 16.
전문가를 위한 C++ | Chapter 09 클래스와 객체 마스터하기(상) 9.1 friend C++는 클래스 안에서 다른 클래스나 다른 클래스의 멤버 함수, 그리고 멤버가 아닌 독립 함수를 friend로 선언하는 기능을 제공한다. friend로 지정된 대상은 이 클래스의 protected, private 데이터 멤버와 메서드에 접근할 수 있다. class Foo { friend class Bar; /* 클래스를 프렌드로 지정합니다. */ friend void Bar::processFroo(const Foo& foo); /* 특정한 메서드만 프렌드로 지정합니다. */ friend void dumpFoo(const Foo& foo); /* 독립 함수를 프렌드로 지정합니다. */ }; 프렌드로 지정할 클래스, 메서드, 그리고 함수는 반드시 접근하고자 하는 클래스 안에서 지정해야 한.. 2022. 1. 14.
Effective C++ | 항목 12 객체의 모든 부분을 빠짐없이 복사하자 항목 12 객체의 모든 부분을 빠짐없이 복사하자 12.1 사용자가 선언한 복사 함수 객체의 안쪽 부분을 캡슐화한 객체 지향 시스템을 잘 보면 객체를 복사하는 함수가 딱 둘만 있을 것을 알 수 있다. 복사 생성자와 복사 대입 연산자라고 이 둘을 통틀어 복사 함수(copy function)라고 부른다. 객체 복사 함수를 여러분이 선언하면 이에 대해 컴파일러는 썩 반기는 분위기가 아니라는 듯, 여러분이 구현한 복사 함수가 잘못되었을 경우에도 입을 다물어 버린다. 고객을 나타내는 클래스가 하나 있다고 가정해보자. 이 클래스의 복사 함수는 호출될 때마다 로그를 남기도록 작성되었다. void logCall(const std::string& log); class Customer { /* 고객을 나타내는 클래스입니다... 2022. 1. 12.
Effective C++ | 항목 11 operator=에서는 자기대입에 대한 처리가 빠지지 않도록 하자 항목 11 operator=에서는 자기 대입에 대한 처리가 빠지지 않도록 하자 자기 대입(self assignment)이란 어떤 객체가 자기 자신에 대해 대입 연산자를 적용하는 것을 말한다. class Widget { ... }; Widget w; w = w; /* 아주 적법한 코드입니다. */ a[i] = a[j]; /* i와 j가 같은 값이면 자기 대입됩니다. */ *px = *py; /* px와 py가 가리키는 대상이 같으면 자기 대입됩니다.*/ 이러한 자기 대입이 생기는 이유는 여러 곳에서 하나의 객체를 참조하는 상태, 다시 말해 중복 참조(ailasing) 때문이다. 같은 타입으로 만들어진 객체 여러 개를 참조자 혹은 포인터로 물어 놓고 동작하는 코드를 작성할 때는 같은 객체가 사용될 가능성을 .. 2022. 1. 12.
Effective C++ | 항목 10 대입 연산자는 *this의 참조자를 반환하게 하자 항목 10 대입 연산자는 *this의 참조자를 반환하게 하자 10.1 대입 연산자와 반환 타입 관례 C++의 대입 연산은 여러 개가 사슬처럼 엮일 수 있는 성질과 우측 연관(right associative) 연산이라는 재미있는 특성을 갖고 있다. int, x, y, z; x = y = z = 10; x = (y = (z = 10)); 이렇게 대입 연산이 사슬처럼 엮이려면 대입 연산자가 좌변 인자에 대한 참조자를 반환하도록 구현되어 있을 것이다. 이런 구현은 일종의 관례(convention)인데, 여러분이 나름대로 만드는 클래스에 대입 연산자가 들어간다면 이 관례를 지키는 것이 좋다. 이 규칙은 단순 대입형 연산자 말고도 모든 형태의 대입 연산자에서 지켜져야 한다. class Widget { public:.. 2022. 1. 11.
Effective C++ | 항목 09 객체 생성 및 소멸 과정 중에는 가상 함수를 절대로 호출하지 말자 항목 09 객체 생성 및 소멸 중에는 가상 함수를 절대로 호출하지 말자 9.1 객체 생성 및 소멸 중 가상 함수 잘못 호출하기 주식 거래를 본떠 만든 클래스가 있다고 가정하자. 매수 주문, 매도 주문 등의 거래를 모델링하는 데 중요한 포인트는 감사(audit) 기능이 있어야 한다는 점이다. 다음과 같이 주식 거래 객체가 생성될 때마다 감사 로그에 적절한 거래 내역이 만들어지도록 해보자. class Transaction { /* 주식 부모 클래스 */ public: Transaction(); virtual void logTransaction() const = 0; /* 거래 로그를 기록하는 순수 가상 메서드입니다. */ }; class BuyTransaction : public Transaction { /.. 2022. 1. 11.
전문가를 위한 C++ | Chapter 08 클래스와 객체 숙달하기 8.1 스프레드시트 예제 이 장과 다음 장에서는 실제로 실행할 수 있는 간단한 스프레드시트 예제를 이용하여 여러 가지 개념을 소개한다. 여기서 만들 스프레드시트는 셀(cell)이란 단위로 구성된 2차원 격자로서, 각 셀은 숫자나 스트링(string)을 담을 수 있다. 스프레드시트 예제 애플리케이션은 Spreadsheet와 SpreadsheetCell이란 기본 클래스를 사용한다. Spreadsheet 객체마다 SpreadsheetCell 객체를 가진다. 그리고 이러한 Spreadsheet를 관리하는 SpreadsheetApplication이란 클래스도 정의한다. 이 장에서는 SpreadsheetCell을 중심으로 소개한다. 8.2 클래스 작성 방법 클래스를 작성하려면 그 클래스의 모든 객체에 적용할 동작(.. 2021. 12. 30.
Effective C++ | 항목 08 예외가 소멸자를 떠나지 못하도록 붙들어 놓자 항목 08 예외가 소멸자를 떠나지 못하도록 붙들어 놓자 8.1 예외를 내보내는 소멸자 소멸자에서는 예외가 발생한 조건이 어떤 조건인지에 따라 프로그램이 종료되던지 아니면 정의되지 않은 동작을 보인다. 이렇게 완전하지 못한 프로그램의 종료나 정의되지 않은 동작의 원인은 바로 예외가 터져 나오는 것을 내버려 두는 소멸자에게 있다. C++는 예외를 내보내는 소멸자를 싫어한다. ■ 8.1.1 소멸자의 예외 처리 여러분이 데이터베이스 연결을 나타내는 클래스를 쓰고 있다고 가정해보자. class DBConnection { public: ... static DBConnection create(); void close(); /* 연결을 닫습니다. 실패하면 예외를 던집니다. */ }; class DBConn { /* D.. 2021. 8. 29.
Effective C++ | 항목 07 다형성을 가진 부모 클래스에서는 소멸자를 반드시 가상 소멸자로 선언하자 항목 07 다형적인 부모 클래스는 가상 소멸자를 선언하자 7.1 부모 클래스와 가상 소멸자 ■ 7.1.1 가상 소멸자의 선언 팩토리 함수(factory function) 새로 생성된 자식 클래스 객체에 대한 부모 클래스 포인터를 반환하는 함수를 말한다. 어떤 객체에 대한 포인터를 반환하는 용도로 사용한다. 팩토리 함수의 규칙 getTimeKeeper 함수에서 반환되는 객체는 힙에 있다. 객체를 사용하지 않으면 지원 누출을 막기 위해 객체를 적절히 삭제(delete)해야 한다. getTimeKeeper 함수가 반환하는 자식 클래스(AtomicClock) 객체를 부모 클래스의 포인터로 삭제한다. // 시간을 기록하는 TimeKeeper 클래스입니다. class TimeKeeper { public: TimeK.. 2021. 8. 29.
Effective C++ | 항목 06 컴파일러가 만들어낸 함수가 필요 없으면 확실히 이들의 사용을 금해버리자 항목 06 컴파일러가 만든 함수가 필요 없으면 사용을 금하자 6.1 복사를 지원하지 않는 클래스 class HomeForSale { public: HomeForSale() { }; }; HomeForSale h1; HomeForSale h2; HomeForSale h3(h1);// h1을 자동으로 복사합니다. h1 = h2;// h2를 자동으로 복사합니다. 복사 생성자와 복사 대입 연산자가 저절로 만들어지는 것을 막기 위해 private 멤버로 선언한다. 컴파일러는 디폴트 버전을 생성하지 않고 비공개(private)의 접근성을 가지므로 외부 호출을 차단할 수 있다. private 멤버 함수는 그 클래스의 멤버 함수와 friend 함수가 호출할 수 있으므로 아예 정의(define)하지 않아 링크 시점에서 .. 2021. 8. 26.
Effective C++ | 항목 05 C++가 은근슬쩍 만들어 호출해버리는 함수들에 촉각을 세우자 항목 05 C++가 은근슬쩍 만들어 호출해버리는 함수들 5.1 컴파일러가 선언하는 디폴트 멤버 함수 컴파일러가 기본으로 선언하는 멤버 함수는 다음과 같다. 생성자(constructor) 복사 생성자(copy constructor) 소멸자(destructor) 복사 대입 연산자(copy assignment operator) 컴파일러가 만드는 함수는 모두 기본형(default)이고 public 멤버이며 inline 함수다. class Empty { }; class Empty { public: Empty() { ... };// 디폴트 생성자 Empty(const Empty& rhs) { ... };// 디폴트 복사 생성자 ~Empty() { ... };// 디폴트 소멸자 Empty& operator=(cons.. 2021. 8. 26.
Effective C++ | 항목 04 객체를 사용하기 전에 반드시 그 객체를 초기화하자 항목 04 객체를 사용하기 전에 반드시 그 객체를 초기화하자 4.1 비멤버 객체 초기화 C++는 객체(변수)를 초기화하는 데 있어 언제 초기화가 보장되며 언제 그렇지 않은지 규칙이 명확하게 준비되어 있다. 그러나 안타까운 점은 그 규칙 자체가 머리에 새겨두기엔 너무 복잡하다는 것이다. 따라서 가장 좋은 방법은 모든 객체를 사용하기 전에 항상 초기화하는 것이다. 기본제공 타입으로 만들어진 비멤버 객체에 대해서는 초기화를 손수해야 한다. /* int의 직접 초기화 */ int x = 0; /* 포인터의 직접 초기화 */ const char* const text = "A C-style string"; /* 입력 스트림에서 읽음으로써 초기화 */ double d; std::cin >> d; 4.2 멤버 객체 초.. 2021. 8. 26.