티스토리 뷰

 

Effective C++ 이펙티브 C++
스콧 마이어스 저/곽용재
 

5. 구현

 

항목 30 : 인라인 함수는 미주알고주알 따져서 이해해 두자

  • 함수 인라인은 작고, 자주 호출되는 함수에 대해서만 하는 것으로 묶어둡시다. 이렇게 하면 디버깅 및 라이브러리의 바이너리 업그레이드가 용이해지고, 자칫 생길 수 있는 코드 부풀림 현상이 최소화되며, 프로그램의 속력이 더 빨라질 수 있는 여지가 최고로 많아집니다.
  • 생성자와 소멸자 인라인은 피하자.
  • 함수 템플릿이 대개 헤더 파일에 들어간다는 일반적인 부분만 생각해서 이들을 inline으로 선언하면 안 됩니다.

 

항목 31 : 파일 사이의 컴파일 의존성을 최대로 줄이자

 

  • 객체 참조자 및 포인터로 충분한 경우에는 객체를 직접 쓰지 않습니다.
  • 할 수 있으면 클래스 정의 대신 클래스 선언에 최대한 의존하도록 만듭니다.
  • 선언부와 정의부에 대해 별도의 헤더 파일을 제공합니다.

 

1. 핸들 클래스(Handle Class)

인터페이스와 구현의 구분 - pimp(pointer to implementation)

 

1.1. 클래스 정의 예

#include <string>

#include <memory>

 

// Person 구현 클래스에 대한 전방 선언

class PersonImpl;

// Person 클래스 안에서 사용하는 클래스에 대한 전방 선언

class Date;

class Address;

 

class Person

{

public:

Person(const std::string& name, const Date& birthday, const Address& addr);

std::string name() const;

std::string birthDate() const;

std::string address() const;

...

private:

// 구현 클래스에 대한 포인터

std::tr1::shared_ptr<PersonImpl> pImpl;

}

 

1.2. 클래스 구현 예

#include "Person.h"

#include "PersonImpl.h"

 

Person::Person(const std::string& name, const Date& birthday, const Address& addr)

: pImpl(new PersonImpl(name, birthday, addr)){ }

 

std::string Person::name() const

{

return pImpl->name();

}

 

2. 인터페이스 클래스(Interface Calss)

 

2.1. 인터페이스 클래스 정의 예

class Person

{

public:

virtual ~Person();

virtual std::string name() const = 0;

virtual std::string birthDate() const = 0;

virtual std::string address() const = 0;

...

// 주어진 매개변수로 초기화되는 Person 객체를 새로 생성하고,

// 그것에 대한 tr1::shared_ptr을 반환합니다.

static std::tr1::shared_ptr<Person>

create(const std::string& name, const Date& birthday, const Address& addr);

...

};

 

2.2. 인터페이스 클래스 사용 예

std::string name;

Date dateOfBirth;

Address address;

...

// Person 인터페이스를 지원하는 객체 한 개를 생성합니다.

std::tr1::shared_ptr<Person> pp(Person::create(name, dateOfBirth, address));

...

std::cout << pp->name() << " was born on " << pp->birthDate()

<< " and now lives at " << pp->address();

...

 

2.3. 인터페이스 클래스의 파생 클래스 정의 예

class RealPerson : public Person

{

public:

RealPerson(const std::string& name, const Date& birthday, const Address& addr)

: theName(name), theBirthDate(birthday), theAddress(addr) { }

virtual ~RealPerson() { }

std::string name() const;

std::string birthDate() const;

std::string address() const;

private:

std::string theName;

Date theBirthDate;

Address theAddress;

};

 

2.4 Person::create 함수 구현 예

std::tr1::shared_ptr<Person> Person::create

(const std::string& name, const Date& birthday, const Address& addr)

{

return std:tr1::shared_ptr<Person>(new RealPerson(name, birthday, addr));

}

 

  • 컴파일 의존성을 최소화하는 작업의 배경이 되는 가장 기본적인 아이디어는 '정의' 대신에 '선언'에 의존하게 만들자는 것입니다. 이 아이디어에 기반한 두 가지 접근 방법은 핸들 클래스와 인터페이스 클래스입니다.
  • 라이브러리 헤더는 그 자체로 모든 것을 갖추어야 하며 선언부만 갖고 있는 형태여야 합니다. 이 규칙은 템플릿이 쓰이거나 쓰이지 않거나 동일하게 적용합시다.

 

- James Song

댓글