복습용/C++

[Unreal Engine 8기] C++ 복사 생성자와 오버로딩

조현묵 2026. 3. 20. 17:09
  • 오버로딩
더보기
  • 오버로딩(Overloading)
    같은 이름이지만 매개변수 목록은 다르게 함수를 재정의하는 것을 “오버로딩”이라 합니다.
  • 함수를 비슷하게 다시 작성하는 경우에는 총 세 가지 경우가 있습니다.
    1. 함수 중복 정의(컴파일 에러)
      같은 반환 자료형, 같은 이름, 같은 매개변수 목록으로 함수를 다시 정의하는 경우
    2. 함수 오버라이딩
      같은 반환 자료형, 같은 이름, 같은 매개변수 목록으로
      부모 클래스의 멤버 함수를 다시 정의하는 경우.
    3. 함수 오버로딩
      같은 이름, 다른 매개변수 목록으로 함수를 다시 정의하는 경우.
      반환 자료형은 오버로딩의 판단 기준이 아님.
  • 함수 오버로딩 매칭
    오버로딩된 함수 중에 어떤 함수를 호출해야 하는지 판단하는 과정. 함수
    매칭 결과는 3가지가 있습니다.
    첫 번째, 가장 적합한 함수를 하나 찾은 경우 -> 정상 작동
    두 번째, 매칭 되는 함수를 여러 개 찾은 경우 -> 컴파일 에러
    세 번째, 매칭 되는 함수를 찾을 수 없는 경우 -> 컴파일 에러
  • 복사 생성자
더보기
      • 복사 생성자(Copy Constructor)
        생성자의 오버로딩 중 하나.
        매개변수 자료형이 같은 클래스의 참조 자료형인 생성자를 복사 생성자라고 부릅니다.
        새 객체를 생성 할 때, 기존에 만들어져 있던 객체를 통해 생성하고자 할 때 호출됩니다.
        다시 말해, 같은 클래스에 속한 다른 객체를 참조하여 새로운 객체를 초기화합니다.

        ThisClass(const ThisClass& InOther); 
        // 이런 형태의 생성자를 복사 생성자라 부릅니다.
        // 자기 자신 자료형의 참조를 인자로 받으면 복사 생성자라고 부릅니다.

        // MyVector.h
        MyVector(const MyVector& InOther) {};

        // Main.cpp
        MyVector A = MyVector(1, 7);

        MyVector B(A);
        // "새 객체" B를 생성할 때, 기존에 만들어져 있던 객체 A를 통해 생성하고자 합니다. 
        // -> 복사 생성자 MyVector(const MyVector& InOther)가 호출됩니다.
        MyVector C = MyVector(B); 
        // "새 객체" C를 생성할 때, 기존에 만들어져 있던 객체 B를 통해 생성하고자 합니다. 
        // -> 복사 생성자 MyVector(const MyVector& InOther)가 호출됩니다.

      • 암시적 복사 생성자
        코드에 복사 생성자가 없는 경우, 컴파일러가 암시적으로 복사 생성자를 자동 생성합니다.
        이 복사 생성자를 암시적 복사 생성자라고 합니다

        // MyVector.h 

        class MyVector
        {
        // 분명 만들지 않았습니다.

        private:
        float X;
            
        float Y;
        }

        // MyVector.obj

        class MyVector
        {
        public:
        MyVector() {}                   // 컴파일러가 암시적으로 만들어준 기본 생성자
            
        MyVector(const MyVector& other) // 컴파일러가 암시적으로 만들어준 복사 생성자
        : X(other.X)
        , Y(other.Y)
        {
        }

        private:
        float X;
            
        float Y;
            
        }
  • 연산자 오버로딩
더보기
  • C++에서는 프로그래머가 연산자를 오버로딩할 수 있습니다.
    단, 주의할 점은 아래와 같습니다.

    MyVector& Ref; // 여기서 &는 단항 연산자가 아닙니다. 자료형 기호.
    MyVector* Ptr; // 여기서 *도 단항 연산자가 아닙니다.

  • 특이한 연산자

    Max(1, 3.14f);          // 여기서 ()도 연산자입니다. 함수 호출 연산자.
    int Score = Scores[10]; // []도 연산자입니다. 배열 첨자 연산자.
    MyVector* Vector01 = new MyVector[10]; // new도 연산자입니다.
    delete[] Vector01;                     // delete도 연산자입니다.

  • 연산자는 오버로딩 하는 방법에는 두 가지 경우가 있습니다.

    1. 멤버 함수로 정의 할 수 있을 때.
    2. 멤버 함수로 정의 할 수 없을 때. 즉, 전역 함수로 정의해야할 때.

  • 멤버 연산자를 작성하는 방법

    ThisClass operator+(const ThisClass& InOther) const;

    ThisClass operator-(const ThisClass& InOther) const;

    ThisClass operator*(const ThisClass& InOther) const;

    ThisClass operator/(const ThisClass& InOther) const;
  • 전역함수의 오버로딩
더보기
  • friend 키워드를 활용한 전역함수 오버로딩 문법

    // MyVector.h

    #include <iostream> // std::ostream

    class MyVector
    {
    friend void operator<<(std::ostream& InOStream, const MyVector& InVector);

    friend MyVector operator*(float InScalar, const MyVector& InVector);

    ...
    };

    // MyVector.cpp

    ...

    void operator<<(std::ostream& InOStream, const MyVector& InVector)
    {
    ...
    }

    MyVector operator*(float InScalar, const MyVector& InVector)
    {
    ...
    }

  • += 연산자와 const 멤버 함수

    MyVector& operator+=(const MyVector& InOtherVector) const;
    // 이렇게 선언해버리면 함수 내부에서 this를 수정할 수 없습니다.
  • 연산자 오버로딩 관련 주의사항
더보기
    • 새로운 연산자 기호를 만들 수는 없습니다.
      ex. MyVector operator@(const MyVector& InOtherVector) const;
    • 오버로딩할 수 없는 연산자가 존재합니다.
      1. .(멤버 접근 연산자)
      2. :: (범위 지정 연산자)
      3. ?: (삼항 연산자)
      4. 기타 등등
    • 연산자 오버로딩을 남용하지 맙시다.
      할 수 있는게 많아진다고 무조건 좋은게 아닙니다. 그만큼의 유지보수 작업과 실수들이 추가됩니다.
      2종 오토로 자동차를 타면 편하면서도 안전합니다.
      1종 수동은 탈 수 있는건 많아지지만 실수도 많아집니다.

      MyVector ResultVector = V1 << V2;
      // 대체 무얼하는 연산자인지 알 수 없습니다.
      // 코드를 까봐야지만 알 수 있습니다.

      MyVector ResultVector = V1 ^ V2;
      // 내적인지, 외적인지, 각 요소별로 단순하게 곱하는건지 알 수 없습니다.
      // 마찬가지로 코드를 봐야 알 수 있습니다.

    • 그럼 연산자 오버로딩을 안쓰고 실수를 덜할 수 있는 방법이 있을까요?
      차라리 함수를 만드는 것.
      함수명 이쁘게 하고 시그니처도 잘 지어서 남들이 그 의도를 단번에 알 수 있게끔 합니다.

      Vector Vector::CrossProduct(const Vector& other) const;
      Vector Vector::ComponentWiseMultiply(const Vector& other) const;