C++/Class 2021. 3. 20. 17:26

함수 오버라이딩

  • 자식 클래스에서 부모 클래스의 함수명과 같은 함수를 정의할 수 있다.

    • 함수 오버로딩과 비슷하다. 호출하는 클래스에 따라 결정된다는 점이 다르다.

예제

함수 오버라이딩

  #include <iostream>

  class Base
  {
  public:
    void    print()
    {
      std::cout << "I'm Base\n";
    }
  };

  class Derived : private Base
  {
  public:
    void    print()
    {
      Base::print();
      std::cout << "I'm Derived\n";
    }
  };

  int        main()
  {
    using namespace std;

    Derived().print();
  }

  /* stdout
  I'm Base
  I'm Derived
  */

연산자 오버라이딩

  • 연산자 오버로딩도 오버라이딩할 수 있다.

  • static_cast를 통해서 부모 클래스로 형변환하면 부모 클래스에서 오버로딩한 연산자도 사용할 수 있다.

    #include <iostream>
    
    class Base
    {
    public:
      friend std::ostream& operator << (std::ostream& out, const Base& b)
      {
        out << "This is Base output\n";
        return (out);
      }
    };
    
    class Derived : private Base
    {
    public:
      friend std::ostream& operator << (std::ostream& out, const Derived& d)
      {
        out << static_cast<Base>(d);
        out << "This is Derived output\n";
        return (out);
      }
    };
    
    int        main()
    {
      using namespace std;
    
      cout << Derived();
    }
    
    /* stdout
    This is Base output
    This is Derived output
    */

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

C++ 다중 상속  (0) 2021.03.20
C++ 상속받은 멤버의 접근 권한 변경  (0) 2021.03.20
C++ 상속과 접근 지정자  (0) 2021.03.20
C++ 상속과 패딩  (0) 2021.03.20
C++ 유도된 클래스들의 소멸 순서  (0) 2021.03.19
C++/Class 2021. 3. 20. 17:24

상속과 접근 지정자

  • 상속 적용 시 부모 클래스 앞에 public, protected, private와 같은 접근 지정자를 붙인다.

    • 자식 클래스에서 기본적으로 부모 클래스의 멤버들을 어떤 권한으로 받아들일지에 관한 것이다.

예제

  • 아래 예제의 경우 public으로 상속받았으므로 멤버들의 기본 접근 권한이 public이 된다.

    • protected, privatepublic보다 보안이 더 강하므로 그대로 적용된다.
    #include <iostream>
    
    class Base
    {
    public:
      int    public_;
    protected:
      int    protected_;
    private:
      int private_;
    };
    
    class Derived : public Base
    {
    };
    
    int        main()
    {
      using namespace std;
    
      Derived d;
    
      d.public_ = 1024;
    }
  • public 대신 protected를 사용하는 예제

    • public 멤버가 Derived 클래스에서는 protected로 적용된다.

      • Derived 클래스 내부에서는 public_, protected_ 모두 접근할 수 있다.
    #include <iostream>
    
    class Base
    {
    public:
      int    public_;
    protected:
      int    protected_;
    private:
      int    private_;
    };
    
    class Derived : protected Base
    {
    };
    
    int        main()
    {
      using namespace std;
    
      Derived d;
    
      d.public_ = 1024;  // 에러
    }
    • 다음과 같이 접근 오류가 발생한다.

      error C2247: 'Base::public_' not accessible because 'Derived' uses 'protected' to inherit from 'Base'
    • Base 클래스의 멤버가 Derived 클래스 안으로 다음과 같이 들어온 것처럼 생각하면 된다.

      class Derived : protected Base
      {
      protected:
        int    Base::public_;
        int    Base::protected_;
      };

2번 상속하는 경우

  • Base -> Derived -> GrandChild로 상속이 적용되는 예제

    • Derived 클래스가 Base 클래스를 protected로 받은 경우

      • GrandChild 클래스에서 Base 클래스의 protected 멤버까지 접근할 수 있다.
      #include <iostream>
      
      class Base
      {
      public:
        int    public_;
      protected:
        int    protected_;
      private:
        int private_;
      };
      
      class Derived : protected Base
      {
      public:
        Derived()
        {
          Base::public_;
          Base::protected_;
        }
      };
      
      class GrandChild : public Derived
      {
      public:
        GrandChild()
        {
          Derived::Base::public_;
          Derived::Base::protected_;
        }
      };
      
      int        main()
      {
        using namespace std;
      
        Derived d;
      }
    • Derived 클래스가 Base 클래스를 private로 받은 경우

      #include <iostream>
      
      class Base
      {
      public:
        int    public_;
      protected:
        int    protected_;
      private:
        int private_;
      };
      
      class Derived : private Base
      {
      public:
        Derived()
        {
          Base::public_;
          Base::protected_;
        }
      };
      
      class GrandChild : public Derived
      {
      public:
        GrandChild()
        {
          Derived::Base::public_;    // 에러
          Derived::Base::protected_; // 에러
        }
      };
      
      int        main()
      {
        using namespace std;
      
        Derived d;
      }
      • Derived 클래스에서는 Base 클래스의 멤버가 private 상태이기 때문에 접근할 수 있다.

      • 하지만 GrandChild 클래스에서는 Derived 클래스의 private 멤버에 접근할 수 없으므로 다음과 같은 에러가 발생한다.

        error C2247: 'Base::public_' not accessible because 'Derived' uses 'private' to inherit from 'Base'

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

C++ 상속받은 멤버의 접근 권한 변경  (0) 2021.03.20
C++ 함수 오버라이딩  (0) 2021.03.20
C++ 상속과 패딩  (0) 2021.03.20
C++ 유도된 클래스들의 소멸 순서  (0) 2021.03.19
C++ 유도된 클래스들의 생성 순서  (0) 2021.03.19
C++/Class 2021. 3. 20. 17:19

