C++/Class 2021. 3. 16. 00:11

Nested Types

  • 클래스 안에서만 사용하는 자료형은 클래스 내부에 정의하는게 좋다.

예제

  • unscoped enum 사용

    #include <iostream>
    
    class Fruit
    {
    public:
      enum FruitType
      {
        APPLE, BANANA, CHERRY
      };
    
    private:
      FruitType    type_;
    
    public:
      Fruit(FruitType type) : type_(type)
      {}
    
      FruitType    getType()
      {
        return type_;
      }
    };
    
    int        main()
    {
      Fruit    apple(Fruit::APPLE);
    
      if (apple.getType() == Fruit::APPLE)
      {
        std::cout << "Apple" << std::endl;
      }
    }
    
    /* stdout
    Apple
    */
  • enum class 사용

    #include <iostream>
    
    class Fruit
    {
    public:
      enum class FruitType
      {
        APPLE, BANANA, CHERRY
      };
    
    private:
      FruitType    type_;
    
    public:
      Fruit(FruitType type) : type_(type)
      {}
    
      FruitType    getType()
      {
        return type_;
      }
    };
    
    int        main()
    {
      Fruit    apple(Fruit::FruitType::APPLE);
    
      if (apple.getType() == Fruit::FruitType::APPLE)
      {
        std::cout << "Apple" << std::endl;
      }
    }
    
    /* stdout
    Apple
    */

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

C++ 구성 관계 (Composition Relationship)  (0) 2021.03.19
C++ 객체들의 관계 (Object Relationship)  (0) 2021.03.19
C++ 익명 객체 (Anonymous Class)  (0) 2021.03.16
C++ friend  (0) 2021.03.16
C++ 정적 멤버 함수 (Static Member Function)  (0) 2021.03.16
C++/Class 2021. 3. 16. 00:10

익명 객체 (Anonymous Class)

  • R-value처럼 사용할 수 있다.

예제

  #include <iostream>

  class A
  {
  public:
      A()
      {
          std::cout << "Constructor : " << this << std::endl;
      }

      ~A()
      {
          std::cout << "Destructor : " << this << std::endl;
      }

      void    print()
      {
          std::cout << this << std::endl;
      }
  };

  int        main()
  {
      A a;
      a.print();
      a.print();

      A().print();
      A().print();
      A().print();
  }

  /* stdout
  Constructor : 00D8F96B
  00D8F96B
  00D8F96B
  Constructor : 00D8F89F
  00D8F89F
  Destructor : 00D8F89F
  Constructor : 00D8F893
  00D8F893
  Destructor : 00D8F893
  Constructor : 00D8F887
  00D8F887
  Destructor : 00D8F887
  Destructor : 00D8F96B
  */
  • 익명 객체는 할 일을 마치면(명령줄이 끝나면) 바로 사라진다. (소멸자 호출)

  • 그럼에도 스택은 내려가지 않고 계속 쌓이는 것을 볼 수 있다.

  • double(8) 같은 문법도 익명 객체와 비슷한 느낌인 것 같다.

    • (double)8과의 사소한 차이점이 있는 것 같긴 한데, 나중에 찾아봐야겠다.

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

C++ 객체들의 관계 (Object Relationship)  (0) 2021.03.19
C++ Nested Types  (0) 2021.03.16
C++ friend  (0) 2021.03.16
C++ 정적 멤버 함수 (Static Member Function)  (0) 2021.03.16
C++ 정적 멤버 변수 (Static Member Variable)  (0) 2021.03.15
C++/Class 2021. 3. 16. 00:09

friend

  • 클래스 내부에다가 friend 키워드 다음에 다른 클래스나 함수를 선언하면, 해당 클래스나 함수에서 private 멤버에 접근할 수 있다.

