Classes
Doing Work in Constructors
생성자에서 가상 메서드를 호출하지 않도록 하고, 오류 신호를 보낼 수 없는 경우 초기화가 실패할 수 있을 것을 방지해야 한다.
Implicit Conversions
암시적 변환을 정의하지말고, explicit 키워드를 사용한다.
class Foo {
explicit Foo(int x, double y);
...
};
void Func(Foo f);
Func({42, 3.14}); // Error
Func(Foo(42, 3.14)); // OK
Copyable and Movable Types
클래스의 public API는 클래스가 복사가 가능한지, 이동만 가능한지, 복사하거나 이동할 수 없는지 여부를 분명하게 해야 한다.
- 복사 가능(Copyable)한 객체
- 같은 타입의 다른 객체를 사용해서 생성 가능 (복사 생성자)
- 같은 타입의 다른 객체를 사용해서 대입 가능 (복사 대입 생성자)
- 원본 객체의 값은 변하지 않음 (즉, 원본과 동일한 객체를 가진 새로운 객체가 생성됨)
- 예시 1. 복사 가능한 객체
int a = 10;
int b = a; // ✅ 복사 가능
std::string s1 = "hello";
std::string s2 = s1; // ✅ 복사 가능 (s2도 "hello"를 가짐)
- 예시 2. 사용자 정의 복사 가능 클래스
class Copyable {
public:
Copyable(const Copyable& other) = default; // 복사 생성자
Copyable& operator=(const Copyable& other) = default; // 복사 대입 연산자
};
2. 이동 가능(Movable)한 객체
- 임시 객체(temporary object)로부터 데이터를 가져올 수 있는 객체
- 이동이 가능한 경우, 복사보다 빠르게 데이터를 전송할 수 있음
- 이동 이후 원본 객체의 상태는 “비워진(empty)” 상태 (이전 데이터를 다른 객체가 가져갔기 때문)
- 예시 1. 이동 가능한 객체 (std::unique_ptr)
std::unique_ptr<int> p1 = std::make_unique<int>(10);
std::unique_ptr<int> p2 = std::move(p1); // ✅ 이동 가능 (p1은 더 이상 10을 소유하지 않음)
- 예시 2. 사용자 정의 이동 가능 클래스
public:
MoveOnly(MoveOnly&& other) = default; // 이동 생성자
MoveOnly& operator=(MoveOnly&& other) = default; // 이동 대입 연산자
MoveOnly(const MoveOnly&) = delete; // 복사는 금지
MoveOnly& operator=(const MoveOnly&) = delete; // 복사는 금지
};
3. 객체 슬라이싱 문제
- 기반 클래스(base class)를 복사할 때, 파생 클래스(derived class)의 정보가 손실되는 현상
- 예시 1.
class Base {
public:
virtual void Print() { std::cout << "Base\n"; }
};
class Derived : public Base {
public:
void Print() override { std::cout << "Derived\n"; }
};
void Func(Base b) { // ❌ 복사 생성자로 인해 slicing 발생
b.Print(); // 항상 Base::Print() 호출됨
}
int main() {
Derived d;
Func(d); // "Base"가 출력됨 (slicing 발생)
}
- 예시 2. 해결 방법 (포인터 또는 참조 사용)
void Func(Base& b) { // ✅ 참조를 사용하면 slicing 방지
b.Print();
}
Inheritance
모든 상속(inheritance)은 public 으로 선언되어야 한다.
- private 상속을 수행하려면 기본 클래스의 인스턴스를 구성원으로 대신 포함
- 기본 클래스로 사용하는 것을 지원하지 않을 경우 final 키워드를 클래스 앞에 선언
상속의 사용을 "is-a"의 경우로 제한한다.
- "Bar가 Foo의 한 종류" 라고 합리적으로 말할 수 있어야 함
인터페이스(interface) 상속은 virtual 클래스로 부터의 상속을 말한다.
- 그 외는 구현(Implementation) 상속이라고 말함
하위 클래스에서 액세스해야 할 수 있는 멤버 함수로 protected의 사용을 제한한다.
다중 상속은 허용되지만 다중 구현 상속은 권장되지 않는다.
Access Control
상수가 아닌 경우 클래스의 데이터 멤버를 private으로 선언한다.
Declaration order
유사한 선언을 그룹화하고 public 부분을 먼저 배치한다.
클래스의 정의는 일반적으로 public: 섹션으로 시작하고 그 다음에 protected:, private: 가 따라와야 한다.
- 비어 있는 섹션은 생략함
다음 순서를 선호한다.
- Types and type aliases (typedef, using, enum, nested structs and classes, and friend types)
- (Optionally, for structs only) non-static data members
- Static constants
- Factory functions
- Constructors and assignment operators
- Destructor
- All other functions (static and non-static member functions, and friend functions)
- All other data members (static and non-static)
'CSE > 알쓸모' 카테고리의 다른 글
Google C++ Style Guide 정리하기 - Naming (0) | 2025.03.03 |
---|---|
Google C++ Style Guide 정리하기 - Functions (0) | 2025.03.02 |
어도비(adobe) 조기 취소 수수료 안내고 싶은데. (0) | 2025.02.28 |
Google C++ Style Guide 정리하기 - Scoping (0) | 2025.02.28 |
Google C++ Style Guide 정리하기 - Header Files (0) | 2025.02.25 |