상속과 패딩

  • 일반적인 구조체와 마찬가지로 패딩이 끼게 된다.

    • 패딩이 없는 예제 (int, float)

      #include <iostream>
      
      class Mother
      {
        int i_;
      
      public:
        Mother(const int & i_in = 0)
          : i_(i_in)
        {
          std::cout << "Mother construction\n";
        }
      };
      
      class Child : public Mother
      {
        float d_;
      
      public:
        Child()
          : d_(1.0), Mother(1024)
        {
          std::cout << "Child construction\n";
        }
      };
      
      int        main()
      {
        using namespace std;
      
        cout << sizeof(Mother) << endl;
        cout << sizeof(Child) << endl;
      }
      
      /* stdout
      4
      8
      */
    • 4바이트 패딩 예제 (int, double)

      #include <iostream>
      
      class Mother
      {
        int i_;
      
      public:
        Mother(const int & i_in = 0)
          : i_(i_in)
        {
          std::cout << "Mother construction\n";
        }
      };
      
      class Child : public Mother
      {
        double d_;
      
      public:
        Child()
          : d_(1.0), Mother(1024)
        {
          std::cout << "Child construction\n";
        }
      };
      
      int        main()
      {
        using namespace std;
      
        cout << sizeof(Mother) << endl;
        cout << sizeof(Child) << endl;
      }
      
      /* stdout
      4
      16
      */
    • 끝에 패딩이 4바이트 더 붙은 예제 (int, double, int)

      #include <iostream>
      
      class Mother
      {
        int i_;
      
      public:
        Mother(const int & i_in = 0)
          : i_(i_in)
        {
          std::cout << "Mother construction\n";
        }
      };
      
      class Child : public Mother
      {
        double d_;
        int    tmp_;
      
      public:
        Child()
          : d_(1.0), Mother(1024)
        {
          std::cout << "Child construction\n";
        }
      };
      
      int        main()
      {
        using namespace std;
      
        cout << sizeof(Mother) << endl;
        cout << sizeof(Child) << endl;
      }
      
      /* stdout
      4
      24
      */

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

C++ 함수 오버라이딩  (0) 2021.03.20
C++ 상속과 접근 지정자  (0) 2021.03.20
C++ 유도된 클래스들의 소멸 순서  (0) 2021.03.19
C++ 유도된 클래스들의 생성 순서  (0) 2021.03.19
C++ 상속 Teacher-Student 예제  (0) 2021.03.19
C++/Class 2021. 3. 19. 19:49

유도된 클래스들의 소멸 순서

  • 말단(자식)부터 소멸된다고 생각하면 된다.

    #include <iostream>
    
    class A
    {
    public:
      A(int a = 1024)
      {
        std::cout << "A : " << a << std::endl;
      }
    
      ~A()
      {
        std::cout << "Destructor A" << std::endl;
      }
    };
    
    class B : public A
    {
    public:
      B(double b = 3.14)
      {
        std::cout << "B : " << b << std::endl;
      }
    
      ~B()
      {
        std::cout << "Destructor B" << std::endl;
      }
    };
    
    class C : public B
    {
    public:
      C(char c)
      {
        std::cout << "C : " << c << std::endl;
      }
    
      ~C()
      {
        std::cout << "Destructor C" << std::endl;
      }
    };
    
    int        main()
    {
      using namespace std;
    
      C c('a');
    }
    
    /* stdout
    A : 1024
    B : 3.14
    C : a
    Destructor C
    Destructor B
    Destructor A
    */

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

C++ 상속과 접근 지정자  (0) 2021.03.20
C++ 상속과 패딩  (0) 2021.03.20
C++ 유도된 클래스들의 생성 순서  (0) 2021.03.19
C++ 상속 Teacher-Student 예제  (0) 2021.03.19
C++ 상속 기본 예제  (0) 2021.03.19
C++/Class 2021. 3. 19. 19:48

유도된 클래스들의 생성 순서

  • 당연하게도 부모 클래스부터 생성된다.

    #include <iostream>
    
    class Mother
    {
      int i_;
    
    public:
      Mother()
        : i_(1)
      {
        std::cout << "Mother construction\n";
      }
    };
    
    class Child : public Mother
    {
      double d_;
    
    public:
      Child()
        : d_(1.0)
      {
        std::cout << "Child construction\n";
      }
    };
    
    int        main()
    {
      using namespace std;
    
      Child c;
    }
    
    /* stdout
    Mother construction
    Child construction
    */

  • 멤버 이니셜라이저 리스트

    • 위의 예제에서 Mother::i_의 접근 권한을 public으로 변경하고, Child 생성자에서 멤버 이니셜라이저 리스트로 값을 설정하려하면 다음과 같은 에러가 발생한다.

      error C2614: 'Child': illegal member initialization: 'i_' is not a base or member
    • i_ 대신에, 존재하지 않는 변수인 dummy로 변경하여 컴파일해봐도 같은 오류가 발생한다.

      error C2614: 'Child': illegal member initialization: 'dummy' is not a base or member
    • 즉, 멤버 이니셜라이저 리스트로 초기화할 수 있는건 해당 클래스의 멤버 변수만 해당되는 것을 알 수 있다.

    • 대신 멤버 이니셜라이저 리스트에서 부모 클래스의 생성자를 호출할 수 있고, C++11부터 위임 생성자도 사용 가능하므로 이를 사용하면 될 것 같다.

      #include <iostream>
      
      class Mother
      {
        int i_;
      
      public:
        Mother(const int & i_in = 0)
          : i_(i_in)
        {
          std::cout << "Mother construction\n";
        }
      };
      
      class Child : public Mother
      {
        double d_;
      
      public:
        Child()
          : d_(1.0), Mother(1024)
        {
          std::cout << "Child construction\n";
        }
      };
      
      int        main()
      {
        using namespace std;
      
        Child c;
      }
      
      /* stdout
      Mother construction
      Child construction
      */
    • 부모 클래스의 생성자를 명시하지 않아도 부모 클래스의 기본 생성자가 호출된다.

      • 다음 예제는 부모 클래스의 기본 생성자가 존재하지 않아서 에러가 발생한다.
      #include <iostream>
      
      class Mother
      {
          int i_;
      
      public:
          Mother(const int& i_in)
              : i_(i_in)
          {
              std::cout << "Mother construction\n";
          }
      };
      
      class Child : public Mother
      {
          double d_;
      
      public:
          Child()
              : d_(1.0)
          {
              std::cout << "Child construction\n";
          }
      };
      
      int        main()
      {
          using namespace std;
      
          Child c;
      }
      error C2512: 'Mother': no appropriate default constructor available

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

C++ 상속과 패딩  (0) 2021.03.20
C++ 유도된 클래스들의 소멸 순서  (0) 2021.03.19
C++ 상속 Teacher-Student 예제  (0) 2021.03.19
C++ 상속 기본 예제  (0) 2021.03.19
C++ 상속 (Inheritance)  (0) 2021.03.19
C++/Class 2021. 3. 19. 19:47

상속 Teacher-Student 예제

main.cpp

#include "Student.h"
#include "Teacher.h"

int        main()
{
    using namespace std;

    Student std("Jack Jack");

    std.setName("New Jack");
    std.getName();

    cout << std.getName() << endl;

    Teacher teacher1("Dash");

    teacher1.setName("Dr. K");

    cout << teacher1.getName() << endl;

    cout << std << endl;
    cout << teacher1 << endl;
}

/* stdout
New Jack
Dr. K
New Jack 0
Dr. K
*/

Person.h

#pragma once

#include <iostream>

class Person
{
    std::string name_;

public:
    Person(const std::string & name_in)
        : name_{name_in}
    {}

    std::string    getName() const
    {
        return name_;
    }