예제

  • 간단한 예제

    #include <iostream>
    
    class A
    {
      int value_ = 1;
    
      friend void doSomething(A& a);
    };
    
    void doSomething(A& a)
    {
      std::cout << a.value_ << std::endl;
    }
    
    int        main()
    {
      A    a;
    
      doSomething(a);
    }
    
    /* stdout
    1
    */
  • 조금 귀찮은 예제

    #include <iostream>
    
    class A;
    
    class B
    {
      int    value_ = 2;
    
    public:
      void doSomething(A& a)
      {
        std::cout << a.value_ << std::endl;  // 에러
      }
    };
    
    class A
    {
      int value_ = 1;
    
      friend class B;
    };
    
    int        main()
    {
      using namespace std;
    
      A    a;
      B    b;
    
      b.doSomething(a);
    }
    error C2027: use of undefined type 'A'
    • class A라고 전방 선언을 해도, class A 내부의 멤버 변수들은 알 수 없으므로 에러가 발생한다.

    • 해결법 : 함수의 정의와 선언을 분리하여 class A의 아래 쪽에 정의한다.

    #include <iostream>
    
    class A;
    
    class B
    {
      int    value_ = 2;
    
    public:
      void doSomething(A& a);
    };
    
    class A
    {
      int value_ = 1;
    
      friend class B;
    };
    
    void B::doSomething(A& a)
    {
      std::cout << a.value_ << std::endl;
    }
    
    int        main()
    {
      using namespace std;
    
      A    a;
      B    b;
    
      b.doSomething(a);
    }

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

C++ Nested Types  (0) 2021.03.16
C++ 익명 객체 (Anonymous Class)  (0) 2021.03.16
C++ 정적 멤버 함수 (Static Member Function)  (0) 2021.03.16
C++ 정적 멤버 변수 (Static Member Variable)  (0) 2021.03.15
C++ static (Class)  (0) 2021.03.15
C++/Class 2021. 3. 16. 00:05

정적 멤버 함수 (Static Member Function)

  • 클래스의 멤버 함수들은 한 번만 정의하고, this를 통해 인스턴스의 주소를 포함해서 전달한다고 했다.

    • 인스턴스 없이 범위 지정 연산자로 바로 멤버 함수를 사용하고자 할 때, 굳이 static을 붙여야 동작할 수 있는건가 싶어서 간단한 예제를 만들어 보았다.

      #include <iostream>
      
      class Something
      {
        static int    s_value_;
      
      public:
        int    getValue()
        {
          return s_value_;
        }
      };
      
      int Something::s_value_ = 1;
      
      int        main()
      {
        using namespace std;
      
        cout << Something::getValue();  // 에러
      }
      error C2352: 'Something::getValue': illegal call of non-static member function
      • 내부적으로 인스턴스의 주소를 인자로 전달하는 원리인데, 범위 지정 연산자로 함수를 사용할 경우 인스턴스의 주소가 없으므로 에러가 발생하는 것이다.

