Class

  • 어떤 종류의 모든 객체에게 공통인 멤버 변수와 멤버 함수를 정의하는 형틀
  • 객체 지향에서의 기본적인 빌딩 블록
  • 인스턴스 : 클래스로부터 만들어지는 객체
  • 멤버 변수 : 클래스 내부의 변수, 인스터스에 개별 존재
  • 멤버 함수 : 클래스 내부의 함수, 인스턴스가 1개의 멤버함수 공유

멤버 변수 내부 정의 주의점

  • 멤버 변수의 경우, 내부에 정의하게 될 경우, 인라인 함수로 사용 되기에 주의 해야 한다.

=default

  • 기본 구현을 사용하여 생성자, 소멸자, 복사연산자 및 이동연사자를 명시적으로 정의할 때 사용

    class MyClass {
    public:
      MyClass() = default;           // 기본 생성자
      ~MyClass() = default;          // 소멸자
      MyClass(const MyClass&) = default;  // 복사 생성자
      MyClass& operator=(const MyClass&) = default;  // 복사 대입 연산자
      MyClass(MyClass&&) = default;  // 이동 생성자
      MyClass& operator=(MyClass&&) = default;  // 이동 대입 연산자
    
      // 다른 멤버 함수들...
    };

new와 일반 선언 차이

특징 new 사용 (동적 할당) 변수 선언 (자동/정적 할당)
메모리 영역 힙 (Heap) 스택 (Stack) 또는 정적
생명 주기 명시적으로 관리 (delete) 스코프 종료 시 자동 소멸
성능 메모리 할당/해제가 느림 상대적으로 빠름
유연성 더 큰 데이터 구조에 유리 간단하고 안전함
  • new를 사용하는 경우: 객체를 스코프와 무관하게 더 오랫동안 유지하거나, 동적으로 크기 조정 가능한 데이터 구조(예: 동적 배열, 연결 리스트 등)를 사용할 때 적합.
  • 변수 선언을 사용하는 경우: 성능과 코드 안전성이 중요한 경우, 객체의 생명 주기가 스코프 내로 제한되어도 되는 경우 적합.

생성자

  • 기본 생성자
      Employee() {}
  • 복사 생성자
      Employee(const Employee& employee) {}