    void    setName(const std::string& name_in)
    {
        name_ = name_in;
    }
};

Student.h

#pragma once

#include "Person.h"

class Student : public Person
{
    int        intel_;

public:
    Student(const std::string& name_in = "No Name", const int& intel_in = 0)
        : Person(name_in), intel_{ intel_in }
    {}

    void    setIntel(const int& intel_in)
    {
        intel_ = intel_in;
    }

    int        getIntel()
    {
        return intel_;
    }

    friend std::ostream& operator << (std::ostream& out, const Student& student)
    {
        out << student.getName() << ' ' << student.intel_;
        return out;
    }
};

Teacher.h

#pragma once

#include "Person.h"

class Teacher : public Person
{

public:
    Teacher(const std::string& name_in = "No Name")
        : Person(name_in)
    {}

    friend std::ostream& operator << (std::ostream& out, const Teacher& teacher)
    {
        out << teacher.getName();
        return out;
    }
};

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

C++ 유도된 클래스들의 소멸 순서  (0) 2021.03.19
C++ 유도된 클래스들의 생성 순서  (0) 2021.03.19
C++ 상속 기본 예제  (0) 2021.03.19
C++ 상속 (Inheritance)  (0) 2021.03.19
C++ 의존 관계 (Dependency)  (0) 2021.03.19
C++/Class 2021. 3. 19. 19:45

상속 기본 예제

  • 상속의 본질은 일반화이다.

  • 용어

    • Generalized class : 상속하는 상위 클래스

    • Derived class : 상속을 받은 하위 클래스

  • 예제

    #include <iostream>
    
    using namespace std;
    
    class Mother
    {
      int    i_;
    
    public:
      Mother(const int& i_in = 0)
        : i_{ i_in }
      {
        cout << "Mother Constructor\n";
      }
    
      void        setValue(const int& i_in)
      {
        i_ = i_in;
      }
    
      int        getValue()
      {
        return i_;
      }
    };
    
    class Child : public Mother
    {
      double    d_;
    
    public:
      Child(const int & i_in = 0, const double & d_in = 0)
        //: i_{i_in}, d_{d_in}  // 생성자 호출 순서때문에 불가능
      {
        cout << "Child Constructor\n";
        Mother::setValue(i_in);
        d_ = d_in;
      }
    
      void        setValue(const int& i_in, const double& d_in)
      {
        Mother::setValue(i_in);
        d_ = d_in;
      }
    
      void        setValue(const double& d_in)
      {
        d_ = d_in;
      }
    
      double    getValue()
      {
        return d_;
      }
    };
    
    class Daughter : public Mother  // 여러 클래스로 상속할 수 있다.
    {
    
    };
    
    class Son : public Mother
    {
    
    };
    
    int        main()
    {
      Mother mother(120);
      mother.setValue(1024);
      cout << mother.getValue() << endl;
    
      Child child;
      child.Mother::setValue(987);
      cout << child.Mother::getValue() << endl;
    
      child.setValue(128);
      cout << child.getValue() << endl;
    }
    
    /* stdout
    Mother Constructor
    1024
    Mother Constructor
    Child Constructor
    987
    128
    */
    • 중간 주석 부분을 제거하고 빌드해보면 i_{i_in}에서 오류가 발생한다.

      error C2614: 'Child': illegal member initialization: 'i_' is not a base or member
      • VS에서 마우스를 갖다대면 inaccessible 상태로 나오지만, 접근 지정자 문제는 아니다.

      • 부모 클래스의 생성자를 호출하기 전에 i_ 변수에 접근하려해서 발생하는 오류라고 한다.

      • 이를 해결할 때는 아래와 같이 부모 클래스의 생성자를 활용하는 편인 것 같다.


  • 다음과 같이 부모 클래스의 생성자를 위임 생성자처럼 사용하는게 정석같은 느낌이다.

    #include <iostream>
    
    using namespace std;
    
    class Mother
    {
      int    i_;
    
    public:
      Mother(const int& i_in = 0)
        : i_{ i_in }
      {
        cout << "Mother Constructor\n";
      }
    
      void    setValue(const int& i_in)
      {
        i_ = i_in;
      }
    
      int        getValue()
      {
        return i_;
      }
    };
    
    class Child : public Mother
    {
      double    d_;
    
    public:
      Child(const int & i_in = 0, const double & d_in = 0)
        : Mother(i_in), d_{d_in}
      {
        cout << "Child Constructor\n";
      }
    
      void    setValue(const int& i_in, const double& d_in)
      {
        Mother::setValue(i_in);
        d_ = d_in;
      }
    
      void    setValue(const double& d_in)
      {
        d_ = d_in;
      }
    
      double    getValue()
      {
        return d_;
      }
    };
    
    int        main()
    {
      Mother mother(120);
      mother.setValue(1024);
      cout << mother.getValue() << endl;
    
      Child child;
      child.Mother::setValue(987);
      cout << child.Mother::getValue() << endl;
    
      child.setValue(128);
      cout << child.getValue() << endl;
    }
    
    /* stdout
    Mother Constructor
    1024
    Mother Constructor
    Child Constructor
    987
    128
    */

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

C++ 유도된 클래스들의 생성 순서  (0) 2021.03.19
C++ 상속 Teacher-Student 예제  (0) 2021.03.19
C++ 상속 (Inheritance)  (0) 2021.03.19
C++ 의존 관계 (Dependency)  (0) 2021.03.19
C++ 연계, 제휴 관계 (Association)  (0) 2021.03.19
C++/Class 2021. 3. 19. 19:44

상속 (Inheritance)

  • is-a relationship

기본 예제

상속 Teacher-Student 예제

유도된 클래스들의 생성 순서

유도된 클래스들의 소멸 순서

상속과 패딩

상속과 접근 지정자

함수 오버라이딩

상속받은 멤버의 접근 권한 변경

다중 상속

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

C++ 상속 Teacher-Student 예제  (0) 2021.03.19
C++ 상속 기본 예제  (0) 2021.03.19
C++ 의존 관계 (Dependency)  (0) 2021.03.19
C++ 연계, 제휴 관계 (Association)  (0) 2021.03.19
C++ 구성 관계 (Composition Relationship)  (0) 2021.03.19
C++/TBC++ 2021. 3. 19. 19:43

따라하며 배우는 C++ 11장

상속 (Inheritance)


참고

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

따라하며 배우는 C++ 13장  (0) 2021.03.21
따라하며 배우는 C++ 12장  (0) 2021.03.20
따라하며 배우는 C++ 10장  (0) 2021.03.19
C++ 따라하며 배우는 C++ 9장  (0) 2021.03.16
따라하며 배우는 C++ 8장  (0) 2021.03.12
C++/Library 2021. 3. 19. 19:42