예제

  • static 멤버 함수에는 this 포인터가 인자로 들어가지 않는다.

    • 즉, this 포인터로 접근해야하는 모든게 안된다.

    • 정적으로 메모리에 존재하는 변수에는 접근할 수 있지만, static 변수가 아닌 일반 변수에는 접근할 수 없다.

    #include <iostream>
    
    class Something
    {
      static int    s_value_;
    
    public:
      static int    getValue()
      {
        return s_value_;
      }
    };
    
    int Something::s_value_ = 1;
    
    int        main()
    {
      using namespace std;
    
      cout << Something::getValue() << endl;
    
      Something    s1;
    
      cout << s1.getValue() << endl;
    }
    
    /* stdout
    1
    1
    */
  • 함수 포인터를 통한 이해

    • 일반 멤버 함수를 저장하는 예제

      #include <iostream>
      
      class Something
      {
        static int    s_value_;
      
      public:
        static int    getValue()
        {
          return s_value_;
        }
      
        int            temp()
        {
          return s_value_;
        }
      };
      
      int Something::s_value_ = 1;
      
      int        main()
      {
        using namespace std;
      
        Something    s1, s2;
      
        cout << s1.getValue() << endl;
      
        int    (Something:: * fptr1)() = &Something::temp;
      
        cout << (s2.*fptr1)() << endl;
      }
      
      /* stdout
      1
      1
      */
    • 정적 멤버 함수를 저장하는 예제

      #include <iostream>
      
      class Something
      {
        static int    s_value_;
      
      public:
        static int    getValue()
        {
          return s_value_;
        }
      
        int            temp()
        {
          return s_value_;
        }
      };
      
      int Something::s_value_ = 1;
      
      int        main()
      {
        using namespace std;
      
        Something    s1, s2;
      
        cout << s1.getValue() << endl;
      
        int    (Something:: * fptr2)() = &Something::getValue;  // 에러
      
        cout << (s2.*fptr2)() << endl;
      }
      error C2440: 'initializing': cannot convert from 'int (__cdecl *)(void)' to 'int (__thiscall Something::* )(void)'
      • 즉, 여기서의 Something::getValue 함수는 int (*)(void) 형태의 함수인 것을 알 수 있다.

      • fptr2의 형태를 바꾸면 작동된다.

      #include <iostream>
      
      class Something
      {
        static int    s_value_;
      
      public:
        static int    getValue()
        {
          return s_value_;
        }
      
        int            temp()
        {
          return s_value_;
        }
      };
      
      int Something::s_value_ = 1;
      
      int        main()
      {
        using namespace std;
      
        Something    s1, s2;
      
        cout << s1.getValue() << endl;
      
        int    (*fptr2)() = &Something::getValue;
      
        cout << fptr2() << endl;
      }
      /* stdout
      1
      1
      */

요약

  • static 멤버 함수는 this 포인터 인자가 들어가지 않는다.

    • 인스턴스를 특정할 수 없으므로 static 멤버 변수만 호출 가능하다.

    • 범위 지정 연산자로 정적 멤버 함수를 사용할 수 있다.

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

C++ 익명 객체 (Anonymous Class)  (0) 2021.03.16
C++ friend  (0) 2021.03.16
C++ 정적 멤버 변수 (Static Member Variable)  (0) 2021.03.15
C++ static (Class)  (0) 2021.03.15
C++ 체이닝(Chaining)  (0) 2021.03.15
C++/Class 2021. 3. 15. 23:59

정적 멤버 변수 (Static Member Variable)

  • 클래스 내부에 static 변수를 정의할 때는 직접 초기화할 수 없다.

    • 중복 선언 문제인 것 같다.

    • 생성자에서도 초기화할 수 없다.

      • Inner Class를 사용해서 우회하여 초기화할 수는 있다.

예제

  • static이 아닌 기본 예제

    #include <iostream>
    
    class Something
    {
    public:
      int    value_ = 1;
    };
    
    int        main()
    {
      using namespace std;
    
      Something st1;
      Something st2;
    
      st1.value_ = 2;
    
      cout << &st1.value_ << ' ' << st1.value_ << endl;
      cout << &st2.value_ << ' ' << st2.value_ << endl;
    }
    
    /* stdout
    00CFFB4C 2
    00CFFB40 1
    */
  • static 예제

    #include <iostream>
    
    class Something
    {
    public:
      static int    s_value_;
    };
    
    int Something::s_value_ = 1;  // define in .cpp file(not in header file)
    
    int        main()
    {
      using namespace std;
    
      cout << &Something::s_value_ << ' ' << Something::s_value_ << endl;
    
      Something st1;
      Something st2;
    
      st1.s_value_ = 2;
    
      cout << &st1.s_value_ << ' ' << st1.s_value_ << endl;
      cout << &st2.s_value_ << ' ' << st2.s_value_ << endl;
    
      Something::s_value_ = 1024;
    
      cout << &Something::s_value_ << ' ' << Something::s_value_ << endl;
    }
    
    /* stdout
    0032C008 1
    0032C008 2
    0032C008 2
    0032C008 1024
    */
    • 클래스 외부에서 정의해야 한다는 점이 좀 헷갈린다.