복사 생성자

  • 동일한 클래스의 객체를 복사하여 객체를 생성할 때 사용
  • 호출되는 경우
    • 같은 종류의 객체로 초기화 : MyClass obj(obj2);
      • 정의 시에만 호출, 이미 생성된 객체 간에는 대입 연산
    • 객체를 함수에 전달 :
      • MyClass func(MyClass obj) { // 여기서 호출 };
    • 함수가 객체를 반환 :
      • MyClass func(MyClass obj) { MyClass tmp; return tmp;// 여기서 호출 };

C++ 복사

  • int, char 배열은 기본적으로 DeepCopy를 지원.
  • 객체의 경우, 기본적으로 ShallowCopy를 지원.
    • 기본 복사 생성자를 사용 시, 배열 복사에서 문제가 발생하는 이유.
    • 대입 연산의 경우(같은 객체 간 대입), 깊은 복사
        MyClass obj("Hello");
        obj = obj; // 자기 자신에 대한 대입

초기화 리스트

  • C++에서 객체의 생성자(constructor)를 호출할 때 멤버 변수를 초기화하는 방법 중 하나

          // 초기화 리스트를 사용하여 멤버 변수를 초기화
          MyClass(int a, int b) : memberA(a), memberB(b) {
              std::cout << "Constructor called!";
      }
  • 생성자의 본문이 실행되기 전에 멤버 변수를 초기화하는 데 사용

    • 본문에서 초기화 하는 것보다 효율적

      int a = 10; // <- 초기화 리스트 방식
      
      int a;
      a = 10; // <- 초기화 리스트x
  • 상수 멤버 변수 초기화 : 상수 멤버 변수를 초기화 리스트로 초기화가능

  • C++11 부터 초기화 시, {}를 사용하는 uniform initialization으로 통일

      AClass a {1, 2, 3};
    • 축소 변환 (3.14를 3으로 자르는 int 변환같은)을 방지하는 기능이 있음
  • C++20 부터는 지정 초기자 기능 사용가능

      AClass{
       int a {3};
       int b;
       int c = 5;
      }
    
      AClass a {
          .a = 5;
          .b = 4;
      } // a = 5, b = 4, c = 5 로 초기화
      // 생략된 대상은 디폴트 값으로 초기화;
      // 구조체에 멤버를 추가해도 기존 코드는 정상 작동

초기자 리스트 생성자

  • 참고 : 전무가를 위한 c++
  • initializer_list<{type}> 을 매개변수로 가지는 생성자
      class ES
      {
      public:
          ES(initializer_list<double> args)
          {
              for (const auto& value : args)
              {
                  m_sequence.push_back(value);
              }
          }
      }

위임 생성자

  • 생성자에서 다른 생성자를 호출

  • 위임한 생성자를 먼저 호출함

      class Person {
      public:
          // 기본 생성자
          Person() : Person("Unknown", 0) {
              std::cout << "Default constructor called\n";
          }
          // 이름만 초기화하는 생성자
          Person(const std::string& name) : Person(name, 0) {
              std::cout << "Constructor with name only called\n";
          }
          // 이름과 나이를 초기화하는 생성자 (메인 생성자)
          Person(const std::string& name, int age) : name(name), age(age) {
              std::cout << "Main constructor called\n";
          }
      };
      int main() {
          Person p1;                      // 기본 생성자 호출
          Person p2("Alice");             // 이름만 초기화
          Person p3("Bob", 30);           // 이름과 나이 초기화
    
          p1.printInfo(); // Main -> Default
          p2.printInfo(); // Main -> Name Only
          p3.printInfo(); // Main
      }

명시적 생성자

  • 생성자는 받은 값을 암묵적으로 변환하여 호출 됨. (변환 생성자)

  • 이를 막고자 하면, explicit 키워드를 생성자 앞에 붙임.

    • 암묵적 변환이 필요한 경우 아니면, explicit 지정 권장
  • 사용 예

      void process(const MyClass& c)
      class MyClass{
      public:
          explicit MyClass(int);    
      }
    
      process({1}) // X  <- 암시적 변환 허용 막기
      process(MyClass{1}); // O

사용자 정의 소멸자 사용 주의점

  • c++11부터 사용자 정의 소멸자가 있으면, 기본으로 복제 생성자를 생성해주지 않음

복제 대입연산자

  • AClass& operator=(const AClass& rhs) = default

이동 연산자

  • 이동 연산자를 사용하면, 복제 대신 얇은 복사와 비슷한 방식으로 소유권을 옮김.
    • 소유권을 옮긴 것이기에 주소는 여전히 해당 위치를 가르키고 있음.
    • 그렇기에, nullptr로 초기화 해 주는게 좋음
  • &&를 사용해서 매개변수를 rvalue로 변환, noexcept키워드를 사용해 중간에 에러로 멈추지 않도록 함
  • 함수에서 로컬 변수나 매개 변수를 리턴할 때는 사용 금지
    • RVO, NRVO를 막아 최적화가 더 안좋아짐
    • 3항 연산자로 return 문에 작성도 최적화를 막으니 사용 금지
  • 이동 생성자
      SpreadSheet::SpreadSheet(SpreadSheet&& src) noexcept {};
  • 이동 대입 연산자
      SpreadSheet& SpreadSheet::operator=(SpreadSheet&& src) noexcept {};

'공부 > C++' 카테고리의 다른 글

(C++17,20)구조적 바인딩  (0) 2025.03.05
튜플(Tuple)  (0) 2025.03.05
함수  (1) 2025.03.03
enum_class  (0) 2025.03.03
C++ 변수  (0) 2025.03.03

+ Recent posts

let textNodes = document.querySelectorAll("div.tt_article_useless_p_margin.contents_style > *:not(figure):not(pre)"); textNodes.forEach(function(a) { a.innerHTML = a.innerHTML.replace(/`(.*?)`/g, '$1'); });