IntArray

  • int 자료형을 여러개 담을 수 있는 컨테이너

    #include <iostream>
    
    class IntArray
    {
        int*        data_ = nullptr;
        unsigned    length_ = 0;
    
    public:
        IntArray(unsigned length = 0)
        {
            initialize(length);
        }
    
        IntArray(const std::initializer_list<int>& list)
        {
            initialize(list.size());
            int count = 0;
            for (auto& e : list)
                data_[count++] = e;
        }
    
        ~IntArray()
        {
            delete[] data_;
        }
    
        void    initialize(unsigned length)
        {
            length_ = length;
            if (length_ > 0)
                data_ = new int[length_];
        }
    
        void    reset()
        {
            if (data_)
            {
                delete[] data_;
                data_ = nullptr;
            }
            length_ = 0;
        }
    
        void    resize(const unsigned& length)
        {
            if (length == 0)
                reset();
            else if (length_ < length)
            {
                int* new_data_ = new int[length];
                for (unsigned i = 0; i < length_; ++i)
                    new_data_[i] = data_[i];
                delete[] data_;
                data_ = new_data_;
            }
            length_ = length;
        }
    
        void    insertBefore(const int& value, const int& ix)
        {
            resize(length_ + 1);
            for (int i = length_ - 2; i >= ix; --i)
                data_[i + 1] = data_[i];
            data_[ix] = value;
        }
    
        void    remove(const int& ix)
        {
            for (int i = ix; i < length_ - 1; ++i)
                data_[i] = data_[i + 1];
            --length_;
            if (length_ <= 0)
                reset();
        }
    
        void    push_back(const int& value)
        {
            insertBefore(value, length_);
        }
    
        friend std::ostream& operator << (std::ostream& out, const IntArray& arr)
        {
            for (unsigned i = 0; i < arr.length_; ++i)
                out << arr.data_[i] << ' ';
            return out;
        }
    };
    
    int        main()
    {
        using namespace std;
    
        IntArray my_arr{ 1, 3, 5, 7, 9 };
        cout << my_arr << endl;
    
        my_arr.insertBefore(10, 1);
        cout << my_arr << endl;
    
        my_arr.remove(3);
        cout << my_arr << endl;
    
        my_arr.push_back(13);
        cout << my_arr << endl;
    }
    
    /* stdout
    1 3 5 7 9
    1 10 3 5 7 9
    1 10 3 7 9
    1 10 3 7 9 13
    */

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

C++ std::exception  (0) 2021.03.22
C++ reference_wrapper  (0) 2021.03.21
C++ initializer_list  (0) 2021.03.19
C++ chrono  (0) 2021.03.16
C++ assert  (0) 2021.03.12
C++/Class 2021. 3. 19. 19:40

의존 관계 (Dependency)

  • Worker 클래스에서 잠깐 사용하는 Timer 클래스

    main.cpp

    #include "Timer.h"
    #include "Worker.h"
    
    int        main()
    {
      Worker().doSomething();
    }
    
    /* stdout
    4e-07
    */

    Timer.h

    #pragma once
    #include <iostream>
    #include <chrono>
    
    using namespace std;
    
    class Timer
    {
        using clock_t = std::chrono::high_resolution_clock;
        using second_t = std::chrono::duration<double, std::ratio<1>>;
    
        std::chrono::time_point<clock_t> start_time = clock_t::now();
    
    public:
        void elapsed()
        {
            std::chrono::time_point<clock_t> end_time = clock_t::now();
    
            cout << std::chrono::duration_cast<second_t>(end_time - start_time).count() << endl;
        }
    };

    Worker.h

    #pragma once
    
    class Worker
    {
    public:
      void    doSomething();
    };

    Worker.cpp

    #include "Worker.h"
    #include "Timer.h"
    
    void    Worker::doSomething()
    {
      Timer timer;
    
      // do some work here
    
      timer.elapsed();
    }

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

C++ 상속 기본 예제  (0) 2021.03.19
C++ 상속 (Inheritance)  (0) 2021.03.19
C++ 연계, 제휴 관계 (Association)  (0) 2021.03.19
C++ 구성 관계 (Composition Relationship)  (0) 2021.03.19
C++ 객체들의 관계 (Object Relationship)  (0) 2021.03.19
C++/Class 2021. 3. 19. 19:40

연계, 제휴 관계 (Association)

  • 의사 클래스와 환자 클래스로 비유

    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    class Doctor;
    
    class Patient
    {
      string            name_;
      vector<Doctor*>    doctors_;
    
    public:
      Patient(const string &name_in)
        : name_{name_in}
      {}
    
      void    addDoctor(Doctor* new_doctor)
      {
        doctors_.push_back(new_doctor);
      }
    
      void    meetDoctors();
    
      friend class Doctor;
    };
    
    class Doctor
    {
      string                name_;
      vector<Patient*>    patients_;
    
    public:
      Doctor(const string &name_in)
        : name_{name_in}
      {}
    
      void    addPatient(Patient* new_patient)
      {
        patients_.push_back(new_patient);
      }
    
      void    meetPatients()
      {
        for (auto& e : patients_)
          cout << "Meet patient : " << e->name_ << '\n';
      }
    
      friend class Patient;
    };
    
    void    Patient::meetDoctors()
    {
      for (auto& e : doctors_)
        cout << "Meet doctor : " << e->name_ << '\n';
    }
    
    int        main()
    {
      Patient* p1 = new Patient("Jack Jack");
      Patient* p2 = new Patient("Dash");
      Patient* p3 = new Patient("Violet");
    
      Doctor* d1 = new Doctor("Doctor K");
      Doctor* d2 = new Doctor("Doctor L");
    
      p1->addDoctor(d1);
      d1->addPatient(p1);
    
      p2->addDoctor(d2);
      d2->addPatient(p2);
    
      p2->addDoctor(d1);
      d1->addPatient(p2);
    
      cout << "p1\n";
      p1->meetDoctors();
    
      cout << "\nd1\n";
      d1->meetPatients();
    
      delete p1, p2, p3, d1, d2;
    
    }
    
    /* stdout
    p1
    Meet doctor : Doctor K
    
    d1
    Meet patient : Jack Jack
    Meet patient : Dash
    */

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

C++ 상속 (Inheritance)  (0) 2021.03.19
C++ 의존 관계 (Dependency)  (0) 2021.03.19
C++ 구성 관계 (Composition Relationship)  (0) 2021.03.19
C++ 객체들의 관계 (Object Relationship)  (0) 2021.03.19
C++ Nested Types  (0) 2021.03.16
C++/Class 2021. 3. 19. 19:37