Inner Class

  • Inner Class를 사용한 static 변수의 클래스 내부 초기화

    #include <iostream>
    
    class Something
    {
    public:
      class _init
      {
      public:
        _init()
        {
          s_value_ = 9876;
        }
      };
    
    private:
      static int        s_value_;
      static _init      s_initializer;
    
    public:
      static int    getValue()
      {
        return s_value_;
      }
    };
    
    int                    Something::s_value_;
    Something::_init    Something::s_initializer;
    
    int        main()
    {
      using namespace std;
    
      Something    s1;
    
      cout << s1.getValue() << endl;
    }
    
    /* stdout
    9876
    */

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

C++ friend  (0) 2021.03.16
C++ 정적 멤버 함수 (Static Member Function)  (0) 2021.03.16
C++ static (Class)  (0) 2021.03.15
C++ 체이닝(Chaining)  (0) 2021.03.15
C++ this  (0) 2021.03.15
C++/Class 2021. 3. 15. 23:58

static

정적 멤버 변수 (Static Member Variable)

정적 멤버 함수 (Static Member Function)

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

C++ 정적 멤버 함수 (Static Member Function)  (0) 2021.03.16
C++ 정적 멤버 변수 (Static Member Variable)  (0) 2021.03.15
C++ 체이닝(Chaining)  (0) 2021.03.15
C++ this  (0) 2021.03.15
C++ 소멸자 (Destructor)  (0) 2021.03.15
C++/Class 2021. 3. 15. 23:39

체이닝(Chaining)

  • 함수의 반환 값을 해당 인스턴스의 레퍼런스로 전달하여, 연속해서 함수를 사용할 수 있도록 하는 기법이다.

  • 아래와 같이 함수를 하나씩 작성하면 귀찮다.

    #include <iostream>
    
    class Calc
    {
      int    value_;
    
    public:
      Calc(const int &value_in)
        : value_{value_in}
      {}
    
      void add(int value) { value_ += value; }
      void sub(int value) { value_ -= value; }
      void mul(int value) { value_ *= value; }
      void print()
      {
        std::cout << value_ << '\n';
      }
    };
    
    int        main()
    {
      Calc cal{ 10 };
    
      cal.add(10);
      cal.sub(1);
      cal.mul(2);
      cal.print();
    }
  • 체이닝을 적용하면 편하다.

    #include <iostream>
    
    class Calc
    {
      int    value_;
    
    public:
      Calc(const int &value_in)
        : value_{value_in}
      {}
    
      Calc& add(int value) { value_ += value; return *this; }
      Calc& sub(int value) { value_ -= value; return *this; }
      Calc& mul(int value) { value_ *= value; return *this; }
      void print()
      {
        std::cout << value_ << '\n';
      }
    };
    
    int        main()
    {
      Calc cal{ 10 };
    
      cal.add(10).sub(1).mul(2).print();
    }

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

C++ 정적 멤버 변수 (Static Member Variable)  (0) 2021.03.15
C++ static (Class)  (0) 2021.03.15
C++ this  (0) 2021.03.15
C++ 소멸자 (Destructor)  (0) 2021.03.15
C++ 변환 생성자(Converting Constructor)  (0) 2021.03.15
C++/Class 2021. 3. 15. 23:38

this

  • 인스턴스 객체의 주소를 가리킨다.

예제

  #include <iostream>

  class Simple
  {
    int    id_;

  public:
    Simple(const int& id_in)
    {
      setID(id_in);

      std::cout << this << std::endl;
    }

    void    setID(int id) { id_ = id; }
    int    getID() { return id_; }
  };

  int        main()
  {
    Simple s1{ 1 }, s2{ 2 };

    s1.setID(2);
    s2.setID(4);
    std::cout << &s1 << '\n' << &s2 << std::endl;
  }

  /* stdout
  00EFFD14
  00EFFD08
  00EFFD14
  00EFFD08
  */
  • 인스턴스를 생성할 때 멤버 함수들을 따로따로 만드는게 아니라, 한번 정의한 것을 계속 사용하는게 효율적이다.
  • 이를 위해서는 인스턴스의 주소를 멤버 함수가 사용될 때 전달해야 한다.
  • 위 예제의 main 함수에서 s1.setID(2) 명령줄은 다음과 같이 작동하는 것이다.
    • 첫 인자로 인스턴스의 주소를 넣는 방식이다.
  • Simple::setID(&s1, 2);
  • -> : 포인터의 member selection operator
  • 체이닝(Chaining)

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

C++ static (Class)  (0) 2021.03.15
C++ 체이닝(Chaining)  (0) 2021.03.15
C++ 소멸자 (Destructor)  (0) 2021.03.15
C++ 변환 생성자(Converting Constructor)  (0) 2021.03.15
C++ 복사 생성자(Copy Constructor)  (0) 2021.03.12
C++/Class 2021. 3. 15. 23:34

소멸자 (Destructor)

  • 인스턴스가 메모리에서 해제될 때 내부에서 호출되는 함수

    • 메모리 누수를 방지할 때 필수적이다.
    #include <iostream>
    
    class Simple
    {
      int        num_;
    
    public:
      Simple(const int& num_in)
        : num_{num_in}
      {
        std::cout << "Constructor " << num_ << '\n';
      }
    
      ~Simple()
      {
        std::cout << "Destructor " << num_ << '\n';
      }
    };
    
    int        main()
    {
      {
        Simple s0{ 0 };
        Simple s1{ 1 };
      }
      std::cout << std::endl;
      {
        Simple *s0 = new Simple{ 0 };
        Simple s1{ 1 };
    
        delete s0;
      }
    }
    
    /* stdout
    Constructor 0
    Constructor 1
    Destructor 1
    Destructor 0
    
    Constructor 0
    Constructor 1
    Destructor 0
    Destructor 1
    */

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

C++ 체이닝(Chaining)  (0) 2021.03.15
C++ this  (0) 2021.03.15
C++ 변환 생성자(Converting Constructor)  (0) 2021.03.15
C++ 복사 생성자(Copy Constructor)  (0) 2021.03.12
C++ 위임 생성자 (Delegating Constructor)  (0) 2021.03.12
C++/Class 2021. 3. 15. 23:32

변환 생성자(Converting Constructor)

  • explicit 키워드가 없는 생성자는 묵시적으로 형변환을 허용한다.

  • 변환이 가능한 경우는 해당 인자를 생성자에 인자로 주었을 때 유효한 경우이다.

    #include <iostream>
    #include <cassert>
    
    class Fraction
    {
      int    numerator_;
      int    denominator_;
    
    public:
      Fraction(int num = 0, int den = 1)
        : numerator_(num), denominator_(den)
      {
        std::cout << "Default constructor" << std::endl;
        assert(den != 0);
      }
    
      Fraction(const Fraction& fraction)
        : numerator_(fraction.numerator_), denominator_(fraction.denominator_)
      {
        std::cout << "Copy constructor called" << std::endl;
      }
    
      friend std::ostream& operator << (std::ostream& out, const Fraction& f)
      {
        out << f.numerator_ << " / " << f.denominator_;
        return (out);
      }
    };
    
    void    doSomething(Fraction frac)
    {
      std::cout << frac << std::endl;
    }
    
    int        main()
    {
      using namespace std;
    
      doSomething(7);
    }
    
    /* stdout
    Default constructor
    7 / 1
    */
    • 위의 기본 생성자 앞에 explicit 키워드를 붙이면, 묵시적 형변환을 금지시키는 것이 되어 에러가 출력된다.

      error C2664: 'void doSomething(Fraction)': cannot convert argument 1 from 'int' to 'Fraction'

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