구성 관계 (Composition Relationship)

  • 몬스터 클래스와 그의 멤버인 좌표 클래스로 비유했다.

  • Monster 클래스의 멤버로 존재하는 Position2D 클래스 인스턴스 location_ (Monster.h 참고)

    • location_ 인스턴스는 Monster 클래스로 만들어진 mon1 인스턴스의 Part-of라고 할 수 있다.

    • mon1이 소멸하면 자동으로 location_도 소멸한다.

    main.cpp

    #include "Monster.h"
    
    int        main()
    {
        using namespace std;
    
        Monster mon1("Sanson", Position2D(0, 0));
    
        cout << mon1 << endl;
        {
            mon1.moveTo(Position2D(1, 1));
            cout << mon1 << endl;
        }
    }
    
    /* stdout
    Sanson 0 0
    Sanson 1 1
    */

    Monster.h

    #pragma once
    #include "Position2D.h"
    
    class Monster
    {
      std::string   name_;
      Position2D    location_;
    
    public:
      Monster(const std::string name_in, const Position2D & pos_in)
        : name_{name_in}, location_{pos_in}
      {}
    
      void    moveTo(const Position2D& pos_target)
      {
        location_.set(pos_target);
      }
    
      friend std::ostream& operator << (std::ostream& out, const Monster& monster)
      {
        out << monster.name_ << ' ' << monster.location_;
        return (out);
      }
    };

    Position2D.h

    #pragma once
    
    #include <iostream>
    
    class Position2D
    {
      int    x_;
      int    y_;
    
    public:
      Position2D(const int &x_in, const int &y_in)
        : x_(x_in), y_(y_in)
      {}
    
      void    set(const Position2D& pos_target)
      {
        set(pos_target.x_, pos_target.y_);
      }
    
      void    set(const int& x_target, const int& y_target)
      {
        x_ = x_target;
        y_ = y_target;
      }
    
      friend std::ostream& operator << (std::ostream& out, const Position2D& pos)
      {
        out << pos.x_ << ' ' << pos.y_;
        return (out);
      }
    };

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

C++ 의존 관계 (Dependency)  (0) 2021.03.19
C++ 연계, 제휴 관계 (Association)  (0) 2021.03.19
C++ 객체들의 관계 (Object Relationship)  (0) 2021.03.19
C++ Nested Types  (0) 2021.03.16
C++ 익명 객체 (Anonymous Class)  (0) 2021.03.16
C++/Class 2021. 3. 19. 19:37

객체들의 관계 (Object Relationship)

관계 관계를 표현하는 동사 예시
구성 (Composition) Part-of 두뇌육체의 일부이다
집합 (Aggregation) Has-a 어떤 사람자동차를 가지고 있다.
연계 (Association) Uses-a 환자의사의 치료를 받는다.
의사환자들로부터 치료비를 받는다.
의존 (Dependency) Depends-on 목발을 짚었다.

관계 관계의 형태 다른 클래스에도 속할 수 있는가 멤버의 존재를 클래스가 관리하는가 방향성
구성 (Composition) 전체/부품 No Yes 단방향
집합 (Aggregation) 전체/부품 Yes No 단방향
연계 (Association) 용도 외 무관 Yes No 단방향, 양방향
의존 (Dependency) 용도 외 무관 Yes Yes 단방향

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

C++ 연계, 제휴 관계 (Association)  (0) 2021.03.19
C++ 구성 관계 (Composition Relationship)  (0) 2021.03.19
C++ Nested Types  (0) 2021.03.16
C++ 익명 객체 (Anonymous Class)  (0) 2021.03.16
C++ friend  (0) 2021.03.16
C++/TBC++ 2021. 3. 19. 19:36

따라하며 배우는 C++ 10장

객체들의 관계 (Object Relationship)

IntArray 컨테이너 만들어보기


참고

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

따라하며 배우는 C++ 12장  (0) 2021.03.20
따라하며 배우는 C++ 11장  (0) 2021.03.19
C++ 따라하며 배우는 C++ 9장  (0) 2021.03.16
따라하며 배우는 C++ 8장  (0) 2021.03.12
따라하며 배우는 C++ 7장  (0) 2021.03.12
C++/Library 2021. 3. 19. 19:35

initializer_list

  • C++11

  • <initializer_list> 라이브러리

  • [] 연산자를 사용할 수 없다.

    • foreach문은 내부적으로 iterator를 사용한다.

    • 내부적으로 iterator를 사용하는 foreach문으로 반복문을 구성하면 된다.

      #include <iostream>
      //#include <initializer_list>
      
      class IntArray
      {
          unsigned    len_ = 0;
          int*        data_ = nullptr;
      
      public:
          IntArray(unsigned length)
              : len_(length)
          {
              data_ = new int[len_];
          }
      
          IntArray(const std::initializer_list<int>& list)
              : IntArray(list.size())
          {
              int count = 0;
              for (auto& e : list)
              {
                  data_[count] = e;
                  ++count;
              }
          }
      
          ~IntArray()
          {
              delete[] data_;
          }
      
          friend std::ostream& operator << (std::ostream& out, const IntArray& arr)
          {
              for (unsigned i = 0; i < arr.len_; ++i)
              {
                  out << arr.data_[i] << ' ';
              }
              return out;
          }
      };
      
      int        main()
      {
          using namespace std;
      
          auto il = { 10, 20 , 30 };  // std::initializer_list<int>
      
          IntArray arr1{ il };
          cout << arr1 << endl;
      
          IntArray arr2 = { 1, 2, 3, 4, 5 };
          cout << arr2 << endl;
      }
      
      /* stdout
      10 20 30
      1 2 3 4 5
      */

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

C++ reference_wrapper  (0) 2021.03.21
C++ IntArray  (0) 2021.03.19
C++ chrono  (0) 2021.03.16
C++ assert  (0) 2021.03.12
C++ vector  (0) 2021.03.12
C++/Overloading 2021. 3. 19. 19:32

대입 연산자 오버로딩 (Assignment Operator Overloading)

  • 자기 자신을 assignment할 때(hello = hello 등) 발생할 수 있는 문제를 미리 방지할 수 있다.

  • 깊은 복사를 직접 구현할 수 있다.

    #include <iostream>
    #include <cassert>
    
    class MyString
    {
        char* data_ = nullptr;
        int        len_ = 0;
    
    public:
        MyString(const char* source = "")
        {
            assert(source);
    
            len_ = std::strlen(source) + 1;
            data_ = new char[len_];
    
            for (int i = 0; i < len_; ++i)
                data_[i] = source[i];
            data_[len_ - 1] = '\0';
        }
    
        ~MyString()
        {
            delete[] data_;
        }
    
        MyString(const MyString& source)
        {
            std::cout << "Copy constructor\n";
    
            len_ = source.len_;
    
            if (source.data_ != nullptr)
            {
                data_ = new char[len_];
    
                for (int i = 0; i < len_; ++i)
                    data_[i] = source.data_[i];
            }
            else
                data_ = nullptr;
        }
    
        char*& getString() { return data_; }
    
        MyString& operator = (const MyString& source)
        {
            std::cout << "Assignment operator\n";
    
            if (this == &source)  // prevent self-assignment
                return *this;
    
            delete[] data_;
    
            len_ = source.len_;
    
            if (source.data_ != nullptr)
            {
                data_ = new char[len_];
    
                for (int i = 0; i < len_; ++i)
                    data_[i] = source.data_[i];
            }
            else
                data_ = nullptr;
        }
    };
    
    int        main()
    {
        using namespace std;
    
        MyString    hello("Hello");
    
        cout << (int*)hello.getString() << endl;
        cout << hello.getString() << endl;
    
        {
            MyString    copy;
    
            copy = hello;
    
            cout << (int*)copy.getString() << endl;
            cout << copy.getString() << endl;
        }
    
        cout << hello.getString() << endl;
    }
    
    /* stdout
    00C0EAD8
    Hello
    Assignment operator
    00C0E5D0
    Hello
    Hello
    */
  • 같은 자료형을 인자로 넣는 초기화는 Copy Constructor를 호출한다.

    • 대입 연산자를 통해 값을 넣으려면 초기화가 아닌 대입을 해야한다.

      #include <iostream>
      #include <cassert>
      
      class MyString
      {
          char* data_ = nullptr;
          int        len_ = 0;
      
      public:
          MyString(const char* source = "")
          {
              assert(source);
      
              len_ = std::strlen(source) + 1;
              data_ = new char[len_];
      
              for (int i = 0; i < len_; ++i)
                  data_[i] = source[i];
              data_[len_ - 1] = '\0';
          }
      
          ~MyString()
          {
              delete[] data_;
          }
      
          MyString(const MyString& source)
          {
              std::cout << "Copy constructor\n";
      
              len_ = source.len_;
      
              if (source.data_ != nullptr)
              {
                  data_ = new char[len_];
      
                  for (int i = 0; i < len_; ++i)
                      data_[i] = source.data_[i];
              }
              else
                  data_ = nullptr;
          }
      
          char*& getString() { return data_; }
      
          MyString& operator = (const MyString& source)
          {
              std::cout << "Assignment operator\n";
      
              if (this == &source)  // prevent self-assignment
                  return *this;
      
              delete[] data_;
      
              len_ = source.len_;
      
              if (source.data_ != nullptr)
              {
                  data_ = new char[len_];
      
                  for (int i = 0; i < len_; ++i)
                      data_[i] = source.data_[i];
              }
              else
                  data_ = nullptr;
          }
      };
      
      int        main()
      {
          using namespace std;
      
          MyString    hello("Hello");
      
          MyString    str1 = hello;
      
          MyString    str2(hello);
      
          MyString    str3{ hello };
      
          MyString    str4;
      
          str4 = hello;
      }
      
      /* stdout
      Copy constructor
      Copy constructor
      Copy constructor
      Assignment operator
      */
C++/Overloading 2021. 3. 16. 00:29

형변환 오버로딩 (Typecasts Overloading)

  • (int)객체, int(객체), static_cast<int>(객체) 등의 형태로 형변환을 할 수 있게 해준다.

  • 묵시적 형변환도 가능해진다.


예제

  #include <iostream>

  class Cents
  {
    int cents_;

  public:
    Cents(int cents = 0) { cents_ = cents; }

    operator int()
    {
      std::cout << "cast here" << std::endl;
      return cents_;
    }
  };

  void    printInt(const int& value)
  {
    std::cout << value << std::endl;
  }

  int        main()
  {
    using namespace std;

    Cents    cents(7);

    printInt(cents);

    int value;

    value = (int)cents;
    value = int(cents);
    value = static_cast<int>(cents);
  }

  /* stdout
  cast here
  7
  cast here
  cast here
  cast here
  */
  • 다른 객체로의 형변환 오버로딩도 가능하다.

    #include <iostream>
    
    class Cents
    {
      int cents_ = 0;
    
    public:
      Cents(const int& cents = 0) { cents_ = cents; }
    
      operator int()
      {
        std::cout << "cast here" << std::endl;
        return cents_;
      }
    };
    
    class Dollars
    {
      int    dollars_ = 0;
    
    public:
      Dollars(const int& dollars = 0) { dollars_ = dollars; }
    
      operator Cents()
      {
        return Cents(dollars_ * 100);
      }
    };
    
    void    printInt(const int& value)
    {
      std::cout << value << std::endl;
    }
    
    int        main()
    {
      using namespace std;
    
      Dollars    dol(2);
      Cents    cents(dol);
    
      printInt(cents);
    }
    
    /* stdout
    cast here
    200
    */
C++/Overloading 2021. 3. 16. 00:27

괄호 연산자 오버로딩 (Parenthesis Operator Overloading)

  • ()(parenthesis)

  • Functor

    • 객체를 함수처럼 사용하는 것

예제

  #include <iostream>

  class Accumulator
  {
    int counter_ = 0;

  public:
    int operator() (int i) { return (counter_ += i); }
  };

  int        main()
  {
    using namespace std;

    Accumulator acc;

    cout << acc(10) << endl;
    cout << acc(20) << endl;
  }

  /* stdout
  10
  30
  */
C++/Overloading 2021. 3. 16. 00:26

첨자 연산자 오버로딩 (Subscript Operator Overloading)

  • [](subscript operator) 내부에 숫자 뿐만 아니라 문자 등 다양한 자료형이 들어갈 수 있다.

예제

  #include <iostream>

  class IntList
  {
    int    list_[10];

  public:
    int& operator [] (const int index)
    {
      return list_[index];
    }
  };

  int        main()
  {
    using namespace std;

    IntList my_list;
    my_list[3] = 1;
    cout << my_list[3] << endl;
    my_list[3] = 10;
    cout << my_list[3] << endl;
  }

  /* stdout
  1
  10
  */
  • const를 사용할 경우

    #include <iostream>
    
    class IntList
    {
      int    list_[10] = { 0, 1, 2, 3, 4, 5 };
    
    public:
      int& operator [] (const int index)
      {
        return list_[index];
      }
    
      const int& operator [] (const int index) const
      {
        return list_[index];
      }
    };
    
    int        main()
    {
      using namespace std;
    
      const IntList my_list;
    
      cout << my_list[3] << endl;
    }
    
    /* stdout
    3
    */
C++/Overloading 2021. 3. 16. 00:25