C++ this  (0) 2021.03.15
C++ 소멸자 (Destructor)  (0) 2021.03.15
C++ 복사 생성자(Copy Constructor)  (0) 2021.03.12
C++ 위임 생성자 (Delegating Constructor)  (0) 2021.03.12
C++ 멤버 초기화 리스트 (Member Initializer Lists)  (0) 2021.03.12
C++/Class 2021. 3. 12. 17:57

복사 생성자(Copy Constructor)

  • 보안이 중요한 경우 복사 생성자를 private로 정의하여 복사를 방지하기도 한다.

  • 기본 복사 생성자는 얕은 복사이므로 주의하자.

    • 이를 방지하기 위해 깊은 복사를 구현해야 하는데, 시간적 여유가 없을 경우 임시로 delete를 통해 구현하기도 한다.
  • copy initialization, direct initialization, uniform initialization 모두 복사 생성자를 호출한다.

    #include <iostream>
    #include <cassert>
    
    class Fraction
    {
      int    numerator_;
      int    denominator_;
    
    public:
      Fraction(int num = 0, int den = 1)
        : numerator_(num), denominator_(den)
      {
        std::cout << "Default constructor" << std::endl;
        assert(den != 0);
      }
    
      Fraction(const Fraction& fraction)
        : numerator_(fraction.numerator_), denominator_(fraction.denominator_)
      {
        std::cout << "Copy constructor called" << std::endl;
      }
    
      friend std::ostream& operator << (std::ostream& out, const Fraction& f)
      {
        out << f.numerator_ << " / " << f.denominator_;
        return (out);
      }
    };
    
    int        main()
    {
      using namespace std;
    
      Fraction frac1(1, 3);
      cout << frac1 << endl;
    
      Fraction frac2 = frac1;   // copy initialization
      cout << frac2 << endl;
    
      Fraction frac3(frac2);    // direct initialization
      cout << frac3 << endl;
    
      Fraction frac4{ frac3 };  // uniform initialization
      cout << frac4 << endl;
    
      Fraction frac5(Fraction(2, 4));
      cout << frac5 << endl;
    }
    
    /* stdout
    Default constructor
    1 / 3
    Copy constructor called
    1 / 3
    Copy constructor called
    1 / 3
    Copy constructor called
    1 / 3
    Default constructor
    2 / 4
    */
    • frac5의 경우 컴파일러가 복사 생성자를 호출하지 않는 식으로 컴파일한다.

반환 값 최적화(RVO, Return Value Optimization)

  • 함수에서 스택에 있는 메모리를 반환하고 그걸 인스턴스에 저장할 때, Release 모드에서는 최적화가 진행된다.

    #include <iostream>
    #include <cassert>
    
    class Fraction
    {
      int    numerator_;
      int    denominator_;
    
    public:
      Fraction(int num = 0, int den = 1)
        : numerator_(num), denominator_(den)
      {
        std::cout << "Default constructor" << std::endl;
        assert(den != 0);
      }
    
      Fraction(const Fraction& fraction)
        : numerator_(fraction.numerator_), denominator_(fraction.denominator_)
      {
        std::cout << "Copy constructor called" << std::endl;
      }
    
      friend std::ostream& operator << (std::ostream& out, const Fraction& f)
      {
        out << f.numerator_ << " / " << f.denominator_;
        return (out);
      }
    };
    
    Fraction doSomething()
    {
      Fraction temp(1, 2);
      std::cout << &temp << std::endl;
      return (temp);
    }
    
    int        main()
    {
      using namespace std;
    
      Fraction result = doSomething();
    
      cout << &result << endl;
      cout << result << endl;
    }
    
    /* stdout(Debug Mode)
    Default constructor
    00CFFD74
    Copy constructor called
    00CFFE60
    1 / 2
    */
    
    /* stdout(Release Mode)
    Default constructor
    008FFA24
    008FFA24
    1 / 2
    */
C++/Class 2021. 3. 12. 17:56

위임 생성자 (Delegating Constructor)

  • C++11

  • 생성자에서 직접 생성하지 않고, 이미 구현된 생성자를 호출해서 대신 생성하도록 하는 것이다.