증감 연산자 오버로딩 (Increment and Decrement Operator Overloading)

  • ++ 연산자 오버로딩 예제

    • 전위(prefix), 후위(postfix)에 따라 오버로딩 방식이 다르다.

      • 클래스 내에서 정의하는 연산자 오버로딩은 파라미터를 받지 않으면 단항 연산자처럼 앞에 붙는 방식으로 오버로딩된다. (전위)

      • 따라서 후위 연산자를 오버로딩하려면 int 자료형의 더미 변수가 있어야 한다.

      #include <iostream>
      
      class Digit
      {
        int    digit_;
      
      public:
        Digit(const int& digit) { digit_ = digit; }
      
        // prefix
        Digit& operator ++ ()
        {
          ++digit_;
          return (*this);
        }
      
        // postfix
        Digit operator ++ (int)
        {
          Digit temp(digit_);
          ++(*this);
          return (temp);
        }
      
        friend std::ostream& operator << (std::ostream& out, const Digit& d)
        {
          out << d.digit_;
          return (out);
        }
      };
      
      int        main()
      {
        using namespace std;
      
        Digit    d(5);
      
        cout << d << endl;
        cout << ++d << endl;
        cout << d++ << endl;
        cout << d << endl;
      }
      
      /* stdout
      5
      6
      6
      7
      */
      • int 대신 다른 자료형으로 바꿔보면 다음과 같은 오류가 발생한다.

        error C2807: the second formal parameter to postfix 'operator ++' must be 'int'
C++/Overloading 2021. 3. 16. 00:25

비교 연산자 오버로딩 (Comparison Operator Overloading)

  • if문, std::sort 등을 사용하려면 필수적으로 구현해야 한다.

예제

  • ==, != 오버로딩 예제

    #include <iostream>
    
    class Cents
    {
      int    cents_;
    
    public:
      Cents(int cents = 0) { cents_ = cents; }
    
      bool operator == (Cents& c)
      {
        return (cents_ == c.cents_);
      }
    
      bool operator != (Cents& c)
      {
        return (cents_ != c.cents_);
      }
    
      friend std::ostream& operator << (std::ostream& out, const Cents& cents)
      {
        out << cents.cents_;
        return (out);
      }
    };
    
    int        main()
    {
      using namespace std;
    
      Cents    c1{ 6 };
      Cents    c2{ 6 };
      Cents    c3{ 0 };
    
      cout << std::boolalpha;
      cout << (c1 == c2) << endl;
      cout << (c1 != c2) << endl;
      cout << (c1 == c3) << endl;
      cout << (c1 != c3) << endl;
    }
    
    /* stdout
    true
    false
    false
    true
    */
  • < 오버로딩 예제

    • std::sort 함수를 사용하려면 < 연산자를 오버로딩해야 한다.
    #include <iostream>
    #include <vector>
    #include <algorithm>
    
    class Cents
    {
      int    cents_;
    
    public:
      Cents(int cents = 0) { cents_ = cents; }
      int& getCents() { return cents_; }
    
      bool    operator < (const Cents& c)
      {
        return (cents_ < c.cents_);
      }
    
      friend std::ostream& operator << (std::ostream& out, const Cents& cents)
      {
        out << cents.cents_;
        return (out);
      }
    };
    
    int        main()
    {
      using namespace std;
    
      vector<Cents>    arr(20);
    
      for (size_t i = 0; i < 20; ++i)
        arr[i].getCents() = i;
    
      std::random_shuffle(begin(arr), end(arr));
    
      for (auto& e : arr)
        cout << e << ' ';
      cout << endl;
    
      std::sort(begin(arr), end(arr));
    
      for (auto& e : arr)
        cout << e << ' ';
      cout << endl;
    }
    
    /* stdout
    12 1 9 2 0 11 7 19 4 15 18 5 14 13 10 16 6 3 8 17
    0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
    */
C++/Overloading 2021. 3. 16. 00:24

단항 연산자 오버로딩 (Unary Operator Overloading)

  • -, ! 오버로딩

    #include <iostream>
    
    class Cents
    {
      int    cents_;
    
    public:
      Cents(int cents = 0) { cents_ = cents; }
    
      Cents operator - () const
      {
        return Cents(-cents_);
      }
    
      bool operator ! () const
      {
        return (cents_ == 0) ? true : false;
      }
    
      friend std::ostream& operator << (std::ostream& out, const Cents& cents)
      {
        out << cents.cents_;
        return (out);
      }
    };
    
    int        main()
    {
      using namespace std;
    
      Cents    c1{ 6 };
      Cents    c2{ 0 };
    
      cout << -c1 << ' ' << -c2 << endl;
      cout << std::boolalpha;
      cout << !c1 << ' ' << !c2 << endl;
    }
    
    /* stdout
    -6 0
    false true
    */
C++/Overloading 2021. 3. 16. 00:20

입출력 연산자 오버로딩 (I/O Operator Overloading)

  • 멤버 함수로 만들 수 없다.

    • 첫 번째 인자가 stream이기 때문이다.

예제

  • friend를 사용한 출력 연산자 오버로딩 예제

    #include <iostream>
    
    class Point
    {
      double    x_;
      double    y_;
      double    z_;
    
    public:
      Point(double x = 0.0, double y = 0.0, double z = 0.0)
        : x_(x), y_(y), z_(z)
      {}
    
      friend std::ostream& operator << (std::ostream& out, const Point& p)
      {
        out << '(' << p.x_ << ", " << p.y_ << ", " << p.z_ << ')';
        return (out);
      }
    };
    
    int        main()
    {
      using namespace std;
    
      Point p1(0.0, 0.1, 0.2), p2(3.4, 1.5, 2.0);
    
      cout << p1 << ' ' << p2 << endl;
    }
    
    /* stdout
    (0, 0.1, 0.2) (3.4, 1.5, 2)
    */
  • stream을 통해 파일 입출력을 할 경우, 이를 이용해서 굉장히 쉽게 할 수 있다.

    • 출력되는 파일은 VS기준 왼쪽 위의 파일명을 우클릭해서 나오는 Open Containing folder를 클릭하면 열리는 폴더에 있다.
      • 단축키는 Ctrl + K를 누른 다음 R을 누르면 된다. (Ctrl + R이 아니다.)
    #include <iostream>
    #include <fstream>
    
    class Point
    {
      double    x_;
      double    y_;
      double    z_;
    
    public:
      Point(double x = 0.0, double y = 0.0, double z = 0.0)
        : x_(x), y_(y), z_(z)
      {}
    
      friend std::ostream& operator << (std::ostream& out, const Point& p)
      {
        out << '(' << p.x_ << ", " << p.y_ << ", " << p.z_ << ')';
        return (out);
      }
    };
    
    int        main()
    {
      using namespace std;
    
      Point p1(0.0, 0.1, 0.2), p2(3.4, 1.5, 2.0);
    
      ofstream of("out.txt");
    
      of << p1 << ' ' << p2 << endl;
    
      of.close();
    }
    
    /* out.txt
    (0, 0.1, 0.2) (3.4, 1.5, 2)
    */
  • friend를 사용한 입력 연산자 오버로딩 예제

    #include <iostream>
    
    class Point
    {
      double    x_;
      double    y_;
      double    z_;
    
    public:
      Point(double x = 0.0, double y = 0.0, double z = 0.0)
        : x_(x), y_(y), z_(z)
      {}
    
      friend std::ostream& operator << (std::ostream& out, const Point& p)
      {
        out << '(' << p.x_ << ", " << p.y_ << ", " << p.z_ << ')';
        return (out);
      }
    
      friend std::istream& operator >> (std::istream& in, Point& p)
      {
        in >> p.x_ >> p.y_ >> p.z_;
        return (in);
      }
    };
    
    int        main()
    {
      using namespace std;
    
      Point p1, p2;
    
      cin >> p1 >> p2;
    
      cout << p1 << ' ' << p2 << endl;
    }
    
    /* stdin
    1 2 3 4 5 6
    */
    
    /* stdout
    (1, 2, 3) (4, 5, 6)
    */