기본 예제

  • 다음 예제에서는 st2를 생성할 때 id_, name_ 멤버 변수를 초기화 리스트로 초기화하고있다.

    #include <iostream>
    
    using namespace std;
    
    class Student
    {
      int        id_;
      string    name_;
    
    public:
      Student(const string& name_in)
        : id_{0}, name_{name_in}
      {
        print();
      }
    
      Student(const int& id_in, const string& name_in)
        : id_{id_in}, name_{name_in}
      {
        print();
      }
    
      void    print()
      {
        cout << id_ << ' ' << name_ << '\n';
      }
    };
    
    int        main()
    {
      Student st1(0, "jack jack");
      Student st2("Dash");
    }
  • 같은 기능을 하는 코드가 여러 군데에 있으면 좋지 않으므로 다음과 같이 변경하는게 좋다.

    #include <iostream>
    
    using namespace std;
    
    class Student
    {
      int        id_;
      string    name_;
    
    public:
      Student(const string& name_in)
        : Student(0, name_in)
      {}
    
      Student(const int& id_in, const string& name_in)
        : id_{id_in}, name_{name_in}
      {
        print();
      }
    
      void    print()
      {
        cout << id_ << ' ' << name_ << '\n';
      }
    };
    
    int        main()
    {
      Student st1(0, "jack jack");
      Student st2("Dash");
    }
  • C++11 이전에서는 다음과 같이 초기화 함수로 작성하는게 일반적이었다고 하는데, 나는 이 방법이 더 좋은 것 같다.

    #include <iostream>
    
    using namespace std;
    
    class Student
    {
      int        id_;
      string    name_;
    
    public:
      Student(const string& name_in)
      {
        init(0, name_in);
      }
    
      Student(const int& id_in, const string& name_in)
      {
        init(id_in, name_in);
      }
    
      void    init(const int& id_in, const string& name_in)
      {
        id_ = id_in;
        name_ = name_in;
        print();
      }
    
      void    print()
      {
        cout << id_ << ' ' << name_ << '\n';
      }
    };
    
    int        main()
    {
      Student st1(0, "jack jack");
      Student st2("Dash");
    }
C++/Class 2021. 3. 12. 17:53

멤버 초기화 리스트 (Member Initializer Lists)

  • 생성자를 만들 때 멤버들을 초기화해주는 기능

    • C++11부터 배열도 이 방식으로 초기화 가능하다고 한다.
    #include <iostream>
    
    class Something
    {
      int        i_;
      double    d_;
      char    c_;
    
    public:
      Something()
        : i_{ 1 }, d_{ 3.14 }, c_{ 'a' }
      {}
    };
    
    int        main()
    {
      Something a;
    }

기본 값 적용 우선순위가 헷갈릴 때

  #include <iostream>

  class Something
  {
      int        i_ = 100;
      double    d_ = 100.0;
      char    c_ = 'F';

  public:
      Something()
          : i_{ 1 }, d_{ 3.14 }, c_{ 'a' }
      {
          i_ *= 3;
          d_ *= 3.0;
          c_ += 3;
          std::cout << i_ << ' ' << d_ << ' ' << c_;
      }
  };

  int        main()
  {
      Something a;
  }

  /* stdout stderr
  3 9.42 d
  */

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

C++ 복사 생성자(Copy Constructor)  (0) 2021.03.12
C++ 위임 생성자 (Delegating Constructor)  (0) 2021.03.12
C++ 생성자 (Constructor)  (0) 2021.03.12
C++ 접근 지정자 (Access Specifier)  (0) 2021.03.12
C++ Class  (0) 2021.03.12
C++/Class 2021. 3. 12. 17:51