C++/Overloading 2021. 3. 16. 00:19

산술 연산자 오버로딩 (Arithmetic Operator Overloading)

  • 클래스 안에서 정의해도 되고, 밖에서 정의해도 된다.

    • 안에서 정의할 때는 this로 첫 번째 파라미터를 받게되므로 파라미터가 하나 줄어든다.

    • 밖에서 정의할 때는 클래스에서 friend 키워드로 선언해주는게 편할 수도 있다.


예제

  • 오버로딩을 하지 않은 예제

    #include <iostream>
    
    class Cents
    {
      int    cents_;
    
    public:
      Cents(const int& cents = 0) { cents_ = cents; }
      int        getCents() const { return cents_; }
      int&    getCents() { return cents_; }
    };
    
    Cents    add(const Cents& c1, const Cents& c2)
    {
      return Cents(c1.getCents() + c2.getCents());
    }
    
    int        main()
    {
      using namespace std;
    
      Cents cents1(6);
      Cents cents2(8);
    
      cout << add(cents1, cents2).getCents() << endl;
    }
    
    /* stdout
    14
    */
  • + 연산자 오버로딩을 하면 다음과 같다.

    #include <iostream>
    
    class Cents
    {
      int    cents_;
    
    public:
      Cents(const int& cents = 0) { cents_ = cents; }
      int        getCents() const { return cents_; }
      int&    getCents() { return cents_; }
    };
    
    Cents    operator + (const Cents& c1, const Cents& c2)
    {
      return Cents(c1.getCents() + c2.getCents());
    }
    
    int        main()
    {
      using namespace std;
    
      Cents cents1(6);
      Cents cents2(8);
    
      cout << (cents1 + cents2 + Cents(6)).getCents() << endl;
    }
    
    /* stdout
    20
    */
  • 클래스 안에서 정의하면 다음과 같다.

    #include <iostream>
    
    class Cents
    {
      int    cents_;
    
    public:
      Cents(const int& cents = 0) { cents_ = cents; }
      int        getCents() const { return cents_; }
      int&    getCents() { return cents_; }
    
      Cents    operator + (const Cents& c2)
      {
        return Cents(cents_ + c2.cents_);
      }
    };
    
    int        main()
    {
      using namespace std;
    
      Cents cents1(6);
      Cents cents2(8);
    
      cout << (cents1 + cents2 + Cents(16)).getCents() << endl;
    }
    
    /* stdout
    30
    */
C++/Overloading 2021. 3. 16. 00:16

오버로딩 (Overloading)

산술 연산자 오버로딩 (Arithmetic Operator Overloading)

입출력 연산자 오버로딩 (I/O Operator Overloading)

단항 연산자 오버로딩 (Unary Operator Overloading)

비교 연산자 오버로딩 (Comparison Operator Overloading)

증감 연산자 오버로딩 (Increment and Decrement Operator Overloading)

첨자 연산자 오버로딩 (Subscript Operator Overloading)

괄호 연산자 오버로딩 (Parenthesis Operator Overloading)

형변환 오버로딩 (Typecasts Overloading)

대입 연산자 오버로딩 (Assignment Operator Overloading)


주의사항

  • 클래스 안에서 멤버로만 오버로딩할 수 있는 연산자

    • =(assignment), [](subscript), ()(parenthesis), ->(member access through pointer)
  • 오버로딩이 불가능한 연산자

    • ?:(삼항 연산자), ::, sizeof, ., .*
  • 오버로딩을 해도 연산자 우선순위는 변하지 않는다.

    • ^의 경우 우선순위가 매우 낮은 편이기 때문에, 사용하려면 괄호로 감싸는게 안전하다.
C++/TBC++ 2021. 3. 16. 00:15

따라하며 배우는 C++ 9장

오버로딩 (Overloading)

복사 생성자 (Copy Constructor)

변환 생성자 (Converting Constructor)

delete

얕은 복사 (Shallow Copy)

깊은 복사 (Deep Copy)

이니셜라이저 리스트 (Initializer List)


참고

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

따라하며 배우는 C++ 11장  (0) 2021.03.19
따라하며 배우는 C++ 10장  (0) 2021.03.19
따라하며 배우는 C++ 8장  (0) 2021.03.12
따라하며 배우는 C++ 7장  (0) 2021.03.12
따라하며 배우는 C++ 6장  (0) 2021.03.11
C++/Library 2021. 3. 16. 00:13

chrono

  • <chrono> 라이브러리

    • C++11

    • 실행 시간 측정(Run Time Measurement)에 사용되며, 시간을 비교적 정밀하게 측정할 수 있다.

    #include <iostream>
    #include <vector>
    #include <algorithm>
    #include <random>
    #include <chrono>
    
    using namespace std;
    
    class Timer
    {
      using clock_t = std::chrono::high_resolution_clock;
      using second_t = std::chrono::duration<double, std::ratio<1>>;
    
      std::chrono::time_point<clock_t> start_time = clock_t::now();
    
    public:
      void elapsed()
      {
        std::chrono::time_point<clock_t> end_time = clock_t::now();
    
        std::cout << std::chrono::duration_cast<second_t>(end_time - start_time).count() << std::endl;
      }
    };
    
    int        main()
    {
      random_device    rnd_device;
      mt19937            mersenne_engin{ rnd_device() };
    
      vector<int>        vec(100000);
      for (size_t i = 0; i < vec.size(); ++i)
        vec[i] = i;
    
      std::shuffle(begin(vec), end(vec), mersenne_engin);
    
      /*for (auto& e : vec) cout << e << ' ';
      cout << endl;*/
    
      Timer timer;
    
      std::sort(begin(vec), end(vec));
    
      timer.elapsed();
    
      /*for (auto& e : vec) cout << e << ' ';
      cout << endl;*/
    }

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

C++ IntArray  (0) 2021.03.19
C++ initializer_list  (0) 2021.03.19
C++ assert  (0) 2021.03.12
C++ vector  (0) 2021.03.12
C++ tuple  (0) 2021.03.12
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++'에 해당되는 글 185건