생성자 (Constructor)

  • 인스턴스가 처음 생성될 때 호출되는 함수

    • 멤버 변수부터 생성하고 그 다음 호출된다.

      • 멤버 중에 클래스가 있을 경우 해당 클래스의 생성자부터 호출된다.
      #include <iostream>
      
      class Second
      {
      public:
        Second()
        {
          std::cout << "Second constructor\n";
        }
      };
      
      class First
      {
        Second sec;
      
      public:
        First()
        {
          std::cout << "First constructor\n";
        }
      };
      
      int        main()
      {
        First test;
      }
      
      /* stdout
      Second constructor
      First constructor
      */

  • 생성자를 하나도 만들지 않으면 기본으로 다음과 같은 형태가 만들어진다.

    • 아무 것도 안하는 생성자

    • MyClass::MyClass() {}

    • 복사 생성자(Copy Constructor)


    • MyClass::MyClass(const MyClass& instance_in) { // 내부 값을 모두 복사하는 코드 }

  • 생성자의 파라미터에 기본값을 넣을 수 있다.

  • Uniform initialization과 Copy initialization의 차이

    • 형변환이 안된다. (1장 참고)
  • 기법

    • 생성자를 private으로 일부러 설정하는 기법도 존재한다.
  • 주의사항

    • 생성자의 인자가 하나도 없을 경우에만 소괄호를 생략한다.
      • 기본값 설정으로 인자를 넣지 않아도 될 경우에도 마찬가지이다.
      • #include <iostream> class Fraction { int numerator_; int denominator_; public: Fraction(const int& num = 1, const int& den = 3) { numerator_ = num; denominator_ = den; } void print() { std::cout << numerator_ << '/' << denominator_; } }; int main() { Fraction frac; // frac()으로 하면 안됨 frac.print(); } /* stdout stderr 1/3 */

멤버 초기화 리스트 (Member Initializer Lists)

위임 생성자(Delegating Constructor)

복사 생성자(Copy Constructor)

변환 생성자(Converting Constructor)


참고

C++/Class 2021. 3. 12. 17:47

접근 지정자 (Access Specifier)

  • 종류

    • public : 어디서든 접근 가능하다.

    • private : 해당 클래스와 friend 클래스만 접근 가능하다.

    • protected : private 특성을 기본으로, 상속받은 자식 클래스도 접근 가능하다.

  • 명시하지 않는 경우, 기본 값은 private이다.

  • private이어도 같은 클래스면 다른 인스턴스의 멤버를 사용할 수 있다.

    class Date
    {
      int    year_;
      int    month_;
      int    day_;
    
      void copyFrom(const Date& original)
      {
        year_ = original.year_;
        month_ = original.month_;
        day_ = original.day_;
      }
    };
  • public 멤버 변수들에 대해 uniform initialization이 가능하다.

    #include <iostream>
    
    class Date
    {
    public:
        int    year_;
        int    month_;
        int    day_;
    };
    
    int        main()
    {
        using namespace std;
    
        Date a{ 2021, 3, 1 };
        cout << a.year_ << ' ' << a.month_ << ' ' << a.day_ << '\n';
    }
    
    /* stdout stderr
    2021 3 1
    */

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

C++ 복사 생성자(Copy Constructor)  (0) 2021.03.12
C++ 위임 생성자 (Delegating Constructor)  (0) 2021.03.12
C++ 멤버 초기화 리스트 (Member Initializer Lists)  (0) 2021.03.12
C++ 생성자 (Constructor)  (0) 2021.03.12
C++ Class  (0) 2021.03.12
C++/Class 2021. 3. 12. 17:47

Class

struct vs class

  • c++에서의 구조체도 멤버 함수를 가질 수 있다.

    • _단순한 기능_의 경우 struct를 사용해도 무방하다.
  • class를 사용하는 이유는 다양한 객체지향 프로그래밍 기법들을 적용하기 위함이다.

    • Access Specifier (public, private, protected 등)

접근 지정자 (Access Specifier)

생성자 (Constructor)

소멸자 (Destructor)

this

const

static

friend

익명 객체 (Anonymous Class)

Nested Types

실행 시간 측정 (Run Time Measurement)


참고