<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>m_jooong.log</title>
        <link>https://velog.io/</link>
        <description></description>
        <lastBuildDate>Fri, 16 Jun 2023 10:08:35 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <image>
            <title>m_jooong.log</title>
            <url>https://velog.velcdn.com/images/m_jooong/profile/264b19bd-aaeb-47d8-8ccf-bae9b5654741/image.jpg</url>
            <link>https://velog.io/</link>
        </image>
        <copyright>Copyright (C) 2019. m_jooong.log. All rights reserved.</copyright>
        <atom:link href="https://v2.velog.io/rss/m_jooong" rel="self" type="application/rss+xml"/>
        <item>
            <title><![CDATA[ActorWorldOffset]]></title>
            <link>https://velog.io/@m_jooong/ActorWorldOffset</link>
            <guid>https://velog.io/@m_jooong/ActorWorldOffset</guid>
            <pubDate>Fri, 16 Jun 2023 10:08:35 GMT</pubDate>
            <description><![CDATA[<pre><code>// Movement rate in units of cm/s
float MovementRate = 50.f;
float RotationRate = 45.f;


// MovementRate * DeltaTime (cm/s) * (s/frame)
// 이동
AddActorWorldOffset(FVector(MovementRate * DeltaTime, 0.f, 0.f));
// 회전
AddActorWorldRotation(FRotator(0.f, RotationRate * DeltaTime, 0.f));

DRAW_SPHERE_SingleFrame(GetActorLocation());
// DebugLine &amp; DebugPoint 그리기
DRAW_VECTOR_SingleFrame(GetActorLocation(), GetActorLocation() + GetActorForwardVector() * 100.f);</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[DebugMacro]]></title>
            <link>https://velog.io/@m_jooong/Drawing-Debug-Sphere</link>
            <guid>https://velog.io/@m_jooong/Drawing-Debug-Sphere</guid>
            <pubDate>Thu, 15 Jun 2023 15:00:46 GMT</pubDate>
            <description><![CDATA[<h1 id="디버그-매크로">디버그 매크로</h1>
<pre><code>#pragma once
#include &quot;DrawDebugHelpers.h&quot;



#define DRAW_SPHERE(Location) if (GetWorld()) DrawDebugSphere(GetWorld(), Location, 25.f, 12, FColor::Red, true);
#define DRAW_LINE(StartLocation, EndLocation) if (GetWorld()) DrawDebugLine(GetWorld(), StartLocation, EndLocation, FColor::Red, true, -1.f, 0, 1.f);
#define DRAW_POINT(Location) if (GetWorld()) DrawDebugPoint(GetWorld(), Location, 15.f, FColor::Red, true);
#define DRAW_VECTOR(StartLocation, EndLocation) if(GetWorld()) \
    { \
        DrawDebugLine(GetWorld(), StartLocation, EndLocation, FColor::Red, true, -1.f, 0, 1.f); \
        DrawDebugPoint(GetWorld(), EndLocation, 15.f, FColor::Red, true); \
    }</code></pre><h1 id="디버그-그리기"><strong>디버그 그리기</strong></h1>
<pre><code>void AItem::BeginPlay()
{
    Super::BeginPlay();

    UWorld* World = GetWorld();
    FVector Location = GetActorLocation();
    FVector Forward = GetActorForwardVector();

    DRAW_SPHERE(Location);
    //DRAW_LINE(Location, Location + Forward * 100.f);
    //DRAW_POINT(Location + Forward * 100.f);
    DRAW_VECTOR(Location, Location + Forward * 100.f);

}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[AddOnScreenDebugMessage]]></title>
            <link>https://velog.io/@m_jooong/AddOnScreenDebugMessage</link>
            <guid>https://velog.io/@m_jooong/AddOnScreenDebugMessage</guid>
            <pubDate>Thu, 15 Jun 2023 14:30:35 GMT</pubDate>
            <description><![CDATA[<blockquote>
<h1 id="output-log-screendebugmesssage-문자-출력하기"><strong>Output Log, ScreenDebugMesssage 문자 출력하기</strong></h1>
</blockquote>
<pre><code>// Fill out your copyright notice in the Description page of Project Settings.


#include &quot;Items/Item.h&quot;

AItem::AItem()
{
    PrimaryActorTick.bCanEverTick = true;

}

void AItem::BeginPlay()
{
    Super::BeginPlay();

    UE_LOG(LogTemp, Warning, TEXT(&quot;BEGIN PLAY CALLED!&quot;));

    if (GEngine)
    {
        GEngine-&gt;AddOnScreenDebugMessage(1, 60.f, FColor::Cyan, FString(&quot;Item OnScreen Message!&quot;));
    }

}

void AItem::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

    UE_LOG(LogTemp, Warning, TEXT(&quot;DELTATIME: %f&quot;), DeltaTime);

    if (GEngine)
    {
        FString Name = GetName();
        FString Message = FString::Printf(TEXT(&quot;ItemName: %s&quot;), *Name);
        GEngine-&gt;AddOnScreenDebugMessage(1, 60.f, FColor::Cyan, Message);

        UE_LOG(LogTemp, Warning, TEXT(&quot;ItemName: %s&quot;), *Name);
    }
}

</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[CharacterController 이동 함수 소개]]></title>
            <link>https://velog.io/@m_jooong/CharacterController-%EC%9D%B4%EB%8F%99-%ED%95%A8%EC%88%98-%EC%86%8C%EA%B0%9C</link>
            <guid>https://velog.io/@m_jooong/CharacterController-%EC%9D%B4%EB%8F%99-%ED%95%A8%EC%88%98-%EC%86%8C%EA%B0%9C</guid>
            <pubDate>Thu, 01 Jun 2023 05:24:16 GMT</pubDate>
            <description><![CDATA[<p><a href="https://truecode.tistory.com/22">https://truecode.tistory.com/22</a></p>
<p><a href="https://mentum.tistory.com/416">https://mentum.tistory.com/416</a></p>
<pre><code>


            //CharacterController : Move()

            //- 인자는 float(방향 x 속도 x deltaTime를 곱해서 넘겨주자)

            //- 중력을 받지않는다! 때문에 중력은 수동으로 속도에 곱해줘야한다.

​

            //CharacterController : SimpleMove()

            //- 인자는 float(방향 x 속도를 곱해서 넘겨주자)

            //- 지면방향 움직임만 설정하면 중력은 자동으로 계산된다.

​

            //controller.Move(moveDir * Time.deltaTime * moveSpeed);

            // 캐릭터에 중력 적용

            m_ChrController.SimpleMove(moveDir * moveSpeed);</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ unique_ptr]]></title>
            <link>https://velog.io/@m_jooong/C-uniqueptr</link>
            <guid>https://velog.io/@m_jooong/C-uniqueptr</guid>
            <pubDate>Mon, 08 May 2023 07:59:41 GMT</pubDate>
            <description><![CDATA[<pre><code>#include &lt;iostream&gt;

/** 문자열 관련 라이브러리*/
#include &lt;string&gt;
/** 스마트 포인터 관련 라이브러리*/
#include &lt;memory&gt;
#include &lt;vector&gt;

/** C++ 표준 라이브러리 사용합니다. */
using namespace std;

/* 정적 할당 테스트 Animal 클래스 정의*/
class Animal
{
public:
    Animal()
    {
        cout &lt;&lt; &quot;정적 할당으로 객체 생성한 생성자&quot; &lt;&lt; endl;
    }

    ~Animal()
    {
        cout &lt;&lt; &quot;정적 할당으로 객체 생성한 소멸자&quot; &lt;&lt; endl;
    }
};

/* new 연산자를 이용한 동적할당 테스트 Lion 클래스 정의*/
class Lion
{
public:
    Lion()
    {
        cout &lt;&lt; &quot;new 연산자로 동적 객체 생성한 생성자&quot; &lt;&lt; endl;

    }

    ~Lion()
    {
        cout &lt;&lt; &quot;new 연산자로 동적 객체 생성한 소멸자&quot; &lt;&lt; endl;

    }
};

/* 스마트 포인터로 동적 객체 생성하기 Tiger 클래스 정의*/
class Tiger
{
public:
    Tiger()
    {
        cout &lt;&lt; &quot;스마트 포인터로 동적으로 객체 생성한 생성자 &quot; &lt;&lt; endl;
    }

    ~Tiger()
    {
        cout &lt;&lt; &quot;스마트 포인터로 동적으로 객체 생성한 소멸자 &quot; &lt;&lt; endl;
    }

};

/* cat 클래스 정의하기.*/
class Cat
{
private:
    int* m_Food;
public:
    Cat()
    {
        /* 생성자에서 사이즈가 100000인 배열을 동적 할당으로 생성하기*/
        m_Food = new int[100000];
        cout &lt;&lt; &quot; Cat 생성자 &quot; &lt;&lt; endl;
    }

    ~Cat()
    {
        /* 소멸자는 객체가 메모리에서 해제될 때 할 일들을 지정해 준다.
        소멸자에서 사이즈가 100000인 배열을 delete 연산자로 객체 해제 해 주지 않으면
        4바이트 * 100000의 메모리 누수가 발생한다.
        */
        //delete m_Food;

        cout &lt;&lt; &quot; Cat 소멸자 &quot; &lt;&lt; endl;
    }
};

int main()
{
    /**
   구글 검색 없이 자연스럽게 써야 하는 문법적 요소
   1. 포인터 Pointer
   2. 참조자 Reference
   3. 상수 Constant
   4. 동적 할당 Dynamic Memory Allocation
   5. 스마트 포인터
       unique_ptr : 객체의 유일한 소유권을 가지는 스마트 포인터
       shared_ptr : 객체간의 공유가 가능한 스마트 포인터
       weak_ptr : shared_ptr의 순환 참조 문제를 해결한 약한 참조의 스마트 포인터
   */

   /**
   C++ 에서 객체 생성 방법

   1. 정적 할당 : 미리 할당을 합니다. 쓰지 않더라도 미리 할당을 합니다.
       비효율적인 부분이 발생할 수 있습니다. 하지만 내가 메모리 관리를 할 필요가 없습니다.

   2. 동적 할당 : 런타임에서 메모리 할당을 합니다. 효율적으로 필요한 부분에서 메모리 할당을 합니다.
       까다로운 부분이 있습니다. 하지만 효율을 위해서 동적으로 객체 생성을 해야 합니다.
       A. new 연산자로 객체 생성을 합니다. delete 연산자로 객체 해제를 해 주어야 합니다.
           만일 delete 연산자로 객체 해제를 해주지 않으면 메모리 누수가 발생합니다.
           계속 메모리에 쓰레기가 쌓여서 프로그램이 crash될 수도 있습니다.
           메모리 누수 : 내가 접근할 수 없는, 내가 지울 수 없는 쓰레기 객체들이 메모리에 계속 쌓입니다.
               나중에는 앱이나 게임이 강제로 종료될 수도 있습니다.
               이 부분 때문에 C++에서는 경험이 많이 필요했습니다.
       B. 2011년도에 스마트 포인터를 지원하면서 메모리 관리가 너무 편해졌습니다.
           내가 객체 해제를 해 줄 필요가 없습니다.
           메모리 누수 발생을 원천적으로 예방할 수 있습니다.
   */

   /* 정적 할당 테스트 Animal 클래스 정의*/
    Animal animal1;
    cout &lt;&lt; endl;

    /* new 연산자를 이용한 동적할당 테스트 Lion 클래스 정의*/
    Lion* lion1 = new Lion();
    cout &lt;&lt; endl;

    /** 더이상 접근할 필요가 없을 때는 delete 연산자로 메모리에서 객체 해제를 해주어야 합니다. */
    delete lion1;
    cout &lt;&lt; endl;

    /* 스마트 포인터로 동적 객체 생성하기 Tiger 클래스 정의*/
    unique_ptr&lt;Tiger&gt; uniquePtr1 = make_unique&lt;Tiger&gt;();
    cout &lt;&lt; endl;

    /* 
    delete 연산자 사용의 복잡성과 메모리 누수 예방을 위해 스마트 포인터가 생겼다.

    1. unique_Ptr : C++ 11 (2011년)에 추가 되었다 객체의 유일한 소유권을 가지는 스마트 포인터
    2. shared_Ptr : C++ 11 (2011년)에 추가 되었다 객체간의 공유가 가능한 스마트 포인터
    3. weak_ptr   : C++ 11 (2011년)에 추가 되었다 shared_ptr의 순환 참조 문제를 해결한
                    약한 참조의 스마트 포인터
    4. auto_ptr : C++ 17년에 없어졌음.

    C언어 malloc(말록, Memory Allocation)함수, free() 함수로 메모리 관리를 했다.
    C++ 에서는 new연산자 delete 연산자로 메모리 관리를 하지만 어렵다.
    메모리 누수 체크를 하는 많은 툴이 있지만 복잡하다

    스마트 포인터를 지원하면서 메모리 관리가 쉬워졌다.
    */

    /* 
    자원 관리 중요성

    메모리를 할당만 하고 해제를 하지않는다면 결국 메모리 부족으로 프로그램이 crash될 수 있다
    C++이후 나온 많은 언어들 대부분 가비지 컬렉션(자원 청소)를 지원한다.
    가비지 컬렉션ㅇ이 1초에 몇십번 호출되어서 메모리에 접근이 안되는 쓰레기 자원들을 정리한다.

    따라서 프로그래머들이 자원을 해제하는 일에 대해 신경쓰지 않아도 되는 장점이 있지만
    너무 의존하게 되면 게임이 느려질 수 있다. 코드 최적화도 중요하다.
    */


    /* cat 클래스 정의하기.*/
    /*
    생성자 함수에서 엄청 큰 사이즈의 큰 배열을 정의하고 있다.
    Cat()
    {
        m_Food = new int[100000];
        cout &lt;&lt; &quot; Cat 생성자 &quot; &lt;&lt; endl;
    }

    객체가 생성만 되고, 생성된 객체가 해제되지 않았다.
    메모리 누수가 발생하는데, 얼마만큼의 메모리 누수가 발생할까

    m_Food = new int[100000];
    int타입은 4바이트이다. 4바이트 * 100000 = 400000Byte

    Cat이라는 객체가 생성될 때마다 400000byte의 메모리 누수가 발생한다.

    heap 메모리 공간 어딘가에 Cat 객체가 남아있지만, 그 주소값을 가지고 있는 포인터는 메모리 상에
    남아있지 않다. Cat객체는 영원히 해제되지 않은채로 heap 메모리 공간에서 자리만 차지한다&#39;

    delete 연산자로 메모리에서 객체 해제해 주면 되지 않겠냐 하지만 프로그램의 크기가 커지면
    해제하는 위치가 복잡할 수 있다. 놓치기 쉽다.
    */

    Cat* cat1 = new Cat();
    cout &lt;&lt; endl;

    delete cat1;
    cout &lt;&lt; endl;

    /*
    C++ 에서 메모리 관리를 잘못했을 때 2가지 문제점이 발생할 수 있다.

    1. 메모리를 사용한 후에 해제하지 않는 경우. 메모리 누수가 발생한다.
    2. 이미 해제된 메모리를 다시 참조하는 경우. 이미 해제한 메모리는 nullptr이 된다.
        nullptr인 객체에 접근하면 에러가 발생한다
    */

    /* 이미 해제된 메모리를 다시 참조했을 때... */
    Cat* cat2 = new Cat();
    cout &lt;&lt; endl;

    /* 포인터 변수들은 같은 객체를 가리킬 수 있다.*/
    Cat* cat3 = cat2;
    cout &lt;&lt; endl;

    /* cat2객체가 동적으로 생성되었으니 메모리에서 객체 해제 해 준다.*/

    /*
    cat2와 cat3는 동시에 한 객체를 가리키고 있다.
    delete cat2를 통해서 객체를 소멸시켜 주었다.
    그런데 cat3가 이미 소멸된 객체를 다시 소멸시키려 하면 에러가 발생한다.
    이미 소멸된 객체를 다시 소멸시켜서 발생하는 버그를 double free버그라고 한다.
    이와 같은 문제가 발생하는 이유는 생성된 객체의 소유권이 명확하지 않기 때문이다.
    만약 우리가 어떤 포인터에 객체의 유일한 소유권을 부여해서 이 포인터 말고는 객체를 소멸시킬 수
    없다라고 한다면 같은 객체를 두번 소멸시켜 버리는 일은 발생하지 않을 것이다.

    unique_ptr : 객체의 유일한 소유권을 가지는 스마트 포인터
    */
    delete cat2;
    cout &lt;&lt; endl;

    /*
    cat3 객체도 동적생성되었으니 메모리에서 객체 해제를 해 준다 

    문법적으로는 문제가 없어보인다, 컴파일 에러도 없다.
    하지만 플레이하면 에러가 발생한다. 런타임 에러는 조심해야 한다.
    */
    //delete cat3;  // x
    cout &lt;&lt; endl;

    /* 
    위의 경우를 보면 cat2에 new Cat()으로 생성된 객체의 소유권을 보유한다면
    delete cat2는 가능하고
    delete cat3는 불가능하다.

    이제 unique_ptr로 객체 생성을 해 준다.
    */
    unique_ptr&lt;Cat&gt; uniquePtr2(new Cat());
    cout &lt;&lt; endl;

    /*
    unique_ptr들이 같은 객체를 가리키면 어떻게 되나..
    만약에 unique_ptr를 복사하려고 한다면?
    */
    unique_ptr&lt;Cat&gt; uniquePtr3(new Cat());
    cout &lt;&lt; endl;
    /* uniquePtr4가 uniquePtr3를 가리킬 수 없다.*/
    //unique_ptr&lt;Cat&gt; uniquePtr4 = uniquePtr3;    // x
    cout &lt;&lt; endl;

    /* 
    unique_ptr 소유권 이전하기에 대해 알아보기
    unique_ptr은 복사가 불가능 하지만 소유권을 이전할 수 있다.
    */

    /* get() 함수를 이용하면 실제 객체의 주소값을 반환해 준다.*/
    cout &lt;&lt; &quot;uniquePtr3 : &quot; &lt;&lt; uniquePtr3.get() &lt;&lt; endl;
    cout &lt;&lt; endl;

    /*
    uniquePtr3를 uniquePtr4로 강제 이동시켜 버린다. 소유권 이전.
    uniquePtr4는 new Cat()으로 생성된 객체의 소유권을 가지게 되고, uniquePtr3는 아무것도 가리키지 않는다.
    */
    unique_ptr&lt;Cat&gt; uniquePtr4 = move(uniquePtr3);

    cout &lt;&lt; &quot;uniquePtr3 : &quot; &lt;&lt; uniquePtr3.get() &lt;&lt; endl;
    cout &lt;&lt; &quot;uniquePtr4 : &quot; &lt;&lt; uniquePtr4.get() &lt;&lt; endl;
    cout &lt;&lt; endl;

    /*
    unique_ptr을 사용하면서 주의 사항

    소유권이 이전된 unique_ptr을 댕글링 포인터(dangling pointer)라고 한다.
    이를 재참조할 시에 런타임 에러가 발생한다.
    따라서 소유권 이전은 댕글링 포인터를 절대 다시 참조하지 않겠다는 확신하에 이동해야 한다.

    소유권을 이동 시킨 후에 원래의 unique_ptr에 접근하지 않도록 조심해야 한다.
    */

    /*
    unique_ptr 안전하게 생성하기
    C++ 14부터 unique_ptr객체를 안전하게 생성할 수 있는 make_unique() 함수를 제공한다.
    */
    unique_ptr&lt;Cat&gt; uniquePtr5 = make_unique&lt;Cat&gt;();
    cout &lt;&lt; endl;

    /*
    unique_ptr를 요소로 가지믄 벡터 컨테이너에 대해 알아보기
    */
    /*
    빌드하면 에러가 생긴다. 
    삭제된 unique_ptr의 복사 생성자에 접근하였기 때문이다.
    기본적으로 vector의 push_back 함수는 전달된 매개 변수를 복사해서 전달되기 때문에
    이와 같은 문제가 발생한다.
    unique_ptr은 소유권이 유일해야 한다. 매개변수에 복사해서 전달하면 유일하지 않는다.
    unique_ptr은 move()함수를 통해서 소유권을 이전해서 vector 컨테이너에 전달해 주어야 한다,
    */
    vector&lt;unique_ptr&lt;Cat&gt;&gt; vector5;
    unique_ptr&lt;Cat&gt; uniquePtr6(new Cat());
    cout &lt;&lt; endl;

    //vector5.push_back(uniquePtr6);    //x
    cout &lt;&lt; endl;
    /* 이를 방지하기 위해서는 명시적으로 uniquePtr6를ㄹ 벡터 컨테이너 안으로 이동시켜주어야한다.*/
    vector5.push_back(move(uniquePtr6));
    cout &lt;&lt; endl;

    /* 
    emplace_back() 함수 : emplace_back() 함수를 이용하면 vector 컨테이너에 unique_ptr 객체를
    직접 생성하면서 넣을 수 있다. 불필요한 과정을 생략 가능하다.
    */
    vector&lt;unique_ptr&lt;Cat&gt;&gt; vector6;
    vector6.push_back(unique_ptr&lt;Cat&gt;(new Cat()));
    cout &lt;&lt; endl;

    /*
    emplace_back() 함수는 전달된 매개변수를 직접unique_ptr&lt;Cat&gt;의 생성자에 전달해서
    vector 컨테이너의 맨 뒤에 unique_ptr&lt;Cat&gt; 객체를 생성한다.
    따라서 불필요한 이동 연산이 필요없게 된다.
    */
    vector6.emplace_back(new Cat());
    cout &lt;&lt; endl;

}
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ OperatorOverLoading]]></title>
            <link>https://velog.io/@m_jooong/C-OperatorOverLoading</link>
            <guid>https://velog.io/@m_jooong/C-OperatorOverLoading</guid>
            <pubDate>Wed, 03 May 2023 07:26:08 GMT</pubDate>
            <description><![CDATA[<pre><code>#include &lt;iostream&gt;

/** 문자열 관련 라이브러리*/
#include &lt;string&gt;

/** C++ 표준 라이브러리 사용합니다. */
using namespace std;

/**
1. 산술 연산자 오버로딩에 대해서 알아 봅니다.
테스트를 위해서 Point1이라는 이름의 클래스를 정의해 줍니다.
*/
class Point1
{
private:
    int m_xPosition;
    int m_yPosition;
public:
    /**
    생성자의 목적은 객체를 생성하면서 멤버 변수의 초기화를 담당합니다.
    : 콜론 뒤가 초기화 리스트로 멤버 변수를 초기화 하는 과정입니다.
    */
    Point1(int x, int y) : m_xPosition(x), m_yPosition(y) {}
    /** ShowPosition이라는 이름의 함수의 원형을 선언합니다. */
    void ShowPosition();
};

/** ShowPosition이라는 이름의 함수를 정의합니다. */
void Point1::ShowPosition()
{
    cout &lt;&lt; &quot;m_xPosition : &quot; &lt;&lt; m_xPosition &lt;&lt; &quot;, m_yPosition : &quot; &lt;&lt; m_yPosition &lt;&lt; endl;
}

/**
연산자 오버로딩을 사용해 봅니다.
테스트를 위해서 Point2라는 이름의 클래스를 정의해 줍니다.
*/
class Point2
{
private:
    int m_xPosition;
    int m_yPosition;
public:
    /**
    생성자 함수를 정의합니다.
    : 콜론 뒤가 초기화 리스트로 객체를 생성하면서 멤버 변수의 값을 초기화 합니다.
    */
    Point2(int x, int y) : m_xPosition(x), m_yPosition(y) {}
    /** ShowPosition이라는 이름의 함수의 원형을 선언합니다. */
    void ShowPosition();
    /** Add라는 이름의 함수의 원형을 선언합니다. */
    Point2 Add(Point2&amp; position);
    /** 덧셈 연산자 오버로딩 함수의 원형을 선언합니다. */
    Point2 operator+(Point2&amp; position);
};

/** ShowPosition이라는 이름의 함수를 정의합니다. */
void Point2::ShowPosition()
{
    cout &lt;&lt; &quot;m_xPosition : &quot; &lt;&lt; m_xPosition &lt;&lt; &quot;, m_yPosition : &quot; &lt;&lt; m_yPosition &lt;&lt; endl;
}

/** Add라는 이름의 함수를 정의합니다. */
Point2 Point2::Add(Point2&amp; position)
{
    Point2 pt(m_xPosition + position.m_xPosition, m_yPosition + position.m_yPosition);
    return pt;
}

/** 덧셈 연산자 오버로딩 함수를 정의합니다. */
Point2 Point2::operator+(Point2&amp; position)
{
    Point2 pt(m_xPosition + position.m_xPosition, m_yPosition + position.m_yPosition);
    return pt;
}


/**
2. 비교 연산자 오버로딩 (==, !=)

테스트를 위해서 Point3라는 이름의 클래스를 정의해 줍니다.
*/
class Point3
{
private:
    int m_xPosition;
    int m_yPosition;
public:
    Point3(int x, int y) : m_xPosition(x), m_yPosition(y) {}
    /** ShowPosition이라는 이름의 함수의 원형을 선언합니다. */
    void ShowPosition();

    /** 더하기 함수의 원형을 선언합니다. */
    Point3 Add(Point3&amp; position);
    /** 같은지 함수의 원형을 선언합니다. */
    bool EqualTo(Point3&amp; position);
    /** 다른지 함수의 원형을 선언합니다. */
    bool NotEqualTo(Point3&amp; position);
    /** 더하기 연산자 오버로딩 함수의 원형을 선언합니다. */
    Point3 operator+(Point3&amp; position);
    /** 같은지 연산자 오버로딩 함수의 원형을 선언합니다. */
    bool operator==(Point3&amp; position);
    /** 다른지 연산자 오버로딩 함수의 원형을 선언합니다. */
    bool operator!=(Point3&amp; position);
};

/** ShowPosition이라는 이름의 함수를 정의합니다. */
void Point3::ShowPosition()
{
    cout &lt;&lt; &quot;m_xPosition : &quot; &lt;&lt; m_xPosition &lt;&lt; &quot;, m_yPosition : &quot; &lt;&lt; m_yPosition &lt;&lt; endl;
}

/** 더하기 함수를 정의합니다. */
Point3 Point3::Add(Point3&amp; position)
{
    Point3 pt(m_xPosition + position.m_xPosition, m_yPosition + position.m_yPosition);
    return pt;
}

/** 같은지 함수를 정의합니다. */
bool Point3::EqualTo(Point3&amp; position)
{
    return ((m_xPosition == position.m_xPosition) &amp;&amp; (m_yPosition == position.m_yPosition));
}

/** 다른지 함수를 정의합니다. */
bool Point3::NotEqualTo(Point3&amp; position)
{
    /** this 포인터가 가리키는 값은 Point3객체의 멤버 변수와 멤버 함수입니다. */
    return !(*this == position);
}

/** 더하기 연산자 오버로딩 함수를 정의합니다. */
Point3 Point3::operator+(Point3&amp; position)
{
    Point3 pt(m_xPosition + position.m_xPosition, m_yPosition + position.m_yPosition);
    return pt;
}

/** 같은지 연산자 오버로딩 함수를 정의합니다. */
bool Point3::operator==(Point3&amp; position)
{
    return ((m_xPosition == position.m_xPosition) &amp;&amp; (m_yPosition == position.m_yPosition));
}

/** 다른지 연산자 오버로딩 함수를 정의합니다. */
bool Point3::operator!=(Point3&amp; position)
{
    return !(*this == position);
}

/**
3. 증감 연산자 오버로딩

테스트를 위해서 Point4라는 이름의 클래스를 정의해 줍니다.
*/
class Point4
{
private:
    int m_xPosition;
    int m_yPosition;
public:
    Point4(int x, int y) : m_xPosition(x), m_yPosition(y) {}
    /** ShowPosition이라는 이름의 함수의 원형을 선언합니다. */
    void ShowPosition();

    /** Add라는 이름의 함수의 원형을 선언합니다. */
    Point4 Add(Point4&amp; position);
    /** Subtract라는 이름의 함수의 원형을 선언합니다. */
    Point4 Subtract(Point4&amp; position);
    /** Multiply라는 이름의 함수의 원형을 선언합니다. */
    Point4 Multiply(Point4&amp; position);
    /** Divide라는 이름의 함수의 원형을 선언합니다. */
    Point4 Divide(Point4&amp; position);
    /** Remainder라는 이름의 함수의 원형을 선언합니다. */
    Point4 Remainder(Point4&amp; position);
    /** EqualTo라는 이름의 함수의 원형을 선언합니다. */
    bool EqualTo(Point4&amp; pisiton);
    /** NotEqualTo라는 이름의 함수의 원형을 선언합니다. */
    bool NotEqualTo(Point4&amp; position);
    /** 전치 증가 함수의 원형을 선언합니다. */
    Point4 IncreaseFront(); // ++Point4
    /** 후치 증가 함수의 원형을 선언합니다. */
    Point4 IncreaseBack(int); // Point++
    /** 전치 감소 함수의 원형을 선언합니다. */
    Point4 DecreaseFront(); // --Point4
    /** 후치 감소 함수의 원형얼 선언합니다. */
    Point4 DecreaseBack(int); // Point4--

    /** 더하기 연산자 오버로딩 함수의 원형을 선언합니다. */
    Point4 operator+(Point4&amp; position);
    /** 빼기 연산자 오버로딩 함수의 원형을 선언합니다. */
    Point4 operator-(Point4&amp; position);
    /** 곱하기 연산자 오버로딩 함수의 원형을 선언합니다. */
    Point4 operator*(Point4&amp; position);
    /** 나누기 연산자 오버로딩 함수의 원형을 선언합니다. */
    Point4 operator/(Point4&amp; position);
    /** 나머지 연산자 오버로딩 함수의 원형을 선언합니다. */
    Point4 operator%(Point4&amp; position);
    /** 같은지 연산자 오버로딩 함수의 원형을 선언합니다. */
    bool operator==(Point4&amp; postion);
    /** 다른지 연산자 오버로딩 함수의 원형을 선언합니다.  */
    bool operator!=(Point4&amp; position);
    /** 전치 증가 연산자 오버로딩 함수의 원형을 선언합니다. */
    Point4 operator++(); // ++Point4
    /** 후치 증가 연산자 오버로딩 함수의 원형을 선언합니다. */
    Point4 operator++(int);  // Point4++
    /** 전치 감소 연산자 오버로딩 함수의 원형을 선언합니다. */
    Point4 operator--(); // --Point4
    /** 후치 감소 연산자 오버로딩 함수의 원형을 선언합니다. */
    Point4 operator--(int);  // Point4--
};

/** ShowPosition이라는 이름의 함수를 정의합니다. */
void Point4::ShowPosition()
{
    cout &lt;&lt; &quot;m_xPosition : &quot; &lt;&lt; m_xPosition &lt;&lt; &quot;, m_yPosition : &quot; &lt;&lt; m_yPosition &lt;&lt; endl;
}

/** Add라는 이름의 함수를 정의합니다. */
Point4 Point4::Add(Point4&amp; position)
{
    Point4 pt(m_xPosition + position.m_xPosition, m_yPosition + position.m_yPosition);
    return pt;
}

/** Subtract라는 이름의 함수를 정의합니다. */
Point4 Point4::Subtract(Point4&amp; position)
{
    Point4 pt(m_xPosition - position.m_xPosition, m_yPosition - position.m_yPosition);
    return pt;
}

/** Multiply라는 이름의 함수를 정의합니다. */
Point4 Point4::Multiply(Point4&amp; position)
{
    Point4 pt(m_xPosition * position.m_xPosition, m_yPosition * position.m_yPosition);
    return pt;
}

/** Divide라는 이름의 함수를 정의합니다. */
Point4 Point4::Divide(Point4&amp; position)
{
    Point4 pt(m_xPosition / position.m_xPosition, m_yPosition / position.m_yPosition);
    return pt;
}

/** Remainder라는 이름의 함수를 정의합니다. */
Point4 Point4::Remainder(Point4&amp; position)
{
    Point4 pt(m_xPosition % position.m_xPosition, m_yPosition % position.m_yPosition);
    return pt;
}

/** EqualTo라는 이름의 함수를 정의합니다. */
bool Point4::EqualTo(Point4&amp; pisiton)
{
    return ((m_xPosition == pisiton.m_xPosition) &amp;&amp; (m_yPosition == pisiton.m_yPosition));
}

/** NotEqualTo라는 이름의 함수를 정의합니다. */
bool Point4::NotEqualTo(Point4&amp; position)
{
    return !(*this == position);
}

/** 전치 증가 함수를 정의합니다. */
Point4 Point4::IncreaseFront()
{
    ++m_xPosition;
    ++m_yPosition;
    return *this;
}

/** 후치 증가 함수를 정의합니다. */
Point4 Point4::IncreaseBack(int)
{
    Point4 pt = *this;
    m_xPosition++;
    m_yPosition++;
    return pt;
}

/** 전치 감소 함수를 정의합니다. */
Point4 Point4::DecreaseFront()
{
    --m_xPosition;
    --m_yPosition;
    return *this;
}

/** 후치 감소 함수를 정의합니다. */
Point4 Point4::DecreaseBack(int)
{
    Point4 pt = *this;
    m_xPosition--;
    m_yPosition--;
    return pt;
}

/** 더하기 연산자 오버로딩 함수를 정의합니다. */
Point4 Point4::operator+(Point4&amp; position)
{
    Point4 pt(m_xPosition + position.m_xPosition, m_yPosition + position.m_yPosition);
    return pt;
}

/** 빼기 연산자 오버로딩 함수를 정의합니다. */
Point4 Point4::operator-(Point4&amp; position)
{
    Point4 pt(m_xPosition - position.m_xPosition, m_yPosition - position.m_yPosition);
    return pt;
}

/** 곱하기 연산자 오버로딩 함수를 정의합니다. */
Point4 Point4::operator*(Point4&amp; position)
{
    Point4 pt(m_xPosition * position.m_xPosition, m_yPosition * position.m_yPosition);
    return pt;
}

/** 나누기 연산자 오버로딩 함수를 정의합니다. */
Point4 Point4::operator/(Point4&amp; position)
{
    Point4 pt(m_xPosition / position.m_xPosition, m_yPosition / position.m_yPosition);
    return pt;
}

/** 나머지 연산자 오버로딩 함수를 정의합니다. */
Point4 Point4::operator%(Point4&amp; position)
{
    Point4 pt(m_xPosition % position.m_xPosition, m_yPosition % position.m_yPosition);
    return pt;
}

/** 같은지 연산자 오버로딩 함수를 정의합니다. */
bool Point4::operator==(Point4&amp; position)
{
    return ((m_xPosition == position.m_xPosition) &amp;&amp; (m_yPosition == position.m_yPosition));
}

/** 다른지 연산자 오버로딩 함수를 정의합니다. */
bool Point4::operator!=(Point4&amp; position)
{
    return !(*this == position);
}

/** 전치 증가 연산자 오버로딩 함수를 정의합니다. */
Point4 Point4::operator++()
{
    ++m_xPosition;
    ++m_yPosition;
    return *this;
}

/** 후치 증가 연산자 오버로딩 함수를 정의합니다. */
Point4 Point4::operator++(int)
{
    Point4 pt = *this;
    m_xPosition++;
    m_yPosition++;
    return pt;
}

/** 전치 감소 연산자 오버로딩 함수를 정의합니다. */
Point4 Point4::operator--()
{
    --m_xPosition;
    --m_yPosition;
    return *this;
}

/** 후치 감소 연산자 오버로딩 함수를 정의합니다. */
Point4 Point4::operator--(int)
{
    Point4 pt = *this;
    m_xPosition--;
    m_yPosition--;
    return pt;
}

/**
멤버 함수에 의한 오버로딩을 알아 보도록 합니다.
테스트를 위해서 Point5라는 이름의 클래스를 정의해 주도록 합니다.
*/
class Point5
{
private:
    int m_xPosition;
    int m_yPosition;
public:
    /**
    생성자 함수를 정의합니다.
    int x = 0, int y = 0 : 디폴트 매개 변수입니다.
    만일 매개 변수에 값을 주지 않을 경우 기본값으로 적용됩니다.
    */
    Point5(int x = 0, int y = 0) : m_xPosition(x), m_yPosition(y) {}
    /** ShowPosition 함수의 원형을 선언합니다. */
    void ShowPosition();

    /** 더하기 연산자 오버로딩 멤버 함수의 원형을 선언합니다. */
    Point5 operator+(const Point5&amp; position);
};

/** ShowPosition 함수를 정의합니다. */
void Point5::ShowPosition()
{
    cout &lt;&lt; &quot;m_xPosition : &quot; &lt;&lt; m_xPosition &lt;&lt; &quot;, m_yPosition : &quot; &lt;&lt; m_yPosition &lt;&lt; endl;
}

/** 더하기 연산자 오버로딩 멤버 함수를 정의합니다. */
Point5 Point5::operator+(const Point5&amp; position)
{
    Point5 pt(m_xPosition + position.m_xPosition, m_yPosition + position.m_yPosition);
    return pt;
}

/**
전역 함수에 의한 오버로딩에 대해서 알아 봅니다.

테스트를 위해서 Point6라는 이름의 클래스를 정의해 줍니다.
*/
class Point6
{
private:
    int m_xPosition;
    int m_yPosition;
public:
    /** 생성자 함수를 정의합니다. */
    Point6(int x = 0, int y = 0) : m_xPosition(x), m_yPosition(y) {}
    /** ShowPosition 함수의 원형을 선언합니다. */
    void ShowPosition();
    /**
    전역 함수를 friend 선언을 해주고 있습니다.
    friend 선언을 해 줌으로써 operator+ 함수를 Point6 객체의 private 멤버에 직접 접근이 가능합니다.
    friend 선언은 연산자 오버로딩에 주로 사용합니다.
    */
    friend Point6 operator+(const Point6&amp; p1, const Point6&amp; p2);

};

/** 전역 공간, main() 함수 밖입니다. 클래스 밖입니다. */
/**
ShowPosition 함수를 정의합니다.
소속이 정해져 있는 멤버 함수입니다.
*/
void Point6::ShowPosition()
{
    cout &lt;&lt; &quot;m_xPosition : &quot; &lt;&lt; m_xPosition &lt;&lt; &quot;, m_yPosition : &quot; &lt;&lt; m_yPosition &lt;&lt; endl;
}

/**
더하기 연산자 오버로딩 함수를 정의합니다.
따로 소속이 정해져 있지 않은 전역 함수입니다.
*/
Point6 operator+(const Point6&amp; p1, const Point6&amp; p2)
{
    /**
    멤버 함수에서는 private 접근 지정자 안에 멤버 변수에 접근이 가능합니다.
    전역 함수에서는 private 접근 지정자 안에 멤버 변수에 접근이 불가능합니다. 하지만 friend 선언을 해 주면
    전역 함수에서도 private 접근 지정자 안에 멤버 변수에 직접 접근이 가능합니다.
    */
    Point6 pt(p1.m_xPosition + p2.m_xPosition, p1.m_yPosition + p2.m_yPosition);
    return pt;
}


int main()
{
    /**
    연산자 오버로딩(Operator Overloading)이란?

    1. 함수 오버로딩 : 매개 변수의 개수나 타입이 틀리면 같은 이름의 함수 이름을
        정의할 수 있습니다.
    2. 연산자 오버로딩 : 하나의 연산자를 다른 기능도 사용할 수 있도록 사용자 정의를
        할 수 있습니다.
    3. 함수 템플릿

    다음과 같은 연산자 이외의 모든 연산자는 오버로딩이 가능합니다.
    :: 범위 지정 연산자
    . 멤버 참조 연산자
    * 멤버 포인터 연산자
    ? 삼항 연산자
    # 전처리기

    멤버 함수로만 오버로딩 가능한 연산자도 있습니다.
    = 대입 연산자
    () 함수 호출
    -&gt; 포인터 멤버 접근 연산자
    [] 배열 인덱스 연산자
    */

    /**
    연산자 오버로딩 규칙

    1. 기본 데이터 타입만을 다루는 연산자 오버로딩은 할 수 없습니다.
        피 연산자 중 하나는 반드시 사용자 정의 타입이어야 합니다.
        int + int는 오버로딩을 통해서 다른 결과를 낼 수가 없습니다.
    2. 비정적 클래스 멤버 함수 또는 전역 함수이어야 연산자 오버로딩이 가능합니다.
    3. 단항 연산자 또는 이항 연산자로 오버로딩 할 수 있습니다.
    4. 오버 로딩된 연산자는 디폴트 매개변수로 사용 불가능합니다.

    반환타입 operator오버로딩할 연산자(매개변수1, 매개변수2, ...) {}
    */

    /**
    연산자의 종류
    1. 산술 연산자(+, -, *, /, %)
    2. 비교 연산자(==, !=)
    3. 증감 연산자(++, --)
    */

    /**
    1. 산술 연산자 오버로딩에 대해서 알아 봅니다.
    테스트를 위해서 Point1이라는 이름의 클래스를 정의해 줍니다.
    */

    /** 문장을 추가해 줍니다. */
    Point1 a1(10, 20);
    Point1 b1(20, 20);
    a1.ShowPosition();
    b1.ShowPosition();

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
    오류가 나는 것을 볼 수 있습니다.

    직교 좌표계의 x, y 값의 점을 가지는 객체를 생성한다고 가정합니다.
    이 때 두 좌표의 값은 (x1, y1) + (x2, y2) = (x1 + x2, y1 + y2)가 되어야 합니다.
    객체간의 덧셈이 정의되어 있지 않으므로 에러가 발생합니다.
    연산자 오버로딩을 통해 Point1객체에 대해 좌표끼리 덧셈을 x좌표는 x좌표끼리
    y좌표는 y좌표끼리 더해서 Point1 객체를 반환하면 됩니다. 따라서
    a1 + b1 은 a1.operator+(b1)와 같은 함수 호출이 되어서 덧셈의 결과가 됩니다.
    */
    // Point1 c1 = a1 + b1; // (X)
    // c1.ShowPosition();

    /**
    연산자 오버로딩을 사용해 봅니다.
    테스트를 위해서 Point2라는 이름의 클래스를 정의해 줍니다.
    */

    /** 문장을 추가해 줍니다. */

    cout &lt;&lt; &quot;더하기 연산자 오버로딩&quot; &lt;&lt; endl;
    Point2 a2(10, 10);
    Point2 b2(20, 20);

    a2.ShowPosition();
    b2.ShowPosition();

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    Point2 c21 = a2.operator+(b2); // 더하기 연산자 오버로딩입니다. 
    Point2 c22 = a2 + b2; // operator+ 생략이 가능합니다. 더하기 연산자 오버로딩입니다. 

    c21.ShowPosition();
    c22.ShowPosition();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
    2. 비교 연산자 오버로딩 (==, !=)

    테스트를 위해서 Point3라는 이름의 클래스를 정의해 줍니다.
    */

    /** 문장을 추가해 줍니다. */
    Point3 a3(10, 10);
    Point3 b3(20, 20);

    a3.ShowPosition();
    b3.ShowPosition();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 같은지 연산자 오버로딩으로 비교합니다. */
    if (a3.operator==(b3))
    {
        cout &lt;&lt; &quot;a3와 b3는 같습니다. &quot; &lt;&lt; endl;
    } /** 다른지 연산자 오버로딩으로 비교합니다. */
    else if (a3.operator!=(b3))
    {
        cout &lt;&lt; &quot;a3와 b3는 다릅니다. &quot; &lt;&lt; endl;
    }

    /** 같은지 연산자 오버로딩으로 비교합니다. */
    string message = (a3.operator==(b3) ? &quot;a3와 b3는 같습니다. &quot; : &quot;a3와 b3는 다릅니다. &quot;);
    cout &lt;&lt; &quot;message : &quot; &lt;&lt; message &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
    3. 증감 연산자 오버로딩

    테스트를 위해서 Point4라는 이름의 클래스를 정의해 줍니다.
    */

    /** 문장을 추가해 줍니다. */
    Point4 a4(10, 10);
    Point4 b4(20, 20);

    a4.ShowPosition();
    b4.ShowPosition();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;더하기 연산자 오버로딩&quot; &lt;&lt; endl;
    Point4 c41 = a4 + b4;
    c41.ShowPosition();

    Point4 c42 = a4.operator*(b4);
    c42.ShowPosition();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;빼기 연산자 오버로딩&quot; &lt;&lt; endl;
    Point4 c43 = a4 - b4;
    c43.ShowPosition();

    Point4 c44 = a4.operator-(b4);
    c44.ShowPosition();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;곱하기 연산자 오버로딩&quot; &lt;&lt; endl;
    Point4 c45 = a4 * b4;
    c45.ShowPosition();

    Point4 c46 = a4.operator*(b4);
    c46.ShowPosition();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;나누기 연산자 오버로딩&quot; &lt;&lt; endl;
    Point4 c47 = a4 / b4;
    c47.ShowPosition();

    Point4 c48 = a4.operator/(b4);
    c48.ShowPosition();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;나머지 연산자 오버로딩&quot; &lt;&lt; endl;
    Point4 c49 = a4 % b4;
    c49.ShowPosition();

    Point4 c50 = a4.operator%(b4);
    c50.ShowPosition();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;증가 연산자 오버로딩&quot; &lt;&lt; endl;
    ++a4;
    a4.ShowPosition();

    a4.operator++();
    a4.ShowPosition();

    a4++;
    a4.ShowPosition();

    a4.operator++(0);
    a4.ShowPosition();

    /**
    멤버 함수에 의한 오버로딩을 알아 보도록 합니다.
    테스트를 위해서 Point5라는 이름의 클래스를 정의해 주도록 합니다.
    */

    /** 문장을 추가해 줍니다. */
    Point5 a5(1, 2);
    Point5 b5(2, 1);


    /**
    a5 _ b5는 어떤 의미를 갖는지 알아 봅니다.
    여기서 a5 + b5는 객체이므로 기본적으로 덧셈 연산이 불가능합니다.
    operator 라는 키워드를 붙여서 a5와 b5를 이용해서 operator+ 라는 함수를 호출하게 됩니다.

    a5 + b5;는
    a5.operator+(b5); 로 이해하면 됩니다.
    */
    cout &lt;&lt; &quot;멤버 함수 더하기 연산자 오버로딩&quot; &lt;&lt; endl;
    Point5 c51 = a5 + b5;
    c51.ShowPosition();

    Point5 c52 = a5.operator+(b5);
    c52.ShowPosition();

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
    전역 함수에 의한 오버로딩에 대해서 알아 봅니다.

    테스트를 위해서 Point6라는 이름의 클래스를 정의해 줍니다.
    */

    /** 문장을 추가해 줍니다. */
    Point6 a6(1, 2);
    Point6 b6(2, 1);

    cout &lt;&lt; &quot;전역 함수 더하기 연산자 오버로딩&quot; &lt;&lt; endl;
    Point6 c61 = a6 + b6;
    c61.ShowPosition();

    Point6 c62 = operator+(a6, b6);
    c62.ShowPosition();
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[FadeManager]]></title>
            <link>https://velog.io/@m_jooong/Fade-manager</link>
            <guid>https://velog.io/@m_jooong/Fade-manager</guid>
            <pubDate>Thu, 27 Apr 2023 06:15:42 GMT</pubDate>
            <description><![CDATA[<p>//---------------------- Fade_Mgr.cs</p>
<p>using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;</p>
<p>public class Fade_Mgr : MonoBehaviour
{
    public bool IsFadeOut = false; //나갈때 
    public bool IsFadeIn  = false;</p>
<pre><code>//--- Fade In Out 관련 변수들...
Image m_FadeImg = null;
float AniDuring = 0.8f;     //페이드아웃 연출 시간 설정
bool  m_StartFade = false;
float m_CacTime = 0.0f;
float m_AddTimer = 0.0f;
Color m_Color;

float m_StVal = 1.0f;
float m_EndVal = 0.0f;

string m_SceneName = &quot;&quot;;    //이동할 씬 이름 저장용 변수
//--- Fade In Out 관련 변수들...

public static Fade_Mgr Inst = null;

void Awake()
{
    Inst = this;    
}

// Start is called before the first frame update
void Start()
{
    GameObject a_Canvas = GameObject.Find(&quot;Canvas&quot;);
    if(a_Canvas != null)
    {
        //매개변수 true의 의미는 Active가 껴져 있는 게임오브젝트도 모두 가져오라는 뜻
        Image[] a_ImgList = a_Canvas.transform.GetComponentsInChildren&lt;Image&gt;(true);
        for(int ii = 0; ii &lt; a_ImgList.Length; ii++)
        {
            if(a_ImgList[ii].gameObject.name == &quot;FadePanel&quot;)
            {
                m_FadeImg = a_ImgList[ii];
                break;
            }
        }

    } //if (a_Canvas != null)

    //--- Fade In 초기화
    if(m_FadeImg != null &amp;&amp; IsFadeIn == true)
    {
        m_StVal = 1.0f;
        m_EndVal = 0.0f;
        m_FadeImg.color = new Color32(0, 0, 0, 255);
        m_FadeImg.gameObject.SetActive(true);
        m_StartFade = true;
    }
    //--- Fade In 초기화

}//void Start()

// Update is called once per frame
void Update()
{
    if (m_FadeImg == null)
        return;

    FadeUpdate();
}

void FadeUpdate()
{
    if (m_StartFade == false)
        return;

    if(m_CacTime &lt; 1.0f)
    {
        m_AddTimer += Time.deltaTime;
        m_CacTime = m_AddTimer / AniDuring;
        m_Color = m_FadeImg.color;
        m_Color.a = Mathf.Lerp(m_StVal, m_EndVal, m_CacTime);
        m_FadeImg.color = m_Color;

        if(1.0f &lt;= m_CacTime)
        {
            if (m_StVal == 1.0f &amp;&amp; m_EndVal == 0.0f) //들어올 때 
            {
                m_Color.a = 0.0f;
                m_FadeImg.color = m_Color;
                m_FadeImg.gameObject.SetActive(false);
                m_StartFade = false;
            }
            else if (m_StVal == 0.0f &amp;&amp; m_EndVal == 1.0f) //나갈 때
            {
                SceneManager.LoadScene(m_SceneName);
            }
        }//if(1.0f &lt;= m_CacTime)

    }//if(m_CacTime &lt; 1.0f)
}//void FadeUpdate()

public void SceneOut(string a_ScName)
{
    if (m_FadeImg == null)
        return;

    m_SceneName = a_ScName;

    m_CacTime = 0.0f;
    m_AddTimer = 0.0f;
    m_StVal = 0.0f;
    m_EndVal = 1.0f;
    m_FadeImg.color = new Color32(0, 0, 0, 0);
    m_FadeImg.gameObject.SetActive(true);
    m_StartFade = true;
}</code></pre><p>}</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C++ ArrayAndPointer]]></title>
            <link>https://velog.io/@m_jooong/C-ArrayAndPointer</link>
            <guid>https://velog.io/@m_jooong/C-ArrayAndPointer</guid>
            <pubDate>Wed, 26 Apr 2023 08:28:51 GMT</pubDate>
            <description><![CDATA[<p><strong>1. 배열과 포인터</strong></p>
<pre><code>
#include &lt;iostream&gt;

/** 문자열 관련 라이브러리*/
#include &lt;string&gt;
/** 배열의 사이즈를 알기 위한 라이브러리*/
#include &lt;array&gt;

/** C++ 표준 라이브러리 사용합니다. */
using namespace std;

int main()
{
    /**
   1. 배열과 포인터
   2. 배열포인터
   3. 포인터배열
   */

   /** 1. 배열과 포인터*/
    int intValue1 = 10;
    /** 포인터 변수를 선언하고 초기화를 합니다. */
    int* intPtr1 = &amp;intValue1;

    cout &lt;&lt; &quot;intPtr1 : &quot; &lt;&lt; *intPtr1 &lt;&lt; &quot;, intPtr1 address : &quot; &lt;&lt; intPtr1 &lt;&lt; endl;

    *intPtr1 = 20;

    cout &lt;&lt; &quot;intPtr1 : &quot; &lt;&lt; *intPtr1 &lt;&lt; &quot;, intPtr1 address : &quot; &lt;&lt; intPtr1 &lt;&lt; endl;

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 주소값을 확인
    // int타입의 무게는 4바이트이다
    // 주소값은 16진수이다.

    // 포인터 변수에 1을 더한 값이 출력된 것을 볼 수 있다
    // intPtr1 + 1의 주소값 : intPtr1의 주소값에 4바이트를 더한 값
    cout &lt;&lt; &quot;intPtr1의 주소값 : &quot; &lt;&lt; intPtr1 &lt;&lt; endl;
    cout &lt;&lt; &quot;intPtr1 + 1의 주소값 : &quot; &lt;&lt; intPtr1 + 1 &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 배열을 선언하면 배열의 시작주소(배열의 0번째 인덱스 값의 주소입니다. )가 반환됩니다. */

    /** 문장을 추가해 줍니다. */
    int intArr1[] = { 1, 3, 5, 7, 9, 11, 13, 15, 17 };

    cout &lt;&lt; &quot;intArr1[0] value : &quot; &lt;&lt; *intArr1 &lt;&lt; endl;          // 0번째 인덱스의 값
    cout &lt;&lt; &quot;intArr1[0] value : &quot; &lt;&lt; intArr1[0] &lt;&lt; endl;        // 0번째 인덱스의 값

    cout &lt;&lt; &quot;intArr1[1] value : &quot; &lt;&lt; *(intArr1 + 1) &lt;&lt; endl;    // 1번째 인덱스의 값
    cout &lt;&lt; &quot;intArr1[1] value : &quot; &lt;&lt; intArr1[1] &lt;&lt; endl;        // 1번째 인덱스의 값

    cout &lt;&lt; &quot;intArr1[0] address : &quot; &lt;&lt; intArr1 &lt;&lt; endl;         // 0번째 인덱스의 주소값
    cout &lt;&lt; &quot;intArr1[0] address : &quot; &lt;&lt; &amp;intArr1[0] &lt;&lt; endl;     // 0번째 인덱스의 주소값

    cout &lt;&lt; &quot;intArr1[1] address : &quot; &lt;&lt; intArr1 + 1 &lt;&lt; endl;     // 1번째 인덱스의 주소값
    cout &lt;&lt; &quot;intArr1[1] address : &quot; &lt;&lt; &amp;intArr1[1] &lt;&lt; endl;     // 1번째 인덱스의 주소값

    /** 다음과 같은 표현도 가능합니다. */
    cout &lt;&lt; &quot;intArr1[1] address : &quot; &lt;&lt; &amp;intArr1[0] + 1 &lt;&lt; endl;

    cout &lt;&lt; &quot;&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;&quot; &lt;&lt; endl;

    /**
    반복문으로 주소값을 출력해 봅니다.
    문장을 추가해 줍니다.
    */

    /** foreach문에서 인덱스를 사용해 봅니다. */

    for (int i : intArr1)
    {
        cout &lt;&lt; &quot;intArr1[&quot; &lt;&lt; i &lt;&lt; &quot;] address : &quot; &lt;&lt; &amp;intArr1[i] &lt;&lt; endl; // 잘못된 값입니다. 
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    int index = 0;

    for (int i : intArr1)
    {
        cout &lt;&lt; &quot;intArr1[&quot; &lt;&lt; index &lt;&lt; &quot;] address : &quot; &lt;&lt; &amp;intArr1[index] &lt;&lt; endl;
        index++;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    for (int i = 0; i &lt; size(intArr1); i++)
    {
        cout &lt;&lt; &quot;intArr1[&quot; &lt;&lt; i &lt;&lt; &quot;] address : &quot; &lt;&lt; &amp;intArr1[i] &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    char charValue2 = &#39;L&#39;;
    int intValue2 = 1024;
    double doubleValue2 = 3.14;

    /** 포인터 변수의 사이즈는 4바이트 입니다. 확인해 봅니다. */
    cout &lt;&lt; &quot;charValue2 size : &quot; &lt;&lt; sizeof(charValue2) &lt;&lt; endl;
    cout &lt;&lt; &quot;charValue2 ptr size : &quot; &lt;&lt; sizeof(&amp;charValue2) &lt;&lt; endl;

    cout &lt;&lt; &quot;intValue2 size : &quot; &lt;&lt; sizeof(intValue2) &lt;&lt; endl;
    cout &lt;&lt; &quot;intValue2 ptr size : &quot; &lt;&lt; sizeof(&amp;intValue2) &lt;&lt; endl;

    cout &lt;&lt; &quot;doubleValue2 size : &quot; &lt;&lt; sizeof(doubleValue2) &lt;&lt; endl;
    cout &lt;&lt; &quot;doubleValue2 ptr size : &quot; &lt;&lt; sizeof(&amp;doubleValue2) &lt;&lt; endl;

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 배열의 요소를 출력해 봅니다. */
    int intArr2[9] = { 1, 2, 3, 4,5, 6, 7, 8, 9 };

    for (int i = 0; i &lt; size(intArr2); i++)
    {
        cout &lt;&lt; intArr2[i] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    for (int i = 0; i &lt; size(intArr2); i++)
    {
        cout &lt;&lt; *(intArr2 + i) &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    for (int* ptr = intArr2; ptr &lt; intArr2 + size(intArr2); ptr++)
    {
        cout &lt;&lt; *ptr &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 배열의 사이즈를 알아보도록 합니다. */
    cout &lt;&lt; &quot;array size : &quot; &lt;&lt; sizeof intArr2 / sizeof intArr2[0] &lt;&lt; endl;      // array size : 9

    cout &lt;&lt; &quot;array size : &quot; &lt;&lt; size(intArr2) &lt;&lt; endl;                           // array size : 9

    cout &lt;&lt; &quot;array size : &quot; &lt;&lt; sizeof(intArr2) / sizeof(intArr2[0]) &lt;&lt; endl;    // array size : 9

}
</code></pre><p><strong>2. 배열포인터</strong></p>
<pre><code>#include &lt;iostream&gt;

/** 문자열 관련 라이브러리*/
#include &lt;string&gt;
/** 배열의 사이즈를 알아오기 위한 라이브러리*/
#include &lt;array&gt;

/** C++ 표준 라이브러리 사용합니다. */
using namespace std;


int main()
{
    /**
    1. 배열과 포인터
    2. 배열포인터
    3. 포인터배열
    */

    /** 2. 배열포인터*/
    int intArr1[9] = { 1, 2,3, 4, 5, 6, 7, 8, 9 };
    int* intPtr1 = intArr1;

    for (int i = 0; i &lt; size(intArr1); i++)
    {
        cout &lt;&lt; *(intPtr1 + i) &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    for (int i = 0; i &lt; size(intArr1); i++)
    {
        cout &lt;&lt; intPtr1[i] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 3번째 문장이 헷갈립니다. 다음과 같이 이해하면 된다
    // intArr1[i] =&gt; *(intArr1 + i) =&gt; *(intPtr1 + i) =&gt; *(i + intPtr1) =&gt; i[intPtr1]
    for (int i = 0; i &lt; size(intArr1); i++)
    {
        cout &lt;&lt; i[intPtr1] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
    포인터와 배열의 관계에 대해서 정리하기.
    */
    intPtr1 = &amp;intArr1[0];
    cout &lt;&lt; &quot;intPtr1 : &quot; &lt;&lt; &amp;intArr1[0] &lt;&lt; endl;        //intPtr1 : 012FF718

    intPtr1 = &amp;intPtr1[0];
    cout &lt;&lt; &quot;intPtr1 : &quot; &lt;&lt; &amp;intPtr1[0] &lt;&lt; endl;        //intPtr1 : 012FF718

    *intPtr1 = intArr1[0];
    cout &lt;&lt; &quot;*intPtr1 : &quot; &lt;&lt; intArr1[0] &lt;&lt; endl;        //*intPtr1 : 1

    *intPtr1 = intPtr1[0];
    cout &lt;&lt; &quot;*intPtr1 : &quot; &lt;&lt; intPtr1[0] &lt;&lt; endl;        //*intPtr1 : 1

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /* 그러면 intPtr1 +1 의 값은?*/
    cout &lt;&lt; &quot;intPtr1 : &quot; &lt;&lt; intPtr1 &lt;&lt; endl;
    /** intPtr1 포인터 변수에 sizeof(*intPtr1)을 더한 주소값입니다. */
    cout &lt;&lt; &quot;intPtr1 + 1 : &quot; &lt;&lt; intPtr1 + 1 &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /*반복문으로 주소값 출력하기*/
    for (int i = 0; i&lt; size(intArr1); i++)
    {
        cout &lt;&lt; &quot;address : &quot; &lt;&lt; &amp;intArr1[i] &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /* 배열이 아닌 포인터 주소로 알아보니 에러 발생*/
    // for(int i = 0; i &lt; size(intPtr1); i++)
    // {

    // }

    /** double 타입으로 테스트를 해 봅니다.*/
    double doubleValue1[5] = { 3.14, 3.14, 3.14, 3.14, 3.14 };

    for (int i = 0; i &lt; size(doubleValue1); i++)
    {
        cout &lt;&lt; &quot;double address : &quot; &lt;&lt; &amp;doubleValue1[i] &lt;&lt; endl;
    }

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;size of double : &quot; &lt;&lt; sizeof(doubleValue1[0]) &lt;&lt; endl;

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** string 타입으로 테스트를 해 보도록 합니다.*/
    string stringValue1[] = { &quot;Jane&quot;, &quot;Tom&quot;, &quot;James&quot;, &quot;Emma&quot;, &quot;Smith&quot; };

    for (int i = 0; i &lt; size(stringValue1); i++)
    {
        cout &lt;&lt; &quot;string address : &quot; &lt;&lt; &amp;stringValue1[i] &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;size of string : &quot; &lt;&lt; sizeof(stringValue1[0]) &lt;&lt; endl;

    cout &lt;&lt; &quot;size of string address : &quot; &lt;&lt; sizeof(&amp;stringValue1[0]) &lt;&lt; endl;

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
    배열포인터에 대해서 알아 봅니다.
    배열포인터는 배열 자체를 가리키는 포인터 입니다.
    */
    int intArr3[3] = { 1, 2, 3 };
    /** 사이즈가 3인 int타입의 배열을 가리키는 포인터를 선언합니다. */
    int(*arrPtr3)[3];

    arrPtr3 = &amp;intArr3;

    /** 반복문으로 값 출력하기 */
    for (int i = 0; i &lt; size(intArr3); i++)
    {
        /**
        배열포인터가 가리키는 값은 배열입니다.
        (arrPtr3) : 배열포인터입니다.
        *(arrPtr3) : 배열포인터가 가리키는 값은 배열입니다.
        (*arrPtr3)[i] : 배열에 인덱스로 접근합니다.
        */
        cout &lt;&lt; &quot;*(arrPtr3)[&quot; &lt;&lt; i &lt;&lt; &quot;] : &quot; &lt;&lt; (*arrPtr3)[i] &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 문장 추가
    int intArr4[5] = { 1, 2, 3, 4, 5 };
    /** int타입의 요소를 5개 가지고 있는 배열을 가리키는 배열포인터를 선언합니다. */
    int(*arrPtr4)[5];

    arrPtr4 = &amp;intArr4;

    cout &lt;&lt; &quot;size of intArr4 : &quot; &lt;&lt; sizeof(intArr4) &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    for (int i = 0; i &lt; size(intArr4); i++)
    {
        cout &lt;&lt; &quot;intArr4[&quot; &lt;&lt; i &lt;&lt; &quot;] 주소값 : &quot; &lt;&lt; *arrPtr4 + i &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    for (int i = 0; i &lt; size(intArr4); i++)
    {
        cout &lt;&lt; &quot;intArr4[&quot; &lt;&lt; i &lt;&lt; &quot;] 값 : &quot; &lt;&lt; (*arrPtr4)[i] &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;
}</code></pre><p><strong>3. 포인터배열</strong></p>
<pre><code>#include &lt;iostream&gt;

/** 문자열 관련 라이브러리*/
#include &lt;string&gt;
/** 배열의 사이즈를 알기 위한 라이브러리*/
#include &lt;array&gt;

/** C++ 표준 라이브러리 사용합니다. */
using namespace std;

int main()
{
    /**
    1. 배열과 포인터
    2. 배열포인터
    3. 포인터배열

    포인터배열을 자세하게 알기 위해서는 이중 for문, 2차원 배열의 지식이 필요합니다.
    */

    /** 3. 포인터배열*/

    // 구구단 
    for (int i = 2; i &lt;= 9; i++)
    {
        for(int j = 1; j &lt;=9; j++)
        {
            cout &lt;&lt; i &lt;&lt; &quot; * &quot; &lt;&lt; j &lt;&lt; &quot; = &quot; &lt;&lt; i * j &lt;&lt; endl;
        }
        cout &lt;&lt; endl;

    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
    Row : 행, Column : 열

    세로 크기(행)가 3이고 가로 크기(열)이 4인 int타입의 2차원 배열을 선언합니다.
    */
    int numArr[3][4] =
    {
        {11, 22, 33, 44},
        {55, 66, 77, 88},
        {99, 110, 121, 132}
    };

    // 11 : 세로 인덱스 0, 가로 인덱스 0인 요소 출력
    cout &lt;&lt; &quot;numArr[0][0] : &quot; &lt;&lt; numArr[0][0] &lt;&lt; endl;
    // 77 : 세로 인덱스 1, 가로 인덱스 2인 요소 출력
    cout &lt;&lt; &quot;numArr[1][2] : &quot; &lt;&lt; numArr[1][2] &lt;&lt; endl;
    // 99 : 세로 인덱스 2, 가로 인덱스 0인 요소 출력
    cout &lt;&lt; &quot;numArr[2][0] : &quot; &lt;&lt; numArr[2][0] &lt;&lt; endl;
    // 132 : 세로 인덱스 2, 가로 인덱스 2인 요소 출력
    cout &lt;&lt; &quot;numArr[2][3] : &quot; &lt;&lt; numArr[2][3] &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /* 
    행을 구하는 공식
    현재 2차원 배열의 행( 세로 크기 )의 사이즈는 3이다
    2차원 배열의 세로 크기를 구할 때는
    배열이 차지하는 전체 공간을 가로 한 줄의 크기로 나눠 준다.
    */
    int row = sizeof(numArr) / sizeof(numArr[0]);
    cout &lt;&lt; &quot;row : &quot; &lt;&lt; row &lt;&lt; endl;
    cout &lt;&lt; endl;

    /*
    열을 구하는 공식
    현재 2차원 배열의 열( 가로 크기 )의 사이즈는 4이다
    2차원 배열의 가로 크기를 구할 때는
    가로 한 줄의 크기를 요소의 크기로 나눠 준다
    */
    int col = sizeof(numArr[0]) / sizeof(int);
    cout &lt;&lt; &quot;col : &quot; &lt;&lt; col &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
    반복문으로 2차원 배열의 요소들을 출력하기.
    세로 크기와 가로 크기를 이미 구해 놓았다.
    반복문으로 세로부터 반복한 뒤, 가로를 반복하면서 2차원 배열의 요소를 출력한다.
    */

    // 2차원 배열의 세로 크기만큼 반복
    for (int i = 0; i &lt; row; i++)
    {
        // 2차원 배열의 가로 크기만큼 반복
        for (int j = 0; j &lt; col; j++)
        {
            // 반복문의 지역변수 i와 증감문으로 1씩 증가하므로 
            // 2차원 배열의 세로 인덱스에는 i의 값을
            // 2차원 배열의 가로 인덱스에는 j의 값을 넣으면
            // 배열의 요소를 순서대로 접근할 수 있다.
            cout &lt;&lt; numArr[i][j] &lt;&lt; &quot; &quot;;
        }
        // 가로 요소를 출력한 뒤에 다음 줄로 넘어감
        cout &lt;&lt; endl;

    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 포인터배열은 배열 하나가 아닌 여러개의 배열을 한번에 처리할 수 있는 엄청난 효율이 있다. */

    /**
    2차원 배열의 요소들을 역순으로 출력하기.
    이미 세로 사이즈(행), 가로 사이즈(열)은 미리 구해 놓았다.
    반복문의 초기값에 배열의 세로 크기와 가로 크기를 바로 넣어 버리면
    처음부터 배열의 인덱스를 벗어난 상태가 된다.
    배열의 인덱스는 0부터 시작하기 때문이다.
    따라서 마지막 요소의 인덱스는 요소의 개수에서 1을 빼준다.
    그리고 0까지 반복할 수 있도록 조건식을 i &gt;= 0와 같이 해 준다.
    */

    // 세로 크기 - 1 부터 역순으로 반복
    for (int i = row - 1; i &gt;= 0; i--)
    {
        // 가로 크기 - 1 부터 역순으로 반복
        for (int j = col - 1; j &gt;= 0; j--)
        {
            // 2차원 배열의 인덱스에 반복문의 변수 i, j를 지정
            cout &lt;&lt; numArr[i][j] &lt;&lt; &quot; &quot;;
        }
        //가로 요소를 출력한 뒤에 다음 줄로 넘어갑니다.
        cout &lt;&lt; endl;

    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 포인터배열 : 포인터들을 배열에 저장. */
    int num1 = 100;
    int num2 = 200;
    int num3 = 300;

    int intArr1[3] = { num1, num2, num3 };

    for (int i = 0; i &lt; size(intArr1); i++)
    {
        cout &lt;&lt; &quot;address : &quot; &lt;&lt; &amp;intArr1[i] &lt;&lt; &quot;, value : &quot; &lt;&lt; intArr1[i] &lt;&lt; endl;
    }

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /* 포인터배열은 틀리다.*/
    int* arr[3] = { &amp;num1, &amp;num2, &amp;num3 };

    for (int i = 0; i &lt; size(arr); i++)
    {
        cout &lt;&lt; &quot;address : &quot; &lt;&lt; arr[i] &lt;&lt; &quot;, value : &quot; &lt;&lt; *arr[i] &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
   1. 2차원 배열에 배열들의 요소들을 출력해 보았다.
   2. 정수값을 포인터배열에 저장해서 요소들을 출력해 보았다.
   3. 포인터배열의 장점은 하나가 아닌 여러개의 배열을 한번에 처리할 수 있는 장점이 있다.

    배열을 포인터배열에 저장해서 요소들을 출력하기.
   */

   /**
   2차원 배열에서는 세로 크기와 가로 크기가 동일했다.
   각각의 배열들의 사이즈가 클리더라도 포인터배열은 배열을 저장하는 것이고
   배열의 포인터를 저장하는 것이라 배열들의 사이즈가 틀리더라도 가능하다.
   */
    int intArr2[5] = { 1, 2, 3, 4, 5 };
    int intArr3[6] = { 10, 20, 30, 40, 50, 60 };
    int intArr4[7] = { 100, 200, 300, 400, 500, 600, 700 };

    /**
    포인터배열을 선언하고 각각의 주소값을 대입해 준다.
    배열의 이름은 배열의 시작주소(배열의 0번째 인덱스 값의 주소)이므로 배열이름으로
    주소값을 대입한 것과 동일하다.
    */
    int* ptrArr[3] = { intArr2, intArr3, intArr4 };

    /**
    세로 사이즈(행)를 구하기.
    세로 사이즈는 3이다.
    */
    int length = size(ptrArr);

    /**
    가로 사이즈(열)를 구하기.
    배열의 사이즈가 틀리니 가로 사이즈는 배열로 만들어 준다.
    가로 사이즈는 배열 {5, 6, 7} 이다.
    */
    int subLength[3] = { size(intArr2), size(intArr3), size(intArr4) };

    /** 포인터배열의 세로 사이즈만큼 반복. */
    for (int i = 0; i &lt; length; i++)
    {
        /**
        포인터배열의 가로 사이즈만큼 반복.
        가로 사이즈는 배열 크기가 모두 달라서 subLength배열에서 인덱스로 접근합니다.
        */
        for (int j = 0; j &lt; subLength[i]; j++)
        {
            /** 포인터 배열의 인덱스에 반복문의 i와 j를 지정합니다. */
            cout &lt;&lt; ptrArr[i][j] &lt;&lt; &quot; &quot;;
        }
        /** 가로 요소를 출력한 뒤에 다음 줄로 넘어갑니다. */
        cout &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 문자열로 된 배열을 포인터배열에 추가해 줍니다. */
    string names[5] = { &quot;Tom&quot;, &quot;John&quot;, &quot;Jane&quot;, &quot;Smith&quot;, &quot;James&quot; };
    string nations[3] = { &quot;Korea&quot;, &quot;Japan&quot;, &quot;China&quot; };
    string animals[6] = { &quot;Tiger&quot;, &quot;Lion&quot;, &quot;Dog&quot;, &quot;Cat&quot;, &quot;Ang&quot;, &quot;Pig&quot; };

    /**
    포인터배열에 각각의 주소값을 대입합니다.
    배열의 이름은 배열의 시작주소(배열의 0번째 인덱스 값의 주소)입니다.
    */
    string* ptrArr1[3] = { names, nations, animals };

    /** 세로 사이즈(행, Row)를 구합니다. */
    int strLength = size(ptrArr1);

    /**
    가로 사이즈(열, Column)를 구합니다.
    배열들의 사이즈들이 모두 틀려서 배열에서 가로 사이즈를 구합니다.
    */
    int strSubLength[3] = { size(names), size(nations), size(animals) };

    /** 포인터배열의 가로 사이즈만큼 반복합니다. */
    for (int i = 0; i &lt; strLength; i++)
    {
        /** 포인터배열의 세로 사이즈만큼 반복합니다. */
        for (int j = 0; j &lt; strSubLength[i]; j++)
        {
            /**
            반복문의 변수 i와 j는 증감문을 통해서 1씩 증가하므로 포인터배열의 세로 인덱스에는 i의 값을
            포인터배열의 가로 인덱스에는 j의 값을 넣으면 포인터배열의 요소를 순서대로 접근할 수 있습니다
            */
            cout &lt;&lt; ptrArr1[i][j] &lt;&lt; &quot; &quot;;
        }
        /** 가로 요소를 출력한 뒤에 다음 줄로 넘어값니다. */
        cout &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

}
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ DynamicAllocation]]></title>
            <link>https://velog.io/@m_jooong/C-DynamicAllocation</link>
            <guid>https://velog.io/@m_jooong/C-DynamicAllocation</guid>
            <pubDate>Wed, 26 Apr 2023 07:41:14 GMT</pubDate>
            <description><![CDATA[<pre><code>#include &lt;iostream&gt;

/** 문자열 관련 라이브러리*/
#include &lt;string&gt;

/** C++ 표준 라이브러리 사용합니다. */
using namespace std;

int main()
{
   /**
   C++ 문법에서 자연스럽게 써야 하는 문법적 요소
   1. 포인터      Pointer
   2. 참조자      Reference
   3. 상수       Constant
   4. 동적할당     Dynamic Memory Allocation
   5. 스마트 포인터 Smart Pointer
           unique_ptr : 객체의 유일한 소유권을 가지는 스마트 포인트
           shared_ptr : 객체간의 공유가 가능한 스마트 포인터
           weak_ptr   : shared_ptr의 순환참조 문제를 해결한 약한 참조의 스마트 포인터
   */

   /**
   Memory 영역은 다음과 같이 나뉘게 됩니다.

   Code : 실행한 프로그램의 코드가 저장됩니다.
   Data : 전역변수(Global Variable), 정적변수(Static Variable)가 저장되면
           프로그램 종료 시까지 사라지지 않고 남아있습니다.
   Stack : 지역변수와 매개변수가 할당되고 함수를 빠져나가면 자동 소멸됩니다.
   Heap : 동적으로 할당된 메모리 영역이며 프로그래머에 의해 할당 및 해제 됩니다.
   */

    // 매개 변수 : Parameter, 인수 (Argument)

    /**
    정적 메모리 할당과 동적 메모리 할당에 대해서 알아 봅니다.

    정적으로 메모리를 할당하면 컴파일시 stack영역에 할당되며, 함수를 빠져 나갈 때 소멸됩니다.
    프로그램 컴파일시 stack에 얼마만큼의 크기로 할당을 해야 하는지 결정되기 때문에
    컴파일 이후 크기를 변경할 수 없습니다.

    따라서 정적 배열 선언시 크기를 가변적으로 명시하면 문제가 될 수 있기 때문에;
    반드시 상수로 명시해야 합니다.
    */

    /** 문장을 추가해 줍니다. */
    int intValue1 = 10;
    const int intValue2 = 10;

    // 정적 배열 선언시 크기를 가변적으로 명시하면 문제가 될 수 있기 때문에
    // 반드시 상수로 명시해야 한다.
    //int intArr1[intValue1;]     // x
    int intArr2[intValue2];
    int intArr3[10];
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
    배열의 종류
    int intArray1[] = {1, 2, 3, 4, 5};          C언어의 배열
    arry&lt;int, 5&gt; intArray2 = {1, 2, 3, 4, 5};   C++ 언어의 배열
    */

    /**
    동적으로 메모리를 할당하는 경우 데이터가 heap영역에 할당됩니다.
    heap 메모리 영역은 프로그래머에 의해 할당(new 연산자)되거나 소멸(delete 연산자)됩니다.
    동적할당은 프로그래머가 원할 땨ㅐ 원하는 크기로 할당할 수 있습니다.
    포인터 변수는 stack에 할당됩니다.
    */

    /** 문장을 추가해 줍니다. */
    int intValue4 = 10;
    /** intArray4 포인터 변수는 stack에 할당되며, intArray1 배열은 heap에 할당됩니다. */
    int* intArray4 = new int[intValue4];

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
    C : malloc(말록, Memory Allocation) 함수와 free() 함수

    C++ : new 연산자와 delete 연산자

    정적 메모리는 컴파일시에 Stack 영역에 할당되고, 함수를 빠져나올 대 소멸됩니다.
    반면 동적 메모리는 런타임시에 프로그래머에 의해서 Heap 영역에 할당되고 소멸됩니다.
    할당시에는 new 연산자를 사용하며 소멸시에는 delete 연산자를 사용합니다.

    heap 영역에 동적 할당되는 메모리의 경우 사용이 끝난다면 반드시 delete를 해 주어야 합니다.
    참고로 동적 배열을 delete 하는 경우 배열이라는 것을 명시하기 위해 delete[] 연산자를 사용합니다.
    */

    /** 동적 할당*/
    int* intPtr1 = new int;
    int* intPtr2 = new int(3);
    int* intPtr3 = new int{ 5 };
    int* intPtr4 = new int();

    /** 배열의 동적 할당*/
    int* array1 = new int[5];

    /** 소멸 */
    delete intPtr1;
    delete intPtr2;
    delete intPtr3;
    delete intPtr4;

    /** 배열의 소멸 */
    delete[] array1;

    cout &lt;&lt; &quot;&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;&quot; &lt;&lt; endl;

    /**
   배열의 동적 할당에 대해서 알아 봅니다.

   정적 할당으로 배열을 선언하게 되면 사이즈가 정해져 버립니다.
   안 쓸 수도 있는데, 사이즈가 정해져 버립니다. 메모리 공간의 낭비가 심해집니다.
   */

   /** 문장을 추가해 줍니다. */

   /**
   사이즈가 1000개인 배열변수를 선언했습니다.
   만일 선언만 하고 안쓴다면 int타입은 4byte입니다. 4 * 1000 = 4000 byte의 비효율이 발생합니다.
   */
    int intArray5[1000];

    /**
    메모리 최적화를 위해서 동적 할당을 할 수 있습니다.
    배열에서는 사이즈도 원하는 사이즈로 동적 할당을 할 수 있습니다.
    */

    /** 문장을 추가해 줍니다. */
    int* intPtr8;
    int arrayLength = 10;

    intPtr8 = new int[arrayLength];

    for (int i = 0; i &lt; arrayLength; i++)
    {
        intPtr8[i] = i;
    }

    for (int i = 0; i &lt; arrayLength; i++)
    {
        cout &lt;&lt; &quot;intPtr8[&quot; &lt;&lt; i &lt;&lt; &quot;] : &quot; &lt;&lt; intPtr8[i] &lt;&lt; endl;
    }

    /** 꼭 delete 연산자로 메모리에서 객체 해제를 해 주어야 합니다. */
    delete[] intPtr8;



}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ Preprocessor]]></title>
            <link>https://velog.io/@m_jooong/C-Preprocessor</link>
            <guid>https://velog.io/@m_jooong/C-Preprocessor</guid>
            <pubDate>Tue, 25 Apr 2023 08:32:09 GMT</pubDate>
            <description><![CDATA[<pre><code>#include &lt;iostream&gt;

/** 문자열 관련 라이브러리*/
#include &lt;string&gt;

/** C++ 표준 라이브러리 사용합니다. */
using namespace std;

/** 매크로 상수를 정의합니다. 끝에 문장의 끝을 나타내는 ;(세미콜론)이 없습니다. */
#define PI 3.141592
#define MY_NAME &quot;John&quot;
#define YEAR 2023
#define MONTH &quot;April&quot;
#define DAY 25

/**
#define을 이용하여 상수뿐만이 아니고 함수도 정의할 수 있습니다.
이름 매크로 함수라고 합니다.
*/
#define SQUARE(x) ((x) * (x))
#define MAX(a, b) ((a &gt; b) ? a : b)

/**
#undef

#undef는  #define과 반대라고 생각하면 됩니다.
#define으로 정의한 내용을 #undef을 사용하면 정의된 것이 없었던 일로 됩니다.

정의해 주도록 합니다.
*/
#define WIDTH 98
#define ADD(X, Y) ((X) + (Y))

#undef WIDTH
#undef ADD

int main()
{
    /**
    C++ 에서 컴파일되는 과정은 다음과 같습니다.

    1. 프로그래머가 작성한 소스파일은 가장 먼저 소스파일에 대한ㅇ 처리는 하는
        선행 처리기를 거치고
    2. 컴파일되어서 오브젝트 파일이 생성되고
    3. 다시 링커에 의해서 실행파일이 됩니다.

    여기서 전처리이자 선행처리(Preprocess)란?
    컴파일 하기 전, 소스 파일 내에 존재하는 선행 처리 지시문을 처리하는 과정을 의미합니다.

    선행 처리 지시문에는  #include, #define, #undef, #if, #elif, #else등
    */

    /**
    #include

    특정 프로그램 파일을 현재 위치에 첨부하여, 하나의 파일처럼 사용합니다.

    #include &lt;stdio.h&gt; Standard Input Output    C언어에서 제공하는 헤더파일
    #include &lt;iostream&gt; Input Output Stream     C++ 언어에서 제공하는 헤더파일
    #include &quot;Creature.h&quot;                       우리가 정의한 커스텀 헤더파일

    &lt;iostream&gt; : C++에서 가장 많이 사용하는 헤더파일, 기본 입출력에 관한 기능으 포함합니다.
    &lt;string&gt; :  문자열 타임인 std::string과 관련 함수를 포함하는 헤더파일입니다.
    &lt;chrono&gt; : 시간 관련 헤더파일입니다.
    &lt;filesystem&gt; : 파일 시스템 관련 헤더파일입니다.
    &lt;thread&gt; : 쓰레드 관련 헤더파일입니다.
    &lt;iomanip&gt; : 입출력 조정자에 관한 헤더파일입니다.
    &lt;fstream&gt; : 파일 스트림 관련 헤더파일입니다.
    &lt;sstream&gt; : std::stringstream이 있는 헤더파일입니다.
    &lt;vector&gt; : vector이 있는 헤더파일

    C++에서 제공하는 헤더파일에 확장자가 없는 이유는
    C++에서 표준 헤더 파일의 선언은 확장자를 생략하기로 약속이 되어 있기 때문입니다.
    */

    /**
    #define    특별히 매크로라고 합니다.

    상수를 이름으로 정의하거나 매크로 함수를 정의할 때 사용하는 전처리 문입니다.
    #define을 잘 활용하면 가독성을 높일 수 이?ㅆ습니다.
    #define으로 상수를 선언하는 것을 매크로라고 하는데, 선언하는 방법은 다음과 같습니다.

    #define PI 3.141592

    그리고 실제로 사용할 때는 PI라는 이름으로 사용하면 됩니다.
    선행 처리자가 #define문을 인식하고 PI 부분을 3.141592라는 상수값으로 치환합니다.

    정의해 주도록 합니다.
    */

    /** 문장을 추가해 줍니다. */
    cout &lt;&lt; &quot;PI : &quot; &lt;&lt; PI &lt;&lt; endl;

    cout &lt;&lt; &quot;SQUARE(9) : &quot; &lt;&lt; SQUARE(9) &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
    매크로 함수를 쓰는 이유는 무엇일까요?
    함수와 매크로 함수의 정의 차이는 무엇일까요?

    함수는 실행파일의 크기를 줄여주고, 코드이 재사용성을 높여주지만 실행 속도가 늦어지는 단점이 있습니다.
    매크로 함수는 실행파일의 크기가 커지고 스택 프레임을 사용할 수 없기 때문에 재귀 호출 구조를 만들 수
        없다는 단점은 있지만 실행 속도가 증가하는 장점이 있습니다.
    */

    /**
    #undef

    #undef는  #define과 반대라고 생각하면 됩니다.
    #define으로 정의한 내용을 #undef을 사용하면 정의된 것이 없었던 일로 됩니다.

    정의해 주도록 합니다.
    */

    /** 문장을 추가해 줍니다. */
    // cout &lt;&lt; &quot;WIDTH : &quot; &lt;&lt; WIDTH &lt;&lt; endl; // (X)
    // int AddResult = ADD(100, 200); // (X)
}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ Constructor]]></title>
            <link>https://velog.io/@m_jooong/C-Constructor</link>
            <guid>https://velog.io/@m_jooong/C-Constructor</guid>
            <pubDate>Tue, 25 Apr 2023 08:02:14 GMT</pubDate>
            <description><![CDATA[<pre><code>
#include &lt;iostream&gt;

// 문자열 라이브러리
#include &lt;string&gt;
// C++ 표준 라이브러리
using namespace std;

//Fruit 라는 클래스 정의하기
class Fruit 
{
private:

    int m_Seed;
    int m_Count;
public:

    // :(콜론) 초기화 리스트로 초기화를 하는 과정이다
    Fruit() : m_Seed(2), m_Count(15)
    {
        cout &lt;&lt; &quot;생성자 호출&quot; &lt;&lt; endl;
        cout &lt;&lt; &quot;Seed : &quot; &lt;&lt; m_Seed &lt;&lt; &quot;, Count : &quot; &lt;&lt; m_Count &lt;&lt; endl;
    }

    // 생성자 오버로딩이다
    // 초기화 리스트에서 앞은 멤버 변수로 인식하고, 뒷 부분은 매개 변수로 인식한다
    Fruit(int seed, int count = 0) : m_Seed(seed), m_Count(count)
    {
        cout &lt;&lt; &quot;Seed : &quot; &lt;&lt; m_Seed &lt;&lt; &quot;, Count : &quot; &lt;&lt; m_Count &lt;&lt; endl;
    }

    ~Fruit()
    {
        cout &lt;&lt; &quot;소멸자 호출 &quot; &lt;&lt; endl;
    }
};

int main()
{
    /**
    객체의 생성과 소멸

    생성자 : 객체를 생성하면서 멤버 변수의 초기화 담당 
    소멸자 : 객체가 메모리에서 소멸될 때 할 일들을 지정해준다.
    */

    // Fruit 라는 클래스 정의하기

    // 동적 할당을 하게 되면 스마크 포인터를 쓰지 않는 이상 delete 연산자로 메모리에서
    // 객체 해제를 해 주어야 한다.
    Fruit* fruit = new Fruit();

    delete fruit;
    cout &lt;&lt; endl;

}
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ iterator]]></title>
            <link>https://velog.io/@m_jooong/C-iterator</link>
            <guid>https://velog.io/@m_jooong/C-iterator</guid>
            <pubDate>Tue, 25 Apr 2023 07:37:00 GMT</pubDate>
            <description><![CDATA[<pre><code>
#include &lt;iostream&gt;

// 문자열 라이브러리
#include &lt;string&gt;
// 스마트 포인터 라이브러리
#include &lt;memory&gt;
// 벡터 컨테이너 라이브러리
#include &lt;vector&gt;
// 리스트 컨테이너 라이브러리
#include &lt;list&gt;
// 배열 사이즈를 가져오는 라이브러리
#include &lt;array&gt;
// 랜덤 라이브러리
#include &lt;time.h&gt;

// C++ 표준 라이브러리
using namespace std;

int main()
{
    // 반복자(Iterator)
    // C++에서는 반복자를 지원하는데 , 이를 사용하면 컨테이너에 저장된 요소를 순회하고
    // 접근하여 효율적으로 컨테이너에 접근할 수 있다
    // 반복자는 포인터는 아니지만 비슷한 개념으로 볼 수 있다
    // 반복자를 이용하면 특정 컨테이너에 종속적이지 않게 컨테이너에 접근 가능하다

    // int타입을 여러개 저장할 수 있는 벡터컨테이너 타입의 intVector1 이름의
    // vector컨테이너 변수 선언
    vector&lt;int&gt; intVector1;

    for (int i = 0; i &lt; 6; i++)
    {
        // 0 , 10, 20, 30, 40, 50
        intVector1.push_back(i * 10);
    }

    for (int i : intVector1)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 1. 반복자 선언
    // vector컨테이너 반복자인 iter반복자 선언
    vector&lt;int&gt;::iterator iter;

    // 2. 반복자 초기화
    // 반복자의 초기화는 중요하다. 
    // 초기화를 하지 않으면 계속 증가해서 에러가 날 수 있다

    // iter반복자는 intVector1의 시작점을 가리킨다
    iter = intVector1.begin();

    // 반복자는 포인터와 유사하지만 아니다
    // 반복자가 가리키는 값을 가져오기 위해서 *(역참조 연산자)를 사용한다
    //cout &lt;&lt; &quot;iter Value : &quot; &lt;&lt; *iter &lt;&lt; &quot;, iter address : &quot;&lt;&lt; iter &lt;&lt; endl;       // x
    cout &lt;&lt; &quot;iter value : &quot; &lt;&lt; *iter &lt;&lt; &quot;, iter address : &quot; &lt;&lt; &amp;iter &lt;&lt; endl;     // x
    cout &lt;&lt; &quot;iter value : &quot; &lt;&lt; *iter &lt;&lt; &quot;, iter address : &quot; &lt;&lt; &amp;*iter &lt;&lt; endl;

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 프로그래밍 언어의 시작은 0부터 시작
    // 0번쨰 인덱스, 1번쨰 인덱, 2번쨰 인덱스, ... 5번쨰 인덱스 
    // 반복자는 인덱스가 아니다
    // 1번쨰 반복자, 2번쨰 반복자, ... 5번째 반복자

    int intArr1[] = { 0,1,2,3,4 };

    // 3. 반복자는 임의 접근이 가능하다
    // 하지만 주의할 점, 임의 접근은 인덱스를 통해 접근해서 해당 값을 반환한다
    // 하지만 iter반복자가 가리키는 값을 변경하는 것은 아니다
    cout &lt;&lt; &quot;iter[1] : &quot; &lt;&lt; iter[1] &lt;&lt; endl;
    cout &lt;&lt; &quot;iter[3] : &quot; &lt;&lt; iter[3] &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // iter 반복자의 *(역참조 연산자)를 사용하면 2번째 인덱스 3번째 반복자의 요소값이 반환된다
    // iter = intVector1.begin() : intVector1의 인덱스 1번째 반복자를 의미한다
    // iter = intVector1.begin() +2 : intVector1의 2번째 인덱스 3번째 반복자를 의미한다
    iter = intVector1.begin() + 2;
    cout &lt;&lt; &quot;intVector1.begin() + 2 : &quot; &lt;&lt; *iter &lt;&lt; endl;
    cout &lt;&lt; endl;

    // iter = intVector1.begin() + 4; intVector1의 4번째 인덱스 5번째 반복자를 의미한다
    iter = intVector1.begin() + 4;
    cout &lt;&lt; &quot;intVector1.begin() + 4 : &quot; &lt;&lt; *iter &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 4. += 연산자 사용 가능
    // 반복자를 초기화 하지 않으면 에러가 발생
    iter = intVector1.begin();      // 초기화를 하지않으면 7번째 인덱스 8번째 반복자를 의미한다
    iter += 3;      // 3번째 인덱스 4번째 반복자 반환
    cout &lt;&lt; &quot;iter : &quot; &lt;&lt; *iter &lt;&lt; &quot;, iter address : &quot;&lt;&lt; &amp;*iter &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /* 5. for문으로 컨테이너의 요소들을 출력하기*/
    cout &lt;&lt; &quot;for문 : &quot; &lt;&lt; endl;
    /* 첫번째 반복자*/
    vector&lt;int&gt;::iterator iter_begin = intVector1.begin();
    // 마지막 반복자의 다음 반복자이다
    vector&lt;int&gt;::iterator iter_end = intVector1.end();
    /*
    iter = iter_begin; : 초기값이다. 첫번째 반복자의 위치
    iter != iter_end; : 조건문이다. 만일 반복자가 마지막 반복자의 다음 위치가 아닐때까지
    */

    for (iter = iter_begin; iter != iter_end; iter++)
    {
        cout &lt;&lt; &quot;iter : &quot; &lt;&lt; *iter &lt;&lt; &quot;, iter address :&quot; &lt;&lt; &amp;*iter &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /* 6. while문*/
    cout &lt;&lt; &quot;while 문 : &quot; &lt;&lt; endl;
    // 반복자는 꼭 초기화 해야한다. 하지 않으면 에러가 발생
    iter = intVector1.begin();
    // 반복자가 마지막 반복자의 다음 위치가 아닐 때까지 반복한다
    while (iter != intVector1.end())
    {
        cout &lt;&lt; *iter &lt;&lt; &quot; &quot;;

        // while반복문을 빠져 나갈 수 있는 조건을 만들어야 한다.
        // 그렇지 않으면 무한 반복한다.

        // 후치 증가 연산자가 아니다. 
        // 연산자 오버로딩으로 반복자를 증가시켜 준다.
        iter++;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /* 7. foreach문*/
    cout &lt;&lt; &quot;foreach문 : &quot; &lt;&lt; endl;
    // foreach문은 반복자 없이도 컨테이너의 값을 출력할 수 있다.
    for (auto iter : intVector1)
    {
        cout &lt;&lt; iter &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /* foreach문의 다른 형태*/
    cout &lt;&lt; &quot;foreach문의 다른 형태 : &quot; &lt;&lt; endl;
    // &amp; : 주소 연산자가 아니고 참조 연산자이다.
    for (auto&amp; iter : intVector1)
    {
        cout &lt;&lt; iter &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /* 8. 반복자를 통한 요소 값 변경*/
    cout &lt;&lt; &quot;반복자를 통한 요소 값 변경 : &quot; &lt;&lt; endl;
    // 반복자를 사용할 때는 꼭 초기화를 해주어야 한다.
    iter = intVector1.begin();

    /**  포인터 연산자와 거의 유사하다*/
    *iter = 100;    // 첫번째 반복자에 100의 리터럴 값을 대입한다
    *(iter + 1) = 200;  // 두번째 반복자에 200의 리터럴 값을 대입한다.
    iter[2] = 300;  // 두번째 인덱스, 세번째 반복자에 300의 리터럴 값을 대입한다.

    for (iter = intVector1.begin(); iter != intVector1.end(); iter++)
    {
        cout &lt;&lt; *iter &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 9. intVector1[2] 앞에 15의 값을 추가한다*/
    cout &lt;&lt; &quot;intVector1[2] 앞에 15의 값을 추가한다.&quot; &lt;&lt; endl;
    intVector1.insert(intVector1.begin() + 2, 15);

    for (iter = intVector1.begin(); iter != intVector1.end(); iter++)
    {
        cout &lt;&lt; *iter &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 10. intVector1[3] 제거하기*/
    cout &lt;&lt; &quot;intVector1[3] 제거 : &quot; &lt;&lt; endl;
    intVector1.erase(intVector1.begin() + 3);

    for (iter = intVector1.begin(); iter != intVector1.end(); iter++)
    {
        cout &lt;&lt; *iter &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 11. 반복문 안에서 erase()함수를 사용할 때는 주의해야 한다.*/
    //cout &lt;&lt; &quot;반복문 안에서 erase()함수를 사용할 때는 주의해야 한다.&quot; &lt;&lt; endl;
    //vector&lt;int&gt; numbers{ 1,2,3,4,5,6,7,8,9,10 };

    //for (vector&lt;int&gt;::iterator it = numbers.begin(); it != numbers.end(); it++)
    //{
    //    // vector 컨테이너의 요소를 2로 나눈 나머지가 0이면 제거하기
    //    // 짝수 값에 제거해 주기
    //    if (*it % 2 == 0)
    //    {
    //        it = numbers.erase(it);
    //    }
    //}

    //for (int i : numbers)
    //{
    //    cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    //}
    //cout &lt;&lt; endl;
    //cout &lt;&lt; endl;

    /** 12. 반복문 안에서 erase()함수를 사용할 때는 주의해야 한다.*/
    cout &lt;&lt; &quot;반복문 안에서 erase()함수를 사용할 때는 주의해야 한다.&quot; &lt;&lt; endl;
    vector&lt;int&gt; numbers{ 1,2,3,4,5,6,7,8,9,10 };

    // 반복문안에서 erase() 함수가 호출되지 않았을 때만 it++ 를 해 준다,.
    for (vector&lt;int&gt;::iterator it = numbers.begin(); it != numbers.end();)
    {
        // vector컨테이너의 요소를 2로 나눈 나머지가 0이면 제거하기
        // 짝수 값을 제거
        if (*it % 2 == 0)
        {
            it = numbers.erase(it);
        }// 반복문 안에서 erase() 함수가 호출되지 않았을 때만 it++ 을 해 준다
        else
        {
            it++;
        }
    }

    for (int i : numbers)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 13. 문자열을 여러개 저장할 수 있는 벡터 컨테이너에서 특정 문자열을 제거하기*/
    cout &lt;&lt; &quot;문자열을 여러개 저장할 수 있는 벡터 컨테이너에서 특정 문자열을 제거하기&quot; &lt;&lt; endl;

    vector&lt;string&gt;names{ &quot;john&quot;, &quot;James&quot;, &quot;Tom&quot;, &quot;Smith&quot;, &quot;Jane&quot; };

    // 반복문 안에서 이름에 &quot;J&quot; 문자열이 들어간 이름들을 지우기
    for (vector&lt;string&gt;::iterator name = names.begin(); name != names.end();)
    {
        // string::find() 함수는 찾는 단어나 문자열이 없으면 string::npos를 반환
        if ((*name).find(&quot;J&quot;) != string::npos)
        {
            name = names.erase(name);
        }   // 반복문 안에서 erase() 함수가 호출되지 않을 때만 name++ 해 주기
        else
        {
            name++;
        }
    }

    for (string name : names)
    {
        cout &lt;&lt; name &lt;&lt; &quot; &quot;;
    }

}
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[VR컨텐츠 2]]></title>
            <link>https://velog.io/@m_jooong/VR%EC%BB%A8%ED%85%90%EC%B8%A0-2</link>
            <guid>https://velog.io/@m_jooong/VR%EC%BB%A8%ED%85%90%EC%B8%A0-2</guid>
            <pubDate>Thu, 20 Apr 2023 09:09:05 GMT</pubDate>
            <description><![CDATA[<p>안녕하세요. 이번주제는 저번글과 이어서 개발기술에대한 팁을 이어서 소개해보겠습니다.
이번에는 최적화에대해 써볼까하는데 사실 VR컨텐츠라고해서 따로 최적화기술이 있는것은 아닙니다.
그러나 VR개발초보자거나 학생분들을위해 몇가지 소개해보겠습니다. </p>
<p>게임의 최적화기술을 한장의글로 서술하기엔 말도안되지만 범용적이고 적용하기쉬운 또 VR에서 효과적인 부분들을 추려서 소개해보겠습니다. 이미 최적화에대한 기본기와 게임개발의 노하우가 있으신분들은 너무쉬운 내용일수 있기때문에 굳이 보지않으셔도 됩니다. </p>
<p>마찬가지로 이번글역시 단순한 팁 그이상그이하도 아니므로 본인의 컨텐츠에 필요한 부분만 습득하시길 바랍니다. </p>
<p>=======================================================================================</p>
<p>개발기술편-2</p>
<ol>
<li>90프레임의 중요성 </li>
</ol>
<p>VR게임은 PC의 하드웨어성능을 공유하더라도 일반적인 게임렌더링보다 당연하게도 더높은 자원을 소비합니다. 왜냐하면 
헤드트래킹을 이용한 양안에 렌더링을 해야하기때문에 두배또는 그이상의 자원이 요구되기 때문입니다.
따라서 일반 PC나 콘솔처럼 개발한다면 VR플레이를 눌렀을때 프레임이 곤두박질치는 낭패를 볼수있습니다.
또한 VR개발시 가장힘든부분이 90프레임을 유지하는것입니다.
90프레임이란 수치는 일반적인 VR기기에서 낼수있는 가장높은 프레임입니다. 만약 이수치보다 프레임이 저하된다면 플레이어의 멀미와 눈의피로도가 현저하게 올라가서 컨텐츠가 망하기 가장쉬운 길입니다. 
그렇기때문에 90프레임을 유지하는것이 VR컨텐츠의 가장기본이고 멀미를 줄이는 최고의방법입니다. 
VR에선 아무리 컨텐츠를 멋지고 화려하게 만들어봤자 프레임이 안나오는 순간 그것은 멀미유발제일 뿐입니다.</p>
<ol start="2">
<li>게임도중 로딩은 최악의수. 프리(pre)로딩의 중요성 </li>
</ol>
<p>앞서말했듯이 프레임간의 간격과 딜레이 괴리감이 멀미와 몰입도에 엄청난 영향을 줍니다. 일반적인 게임은 &#39;디스플레이&#39;라는 공간안에서 벌어지는 가상세계라는것을 플레이어가 인지하고 게임을 진행합니다.
그러나 VR은 인지조화가 현실세계처럼 일어나는 공간이라 인간의 지각이 가상세계임을 인지하기 어렵습니다. 따라서 내가인지하고있는 시각의 간극이 현실세계와다르게 끊기거나 딜레이가 발생한다면 그순간 멀미가 발생하고 몰입도가 깨져버립니다. 따라서 맵을 이동하거나 대량의 오브젝트가 스폰됬을때 등등 발생하는 로딩의 순간들이 일반적인 컨텐츠에서는 당연할수있지만 VR컨텐츠에서는 매우 금기시되는 일입니다. </p>
<p>따라서 레벨스트리밍이나 오픈레벨같은 함수들을 사용하는것은 굉장히 위험한 일입니다. 일반적인 게임의 대표적 최적화 기술인 레벨스트리밍 조차 잠깐의 화면끊김시간을 유발할수 있습니다. 특히 오픈레벨은 정말 긴시간의 로딩을 유발할수도있습니다.  그렇다면 이런것들을 어떻게 극복할수 있을까? </p>
<p>1) 오픈레벨을 최소화, 비밀의방을 만들자.</p>
<p>비밀의방이란 단어는 약간의 은어인데 제가 회사에서 개발하던시절 쓰던 용어입니다. 
일반적인 게임의 진행은 [메뉴창,설정,난이도......등등 UI셋팅레벨] - [게임진행레벨] 이런식으로 구성됩니다.
이때 두개의 레벨로 나뉘어져있기때문에 레벨간 이동을할때 로딩시간이 발생합니다. </p>
<p>VR에선 로딩시간이 발생되면 안되기때문에 이러한것들을 하나의 레벨안에 전부 구성합니다. 그러면 한레벨안에 많은 로딩이 발생하기 때문에 시작이 오래 걸릴수는 있지만 도중에 끊기는 현상은 막을수있습니다.</p>
<p>쉽게말하면 처음시작할때 대부분의 로딩을 시키고 플레이도중에는 로딩을최소화 하는것입니다. 그렇기에 처음게임을 시작할때 등장하는 셋팅화면,메뉴화면등을 같은레벨안의 다른 &#39;비밀의방&#39;을 만들어둔뒤 진행합니다. 
그렇게되면 이미 로딩된 게임공간으로 이동시간을 최소화 시킬 수 있습니다. </p>
<p>이런식으로 게임의 처음 시작뿐만이아니라 인게임도중 장소나 환경을 바꿀일이 있다면 다음과 같은 방법을 사용하는것이 효휼적일 수 있습니다. </p>
<p>2) 화면전환시 자연스러운 트랜지션효과는 필수. </p>
<p>아무리 프리로딩을 해서 진행한다해도 순식간에 주변환경이바뀌는 것은 멀미를 유발할수 있습니다.
따라서 화면을 전환할때는 적절한 효과가 필수입니다. 진행상황에 따라 일반적으로 쓰이는 블랙아웃이나 화이트아웃 또는 디졸브 같은 효과로 최대한 자연스럽게 화면을 전환해야 멀미를 최소화 할 수 있습니다. </p>
<ol start="3">
<li>쉐이더는최대한 간단하게. </li>
</ol>
<p>VR에선 화질이 그렇게 좋지않습니다. 모니터와는 다르게 받아들이는 시각정보가 뚜렷하게 보이지않기때문에 
셰이더에 너무 집착할필요가없습니다. 셰이더는 최대한 간단하게 해야하며 화려한 PBR메터리얼을 만드는것은 자칫하면 낭비일수도 있습니다. 간단한 텍스쳐 몇장으로 좋은 퀄리티를 뽑아야합니다. 
특히나 복잡한 수식으로 구현한 셰이더는 쓸데없는 낭비일뿐입니다. 왠만하면 최종 텍스쳐를 베이크해서 수식을줄이고 최적화하는것이 좋습니다. 절대로 언리얼예제에있는 파티클이펙트 예제나 다른 예제의 엄청난 셰이더를 VR에 적용하려고하지마세요. 용도가 분명히 다릅니다!
또한 구매한 에셋들을 이주시키는 경우가 많이 있는데 대부분 VR에 최적화된 에셋들이아닌경우가 다반사입니다. 반드시 프로젝트에 맞춰서 한번더 최적화를 하고 이주해야합니다.</p>
<p>4.동적라이트는 심사숙고 해야한다.  </p>
<p>프로젝트가 정말정말 가볍지않은이상 동적라이트는 매우 위험할수있습니다. 사실 최적화부분에서 초보자가 가장 하기 쉽고 효과적인것이 스태틱라이트로 전환하는것입니다. 물론 다이나믹섀도우는 기대하기어렵지만 페이크섀도우를 최대한 활용하여 섀도우를 동적으로 그려주는것이 좋습니다. 물론 최적화에 굉장한 자신이 있다면 다이나믹라이트도 도전해볼만하지만 그렇지않고 시간적,인적 자원이 부족하다면 스태틱라이트는 최선의 선택일것입니다. </p>
<p>5.BP or C++? </p>
<p>다들아시겠지만 성능이야 cpp 를 BP가 이길수가 없습니다. 그러나 VR게임의 특성을 생각해보면 때론 BP로 만드는것이 더 효휼적일수 있습니다. 대부분 VR게임이 MMO처럼 대규모 멀티플레잉을 요구하거나 큰데이터를 처리하는 컨텐츠는 많이없습니다. 간단한 체험물이거나 싱글게임처럼 복잡한 알고리즘을 사용할 일이 거의없는 컨텐츠들도 많습니다. 물론 시간이 충분하고 인적자원도 충분하다면 CPP로 짜는게 백번천번 좋지만 그렇지않고 1회성컨텐츠거나 사후관리가 거의필요없거나 패치등도 할일이 거의없다면 BP를 많이 활용하는것이 좋을수도있습니다.
BP의 가장큰 장점은 제작속도입니다. 사실 규모가 작은 프로젝트는 BP로 짜던 CPP로짜던 성능차이가 매우 적을수있습니다. 그렇기에 BP로 빠르게 시스템설계를하고 그래픽쪽 최적화에 투자하는것이 훨씬 효휼적인경우가 많이있습니다. 이것은 설계부분에서 결정해야할 문제기때문에 프로그래머는 프로젝트의 규모와 시스템을 시작단계에서 잘계획하여 제작한다면 시간을 굉장히 아낄수 있습니다. 
때론 작은프로젝트에선 알고리즘이나 코드로 최적화하기보단 폴리곤수 한개라도 더 줄이는게 효과적일수 있기 때문입니다. </p>
<p>6.90프레임의 틈을 노려보자 </p>
<p>가장 처음에 강조했지만 VR게임에서 90프레임이 얼마나 중요한지에대해 말씀드렸습니다.
그러나 90프레임을 무조건 유지하지않아도 되는경우가 있는데 아무것도 움직이지 않을때입니다.
특히 UI만 보고있을때나 영상같은것을 보고있을때는 움직임이 없기때문에 90프레임 이하로 떨어져도 크게상관이 없습니다. 90프레임이 정안된다면 이러한 부분들은 포기하고 넘어가도 크게상관없습니다. </p>
<ol start="7">
<li>렌더타겟은 정말 무겁다.</li>
</ol>
<p>거울을 만들거나 CCTV등 어떤 특정장면을 보여줘야할때 쓰이는 렌더타겟은 정말정말 무겁습니다. 따라서 어떤 장면을 보여줘야할 상황이온다면 그냥 영상으로 녹화한다음 미디어컨텐츠로 영상으로 보여주는것이 훨씬더 가볍습니다. </p>
<ol start="8">
<li>대표적으로 무거워서 쓰기어려운것들. </li>
</ol>
<p>위에 언급한것 이외에 테셀레이션,데칼,모든종류의 블러(PP의 뎁스오브필드 포함)
파티클안에 라이트(진짜 무겁다), 많은수의 파티클 이펙트(파티클은 최소화해야한다) -&gt; 특히 파티클은 에셋구매할경우가많은데 에셋들은 멋있게 보이게 하기위해 라이트모듈을 넣은경우가많다. 반드시 체크해보자! 
[출처] [효율적인 VR컨텐츠 개발하기] [개발기술편-2] (언리얼 엔진 공식 카페 (Unreal Engine)) | 작성자 포인팅</p>
]]></description>
        </item>
        <item>
            <title><![CDATA[C++ Vector]]></title>
            <link>https://velog.io/@m_jooong/C-Vector</link>
            <guid>https://velog.io/@m_jooong/C-Vector</guid>
            <pubDate>Thu, 20 Apr 2023 08:08:20 GMT</pubDate>
            <description><![CDATA[<pre><code>
#include &lt;iostream&gt;

// 문자열 라이브러리
#include &lt;string&gt;
// 벡터 컨테이너 라이브러리
#include &lt;vector&gt;

// C++ 표준 라이브러리
using namespace std;

int main()
{
    // 자료 구조는 C언어 문법이다
    // C++ 에서는 STL(Standard Template Library)를 사용한다

    // STL의 종류
    // vector, list, map, set, deque, queue, stack, pair, tuple

    // 벡터 컨테이너는 자동으로 메모리가 할당되는 배열이다
    // 자동으로 메모리를 할당해주고 알아서 끝에 들어가 주고 알아서 삭제도 해준다
    // Template를 사용하기 때문에 데이터 타입은 어느 타입이던지 가능하다
    // 맨 뒤에서 삽입과 삭제가 가능하다
    // 하지만 배열 기반이므로 삽입 삭제가 빈번하게 일어난다면 효율적이 아니다
    // #include &lt;vector&gt; 를 해야한다

    // Unity C#     : array     List        Dictionary      HashSet
    // Native C++   : array&lt;&gt;   vector      map             set
    // Unreal C++   :           TArray      TMap            TSet

    // vector컨테이너 생성 방법
    // 1. 비어있는 vector1 컨테이너 생성
    vector&lt;int&gt; vector1;

    // 2. 기본값 0으로 초기화된 5개의 요소를 가지는 vector2 컨테이너를 생성한다
    vector&lt;int&gt; vector2(5);

    for (int i : vector2)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 3. 2로 초기화된 5개의 요소를 가지는 vector3 컨테이너 생성
    vector&lt;int&gt; vector3(5, 2);
    for (int i : vector3)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 4. vector4 컨테이너는 vector3 컨테이너를 복사해서 생성한다
    vector&lt;int&gt; vector4(vector3);
    for (int i : vector4)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // vector 컨테이너의 멤버 함수들에 대해 알아보기

    // push_back() : vector 컨테이너 맨 뒤에 요소를 추가 
    vector&lt;int&gt; vector5;
    vector5.push_back(1);
    vector5.push_back(2);
    vector5.push_back(3);
    vector5.push_back(4);
    vector5.push_back(5);

    for (int i : vector5)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // at(index) : 인덱스로 요소를 참조한다
    // vector5[index] 보다 속도는 느리지만, 범위를 점검하므로 안전하다

    int index1 = vector5.at(1);

    cout &lt;&lt; &quot;vector5.at(1) : &quot; &lt;&lt; index1 &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // [index] : 배열의 인덱스처럼 요소를 참조한다
    // 범위를 점검하지 않으므로 속도가 vector5.at(1) 보다 빠르다
    int index2 = vector5[2];

    cout &lt;&lt; &quot;vector5[2] : &quot; &lt;&lt; index2 &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // front() : 첫 번째 요소를 참조
    int index3 = vector5.front();

    cout &lt;&lt; &quot;vector5.front() : &quot; &lt;&lt; index3 &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // back() : 마지막 요소를 참조한다
    int index4 = vector5.back();

    cout &lt;&lt; &quot;vector5.back() : &quot; &lt;&lt; index4 &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // clear() : 모든 요소를 제거하는 함수
    // 요소만 제거하고 메모리는 남아있다.
    // size(길이)만 줄어들고, capacity(용량)은 그대로 있다
    vector5.clear();

    cout &lt;&lt; &quot; vector5.clear() : &quot; &lt;&lt; vector5.size() &lt;&lt; endl;
    cout &lt;&lt; &quot; vector5.capacity() : &quot; &lt;&lt; vector5.capacity() &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 테스트를 위해 값을 추가
    for (int i = 1; i &lt;= 5; i++)
    {
        vector5.push_back(i);
    }

    for (int i : vector5)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // push_back(7) : 마지막 요소뒤에 요소 7 을 추가
    vector5.push_back(7);

    for (int i : vector5)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // pop_back() : 마지막 요소 제거
    vector5.pop_back();
    for (int i : vector5)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // reserve(n) : n개의 요소를 저장할 위치를 예약한다, 미리 동적 할당을 해 놓는다
    vector5.reserve(15);

    cout &lt;&lt; &quot;vecto5.size() : &quot; &lt;&lt; vector5.size() &lt;&lt; endl;
    cout &lt;&lt; &quot;vector5.capacity() : &quot; &lt;&lt; vector5.capacity() &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // resize(n) : 크기를 n개로 변경
    // 만일 더 커졌을 경우 default 값이 0으로 초기화 해 준다
    vector5.resize(10);

    cout &lt;&lt; &quot;vecto5.size() : &quot; &lt;&lt; vector5.size() &lt;&lt; endl;
    cout &lt;&lt; &quot;vector5.capacity() : &quot; &lt;&lt; vector5.capacity() &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // resize(n, m) : 크기를 n개로 변경
    // 더 커졌을 경우 m값으로 초기화
    vector5.resize(15, 3);

    cout &lt;&lt; &quot;vecto5.size() : &quot; &lt;&lt; vector5.size() &lt;&lt; endl;
    cout &lt;&lt; &quot;vector5.capacity() : &quot; &lt;&lt; vector5.capacity() &lt;&lt; endl;
    for (int i : vector5)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // begin() : 첫번째 반복자를 반환한다. 반복자(Iterator)와 함께 사용
    // 프로그래밍 언어에서 숫자는 0부터 시작
    // 배열에서도 0번째 인덱스부터 시작
    // 반복자는 인덱스가 아니다 첫번째 부터 시작

    vector5.begin();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // end() : 마지막 반복자의 다음 반복자를 반환한다 반복자(Iterator)와 함께 사용
    vector5.end();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // rbegin() : reverse begin
    // 거꾸로 해서 첫 번째 반복자를 반환한다 반복자와 함께 사용
    vector5.rbegin();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // rend() : reverse end
    // 거꾸로 해서 마지막 반복자의 다음 반복자를 반환한다 반복자와 함께 사용
    vector5.rend();
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // size는 데이터가 채워진 요소의 개수이고, capacity는 할당된 메모리 공간이다
    vector&lt;string&gt; names;

    names.push_back(&quot;Tom&quot;);
    names.push_back(&quot;Jane&quot;);
    names.push_back(&quot;John&quot;);
    names.push_back(&quot;Smith&quot;);
    names.push_back(&quot;Emma&quot;);
    names.push_back(&quot;James&quot;);
    names.push_back(&quot;Olive&quot;);
    names.push_back(&quot;Harry&quot;);
    names.push_back(&quot;Lucas&quot;);
    names.push_back(&quot;Owen&quot;);

    for (string name : names)
    {
        cout &lt;&lt; name &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 이런 식으로 메모리 할당을 하는 이유는 push_back이 일어날 때마다 동적할당을 하면
    // 비효율적이므로 미리 정해둔 만큼 동적 할당을 하는 것이다
    cout &lt;&lt; &quot;size : &quot; &lt;&lt; names.size() &lt;&lt; endl;
    cout &lt;&lt; &quot;capacity : &quot; &lt;&lt; names.capacity() &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // vector컨테이너의 size, capacity에 대한 테스트
    vector&lt;int&gt; vector6;

    for (int i = 0; i &lt; 100; i++)
    {
        vector6.push_back(i + 1);
        cout &lt;&lt; vector6[i] &lt;&lt; &quot;, size: &quot; &lt;&lt; vector6.size() &lt;&lt; &quot;, capacity : &quot; &lt;&lt; vector6.capacity() &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;
}
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ ThisPointer]]></title>
            <link>https://velog.io/@m_jooong/C-ThisPointer</link>
            <guid>https://velog.io/@m_jooong/C-ThisPointer</guid>
            <pubDate>Wed, 19 Apr 2023 08:29:37 GMT</pubDate>
            <description><![CDATA[<pre><code>
#include &lt;iostream&gt;

// 문자열 관련 라이브러리
#include &lt;string&gt;

// C++ 표준 라이브러리
using namespace std;

// 테스트를 위해 Student1이라는 이름의 클래스를 정의한다
class Student1
{
private:
    int age;
public:
    Student1(int value)
    {
        age = value;
    }

    void SetInfo()
    {
        cout &lt;&lt; age &lt;&lt; &quot; 살 입니다&quot; &lt;&lt; endl;
    }

};

// 1. 클래스의 멤버 변수와 매개 변수의 이름이 같을 때 사용된다.
// 테스트를 위해 student2 클래스 정의
class Student2
{
private:
    // 멤버 변수는 변수 이름만 보더라도 멤버 변수인 것을 알 수 있도록 m_를 붙여준다.
    // int m_Age;
    int age;
public:
    // 멤버 변수 age와 매개 변수 age가 같을 때
    // this-&gt;age는 멤버 변수를 의미하고, age는 매개 변수를 의미한다
    // 하지만 매개 변수를 동일한 이름으로 하지 않는다면 굳이 this포인터를 쓸 필요는 없다.
    // this 포인터는 명시적으로 멤버 변수임을 가리킬 수 있다.
    Student2(int age)
    {
        //age = age;      // (o)
        this-&gt;age = age;
    }
};

// 2. 객체 자신의 주소를 반환할 때 사용된다,
// 테스트를 위해 Student3 클래스 정의
class Student3
{
private:
    int age;
public:
    Student3(int age)
    {
        this-&gt;age = age;
    }

    void SetInfo()
    {
        // 자기 자신의 주소를 반환
        cout &lt;&lt; &quot;this : &quot; &lt;&lt; this &lt;&lt; endl;
    }
};

// *this를 확인해보기 위해 Lion 클래스를 정의
class Lion
{
private:
    int num = 10;
public:
    // 자기 자신을 출력하는 멤버 함수를 정의
    void PrintThis()
    {
        cout &lt;&lt; &quot;this : &quot; &lt;&lt; this &lt;&lt; endl;
    }
    // 자기 자신의 참조자를 반환하는 멤버 함수를 정의
    Lion&amp; ReturnThisReference()
    {
        return *this;
    }
};

// 테스트를 위해 Tiger 클래스 정의
class Tiger
{
private:
    string m_Name;
public:
    // : 콜론 뒤가 초기화 리스트로 초기화를 하는 부분이다
    Tiger(string name) : m_Name(name)
    {

    }

    void SetName()
    {
        cout &lt;&lt; &quot;Name : &quot; &lt;&lt; m_Name &lt;&lt; endl;
    }

    Tiger&amp; ReturnThis1()
    {
        return *this;   // 가리키는 값이 자기 자신이라서 참조가 가능하다
    }

    Tiger ReturnThis2()
    {
        return *this;   // 복사 생성자에 의해 주소값 다르다 
    }

    Tiger&amp; ReturnThis3()
    {
        //return this;    // 주소값에 대한 참조는 안되기 때문이다
    }

    Tiger* ReturnThis4()
    {
        return this;        // this가 자기 자신을 가리키는 포인터이기 때문에 포인터 리턴이 가능하다
    }

    Tiger ReturnThis5()
    {
        //return this; // 포인터를 일반 변수로 리턴하면 안된다
    }


};


int main()
{
    // This포인터

    // 클래스의 멤버 변수를 호출할 때 C++은 어떻게 호출할 객체(인스턴스, instance)를 찾을까
    // = this라는 숨겨진 포인터를 사용한다는 것이다.

    // this포인터는 클래스의 실제 객체에 대한 주소를 가리키는 포인터이다
    // 클래스의 멤버 함수를 호출할 때 이 this라는 포인터를 이용해서 객체를 찾을 수 있다,

    // 클래스가 메모리에 올라가면 객체(인스턴스)가 된다.


    // 테스트를 위해 student1이라는 이름의 클래스를 정의한다
    Student1 student1(22);
    cout &lt;&lt; &quot;student1 : &quot;;
    student1.SetInfo();
    cout &lt;&lt; endl;

    // 메모리에 객체가 생성될 때 멤버 변수는 메모리에 올라가지만 멤버 함수는 올라가지 않는다.
    // 여러개의 같은 객체가 메모리에 올라갈 때 멤버 변수는 다양하게 생성되지만
    // 멤버 함수는 하나만 생성되고 구분을 위해 this포인터를 사용한다.
    cout &lt;&lt; &quot;Sizeof(student1) : &quot; &lt;&lt; sizeof(student1) &lt;&lt; &quot; bytes&quot; &lt;&lt; endl;
    cout &lt;&lt; endl;

    // student1.SetInfo() : 함수는 매개 변수 없이 호출되는 것 처럼 보인다
    // 하지만 student1.SetInfo(student1); 처럼 쓰인다.
    // 이 주소는 우리 눈에는 안보이지만 존재한다.
    // 첫 번째 매개 변수로 전달된 객체의 주소는 이름이 this인 포인터 변수에 저장된다.

    // student1 : student1객체의 주소
    // this : 객체의 주소

    // 이렇게 컴파일러에 의해서 자동으로 추가 된다.
    // 우리가 실제로 매개 변수로 넣어주는 것 보다 하나가 더 추가되는 것이다.
    // 이렇게 하면 호출된 멤버 함수는 자신을 호출한 객체가 무엇인지 정확하게 알 수 있다

    // this포인터는 
    // 1. 클래스의 멤버 변수와 매개 변수의 이름이 같을 때 사용된다.
    // 테스트를 위해 student2 클래스 정의

    // 2. 객체 자신의 주소를 반환할 때 사용된다,
    // 테스트를 위해 Student3 클래스 정의
    Student3 student3(2);

    cout &lt;&lt; &quot;student3의 주소값 : &quot; &lt;&lt; &amp;student3 &lt;&lt; endl;
    cout &lt;&lt; endl;

    // this를 이용해서 출력한 값과 &amp;student3의 값이 같은 것을 확인할 수 있다.
    // this는 자기 자신을 가리키는 포인터이기 때문이다.
    cout &lt;&lt; &quot;student3의 주소값 : &quot;;
    student3.SetInfo();
    cout &lt;&lt; endl;

    // this포인터는 메모리에 생성된  객체 자신을 가리키는 포인터이다
    // 그러면 왜 this 포인터를 만든 것일까
    // class멤버변수들은 객체가 생성되어질 때 마다 메모리에 할당된다.
    // 함수와 같이 크기가 큰 것들은 메모리에 굳이 반복해서 할당할 필요없다.
    // 함수를 메모리에 한 번만 할당해 놓고 각 객체의 this포인터를 넘긴다
    // 어떤 객체가 함수를 호출했는지 알 수 있게 하는 것이다.

    // *this는 무엇일까

    // this포인터가 가리키는 주소의 실제 값을 의미한다
    // 멤버 변수와 멤버 함수이다
    int intValue1 = 30;
    int* intPtr1 = &amp;intValue1;
    cout &lt;&lt; &quot;*intPtr1 : &quot; &lt;&lt; *intPtr1 &lt;&lt; endl;
    cout &lt;&lt; endl;

    // *intPtr1은 출력하면 30이 나온다
    // 이것은 *intPtr1 가리키는 값을 참조하기 때문이다 포인터의 참조이다
    // int&amp; intRef1 = *intPtr1; 은
    // int&amp; intRef1 = intValue1; 으로 생각할 수 있다
    // 참조자는 포인터가 아니다 별명이다

    // int* (&amp;intRef2) = intPtr1;은
    // intPtr1이 가리키는 주소값을 받는 상황임에도 당연히 포인터로 받아야 하지만
    // intRef2라는 참조자로 받는 것도 가능하다
    // 단 intRef2는 참조자이지만 포인터로 전달받기 때문에 별도의 포인터 주소값을 가지게 된다.

    int&amp; intRef1 = *intPtr1;
    int* (&amp;intRef2) = intPtr1;

    // 참조자는 포인터가 아니다
    // *intRef1 : 참조자는 포인터가 아니니 역참조 연산자로 포인터가 가리키는 값을 알 수 없다.
    // &amp;intRef1 : 참조자는 포인터가 아니니 참조자가 가리키는 주소값을 알기 위해서는 주소 연산자를 사용한다.

    //cout &lt;&lt; &quot;intRef1 value : &quot; &lt;&lt; *intRef1 &lt;&lt; &quot;, intRef1 address : &quot; &lt;&lt; &amp;intRef1 &lt;&lt; endl;  // x
    cout &lt;&lt; &quot;intRef1 value : &quot; &lt;&lt; intRef1 &lt;&lt; &quot;, intRef1 address : &quot; &lt;&lt; &amp;intRef1 &lt;&lt; endl;
    cout &lt;&lt; endl;

    // this는 자기 자신의 객체를 가리키는 포인터 변수이다
    // *this를 확인해보기 위해 Lion 클래스를 정의
    Lion lion1;
    // 자기 자신을 출력
    lion1.PrintThis();
    cout &lt;&lt; endl;

    // 참조자 변수 선언하고 참조자 리턴 받기
    Lion&amp; lionRef = lion1.ReturnThisReference();
    // 참조자의 자기 자신을 출력
    lionRef.PrintThis();
    cout &lt;&lt; endl;

    // this는 자기 자신을 가리키는 키워드 이고
    //  포인터 변수에 역참조 연산자 (*)를 붙여주면 포인터 변수가 가리키는 실제 값이다
    // 객체일 때는 포인터 변수가 가리키는 객체의 멤버변수, 멤버함수를 가리킨다.
    // *this : 자기 자신이 가리키는 값(멤버변수, 멤버함수)이다
    // 포인터의 참조 개념이다

    // this는 자기 자신을 가리키는 포인터이고
    // *this는 자기 자신의 객체 자체이다

    cout &lt;&lt; &quot;lion1의 주소값 : &quot; &lt;&lt; &amp;lion1 &lt;&lt; endl;
    cout &lt;&lt; &quot;lionRef의 주소값 : &quot; &lt;&lt; &amp;lionRef &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 테스트를 위해 Tiger 클래스 정의
    Tiger tiger1(&quot;Korea&quot;);

    Tiger* ReturnThis1 = &amp;tiger1.ReturnThis1();
    Tiger ReturnThis2 = tiger1.ReturnThis2();
    Tiger* ReturnThis4 = tiger1.ReturnThis4();

    cout &lt;&lt; &quot;ReturnThis1 : &quot; &lt;&lt; ReturnThis1 &lt;&lt; endl;
    cout &lt;&lt; &quot;ReturnThis2 : &quot; &lt;&lt; &amp;ReturnThis2 &lt;&lt; endl;
    cout &lt;&lt; &quot;ReturnThis4 : &quot; &lt;&lt; ReturnThis4 &lt;&lt; endl;

    ReturnThis1-&gt;SetName();
    ReturnThis2.SetName();
    ReturnThis4-&gt;SetName();

}
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ Array]]></title>
            <link>https://velog.io/@m_jooong/C-Array</link>
            <guid>https://velog.io/@m_jooong/C-Array</guid>
            <pubDate>Tue, 18 Apr 2023 08:36:04 GMT</pubDate>
            <description><![CDATA[<pre><code>
#include &lt;iostream&gt;

// 문자열 관련 라이브러리
#include &lt;string&gt;
// 배열의 사이즈를 가져오기 위한
#include &lt;array&gt;
// C++ 표준 라이브러리
using namespace std;

// Rectangle 이름의 구조체를 정의
struct Rectangle
{
    int width;
    int height;
};

// Fruit라는 이름의 구조체 정의
struct Fruit
{
    string name;
    int count;
};

int main()
{
    // 배열(array)은 같은 자료형을 여러개 저장할 수 있는 타입이다

    // 매우 비효율적이다
    int score0;
    int score1;
    int score2;
    // ~
    int score499;
    int score500;

    // 배열을 사용하면 위의 작업을 쉽고, 효율적으로 실행할 수 있다.
    // int타입의 여러 변수 저장 할 수 있는 score[]변수 선언
    // 대괄호를 사용해 배열 변수에 할당할 배열 길이 설정

    // 자료형 배열이름[배열길이]; 
    int score[30];

    // 배열에 있는 각 변수를 요소(element)라고 한다,
    // 요소에는 고유한 이름이 없다.
    // 대신 배열의 개별 요소에 접근하려면, 배열 이름을 하위 연산잔([])와 함께 사용하며
    // 원하는 요소를 알려주는 인덱스(index)라는 매개 변수를 사용한다.

    // 배열이름[인덱스]

    // 프로그래밍 언어에서 숫자는 0부터 시작한다.

    // score[0]     : score배열의 0번째 인덱스, score배열의 첫 번째 요소이다.
    // score[1]     : score배열의 1번째 인덱스, score배열의 두 번째 요소이다.
    // score[2]     : score배열의 2번째 인덱스, score배열의 세 번째 요소이다.
    // score[9]     : score배열의 9번째 인덱스, score배열의 열 번째 요소이다.
    // score[29]    : score배열의 29번째 인덱스, score배열의 마지막 요소이다.

    // 배열의 인덱스는 0부터 시작한다.

    // string 타입을 여러개 저장할 names 배열 변수 선언
    // 사이즈를 5로 해서 초기화
    string names[5];
    names[0] = &quot;John&quot;;
    names[1] = &quot;Hane&quot;;
    names[2] = &quot;Tom&quot;;
    names[3] = &quot;Smith&quot;;
    names[4] = &quot;James&quot;;

    cout &lt;&lt; &quot;for 문&quot; &lt;&lt; endl;

    for (int i = 0; i &lt; size(names); i++)
    {
        cout &lt;&lt; names[i] &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;


    cout &lt;&lt; &quot;foreach 문&quot; &lt;&lt; endl;

    for (string name : names)
    {
        cout &lt;&lt; name &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 모든 자료형을 배열로 만들 수 있다. 구조체를 배열로 만들어보기
    // Rectangle 이름의 구조체를 정의

    // 배열의 사이즈는 5인데 인덱스는 2까지만 값을 줌
    Rectangle rectangles[5];
    rectangles[0].width = 20;
    rectangles[0].height = 10;
    rectangles[1].width = 22;
    rectangles[1].height = 30;
    rectangles[2].width = 55;
    rectangles[2].height = 60;

    // 배열의 사이즈는 5개인데, 요소의 수를 넘겨보자
    // 배열은 사이즈를 다시 정해주기 전까지는 사이즈를 줄이거나 늘릴 수 없다.
    rectangles[10].width = 25;
    rectangles[10].height = 100;

    cout &lt;&lt; &quot;for 문&quot; &lt;&lt; &quot; &quot;;
    for (int i = 0; i &lt; size(rectangles); i++)
    {
        cout &lt;&lt; &quot;width : &quot; &lt;&lt; rectangles[i].width &lt;&lt; &quot;, height : &quot; &lt;&lt; rectangles[i].height &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;foreach 문&quot; &lt;&lt; &quot; &quot;;
    for (Rectangle rectangle : rectangles)
    {
        cout &lt;&lt; &quot;width : &quot; &lt;&lt; rectangle.width &lt;&lt; &quot;, height : &quot; &lt;&lt; rectangle.height &lt;&lt; endl;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 고정 배열을 선언할 때 배열의 길이는 컴파일 타임 상수이어야 한다.
    // 컴파일 타임에 고정 배열의 길이를 알아야 하기 때문이다

    // 상수(constant)란
    // 상수는 값이 변하지 않는 것을 의미한다,
    // 상수에 넣는 데이터로는 숫자만 오는 것이 아니라 클래스나 구조체 같은 객체도 가능하다

    // Fruit라는 이름의 구조체 정의
    const Fruit fruit = {&quot;Apple&quot;, 10};
    //fruit.name = &quot;Banana&quot;;      // x
    //fruit.count = 30;           // x

    // 리터럴(Literal) 이란 
    // 리터럴은 값 그 자체를 의미한다. 즉 변수에 넣는 변하지 않는 데이터를 의미한다,

    // intValue1 은 상수변수이고, 1 은 리터럴 값이다.
    const int intValeu1 = 1;
    // stringValue1은 상수변수이고 &quot;Jane&quot;은 리터럴 값이다.
    const string stringValue1 = &quot;Jane&quot;;

    // 고정배열을 선언하는 방법 4가지
    // 1. 리터럴 상수를 사용
    int intArr1[5];

    // 2. 메크로 기호 상수를 사용
#define ARRAY_LENGTH 5
    int intArr2[ARRAY_LENGTH];

    // 3. 상수 변수 사용
    const int arrayLength = 5;
    int intArr3[arrayLength];

    // 4. 열거형 사용
    enum EArrayLength {MaxArrayLength = 10};
    int intArr4[EArrayLength::MaxArrayLength];

    // 좋지 않은 예
    // 비-상수 변수 사용
    int arrayLength1 = 10;
    //int intArr5[arrayLength1];  // x

    // 런타임 상수 변수 사용
    int arrayLength2 = 5;
    // arrayLength3 값은 컴파일 타임에서는 알 수 없는 런타임 상수이다.
    const int arrayLength3 = arrayLength2;
    //int intArr5[arrayLength3];      // x 

    // 배열은 선언과 동시에 초기값을 줄 수 있다.
    string friend1[5] = { &quot;John&quot;, &quot;Tom&quot;, &quot;Jane&quot;, &quot;Smith&quot;, &quot;James&quot; };

    // 요소의 개수로 사이즈를 알 수 있기 때문에 사이즈를 명시하지 않아도 된다.
    string friend2[] = { &quot;John&quot;, &quot;Tom&quot;, &quot;Jane&quot;, &quot;Smith&quot;, &quot;James&quot; };

    for (auto name : friend1)
    {
        cout &lt;&lt; name &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 배열의 초기화에 대한 정리

    // 일반적인 배열 선언 방식
    int intArr5[3];
    intArr5[0] = 1;
    intArr5[1] = 2;
    intArr5[2] = 3;

    for (int i : intArr5)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 배열을 선언하고 초기화
    int intArr6[] = { 10, 20, 30, 40, };

    for (int i : intArr6)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;


    // 배열을 선언하고 초기화 하지 않아도 된다, 나머지는 기본값으로 채워진다  // 기본값 : 0
    int intArr7[10] = { 10, 20 };

    for (int i : intArr7)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 대입 연산자가 없어도 된다.
    int intArr8[3]{ 10, 20, 30 };

    for (int i : intArr8)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 배열의 요소를 전부 0으로 설정
    int intArr9[20] = {};
    for (int i : intArr9)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    int intArr10[30]{};
    for (int i : intArr10)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 요소의 갯수로 사이즈를 알 수 있기 때문에 사이즈를 명시하지 않아도 된다
    int intArr11[] = { 1,2,3,4,5,6,7,8,9, };
    for (int i : intArr11)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 대입연산자가 없어도 되며 사이즈를 명시하지 않아도 된다
    int intArr12[]{ 1,2,3,4,5,6,7,8,9 };
    for (int i : intArr12)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 지금까지는 C언어 스타일의 배열이다.

    // 이제는 C++ 스타일의 배열
    array&lt;int, 5&gt; intArr13 = { 1,2,3,4,5, };
    for (int i : intArr13)
    {
        cout &lt;&lt; i &lt;&lt; &quot; &quot;;
    }
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ CallByValue]]></title>
            <link>https://velog.io/@m_jooong/C-CallByValue</link>
            <guid>https://velog.io/@m_jooong/C-CallByValue</guid>
            <pubDate>Tue, 18 Apr 2023 07:21:50 GMT</pubDate>
            <description><![CDATA[<pre><code>
#include &lt;iostream&gt;

/** 문자열 관련 라이브러리*/
#include &lt;string&gt;

/** C++ 표준 라이브러리 사용합니다. */
using namespace std;

// 값에 의한 호출을 테스트 하기 위해 CallByValue라는 함수를 정의한다.
void CallByValue(int value) 
{
    // 함수 내부에서 값을 변경하기
    value = 20;
    cout &lt;&lt; &quot;value : &quot; &lt;&lt; value &lt;&lt; &quot;, address : &quot; &lt;&lt; &amp;value &lt;&lt; endl;
}

// 주소에 의한 호출을 테스트 하기 위해 CallByAddress라는 함수를 정의한다.
void CallByAddress(int* address) 
{
    // * : 역참조 연산자, 포인터 변수가 가리키는 실제 값 20을 의미한다.
    *address = 20;
    cout &lt;&lt; &quot;address : &quot; &lt;&lt; *address &lt;&lt; &quot;, address address : &quot; &lt;&lt; address &lt;&lt; endl;
}

// 참조에 의한 호출을 테스트 하기 위해 CallByReference라는 함수를 정의한다.
void CallByReference(int&amp; reference)
{
    reference = 20;
    cout &lt;&lt; &quot;reference : &quot; &lt;&lt; reference &lt;&lt; &quot;, reference address : &quot;&lt;&lt; &amp;reference &lt;&lt; endl;
}

// 값을 위한 호출을 테스트 하기 위해 SwapByValue라는 이름의 함수를 정의한다
void SwapByValue(int value1, int value2)
{
    int temp = value1;
    value1 = value2;
    value2 = temp;

    cout &lt;&lt; &quot;value1 : &quot; &lt;&lt; value1 &lt;&lt; &quot;, value2 : &quot; &lt;&lt; value2 &lt;&lt; endl;

}

// 주소에 의한 호출을 테스트 위해 SwapByAddress라는 함수를 정의한다.
void SwapByAddress(int* value1, int* value2)
{
    int temp = *value1;
    *value1 = *value2;
    *value2 = temp;

    cout &lt;&lt; &quot;value1 : &quot; &lt;&lt; *value1 &lt;&lt; &quot;, value1 : &quot; &lt;&lt; *value2 &lt;&lt; endl;
}

// 참조에 의한 호출을 테스트 하기 위해 SwapByReference 함수를 정의
void SwapByReference(int&amp; value1, int&amp; value2)
{
    int temp = value1;
    value1 = value2;
    value2 = temp;

    cout &lt;&lt; &quot;value1 : &quot; &lt;&lt; value1 &lt;&lt; &quot;, value1 : &quot; &lt;&lt; value2 &lt;&lt; endl;

}

int main()
{
    // 함수의 매개 변수에 값을 전달하는 방식입니다
    // 1. CallByValue : 값을 의한 호출
    // 2. CallByAddress : 주소에 의한 호출
    // 3. CallByReference : 참조에 의한 호출

    // 1. CallByValue : 
    // 값을 의한 호출로 함수의 매개 변수에 값을 복사해서 넘겨주는 방식이다. 값에 의한 호출이다.

    // 함수가 호출될 때 메모리 공간 안에서는 함수를 위한 별도의 임시 공간이 생성된다. 함수가 종료되면 해당 공간은 사라진다.
    // 메모리 공간은 스택(Stack)영역과 힙(heep)영역이 있다.
    // 스택 : 함수 호출시 할당되는 메모리 영역이다. 지역변수의 선언으로
    //      할당되는 메모리 영역이다. 값에 의한 호출 방식은 전달되는 변수의 값을
    //      복사해서 함수의 매개 변수로 전달한다. 복사된 변수의 값은 함수 안에서
    //      지역적으로 사용되는 지역 변수의 성격을 가진다.
    //      따라서 함수 안에서 매개 변수의 값이 변경되어도, 외부의 변수의 값은 변경되지 않는다.

    // 2. CallByAddress : 주소에 의한 호출

    // CallByAddress와 CallByReference는 결과값이 같다.
    // CallByReference는 C++에서 지원한다.

    // 3. CallByReference : 참조에 의한 호출

    // 함수를 호출할 때 메모리 공간 안에서는 함수를 위한 별도의 공간이 생성된다.
    // 함수가 종료되면 해당 공간은 사라진다.
    // 참조에 의한 호출은 매개 변수로 전달되는 변수의 레퍼런스(참조)를 전달한다.
    // 해당 변수를 계속 가리키게 된다.
    // 따라서 함수 안에서 매개 변수의 값이 변경되면, 매개 변수로 전달된 값도 변경된다.

    // 값에 의한 호출을 테스트 하기 위해 CallByValue라는 함수를 정의한다.
    // 문장 추가
    // 함수가 호출되면 int value = intValue3 형태로 값의 복사가 이뤄진다.
    // 실제로 intValu3을 대입시키는 것이 아니라 intValue3 변수가 가지는 값을 복사하고
    // 임시로 메모리에 저장한 후 그 값을 value에 넣는다. value와 intValue3은 지역 변수로
    // 각각 다른 주소값을 가지게 되기 때문에 value값을 변경해도 intValue3변수의 값은 변경되지 않는다.
    int intValue3 = 10;
    CallByValue(intValue3);

    cout &lt;&lt; &quot;intValue3 : &quot; &lt;&lt; intValue3 &lt;&lt; &quot;, intValue3 address : &quot; &lt;&lt; &amp;intValue3 &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 주소에 의한 호출을 테스트 하기 위해 CallByAddress라는 함수를 정의한다.
    // 함수가 호출되면 int* address : &amp;intValue4 의 형태로 intValue4의 주소를 가리키고 있기 때문에
    // 역참조 연산자로 intValue4의 주소에 접근을 하고 값을 변경하면 intValue4의 값이 변경되게 된다.
    // 
    int intValue4 = 10;
    CallByAddress(&amp;intValue4);

    cout &lt;&lt; &quot;intValue4 : &quot; &lt;&lt; intValue4 &lt;&lt; &quot;, intValue4 address : &quot; &lt;&lt; &amp;intValue4 &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 참조에 의한 호출을 테스트 하기 위해 CallByReference라는 함수를 정의한다.
    int intValue5 = 10;
    CallByReference(intValue5);

    cout &lt;&lt; &quot;intValue5 : &quot; &lt;&lt; intValue5 &lt;&lt; &quot;, intValue5 address : &quot; &lt;&lt; &amp;intValue5 &lt;&lt; endl;
    cout &lt;&lt; endl;


    // 매개 변수에 값을 전달하더라도 원본 변수의 값을 변경하지 않으려면 CallByValue를 쓴다.
    // 메개 변수에 값을 전달하면서 원본 변수의 값을 변경하려면 CallByReference를 쓴다.
    // CallByAddress와 CallByReference는 결과 값이 동일하다.


    // 값을 위한 호출을 테스트 하기 위해 SwapByValue라는 이름의 함수를 정의한다
    // intValue1의 값은 value1에 복사되고 intValue2의 값은 value2에 복사되어 전달하기 때문에
    // intValue1과 intValue2의 값이 바뀐것이 아니라 value1 value2의 값만 변경된다.
    // CallByValue는 값을 복사해서 전달되기 때문에 함수 외부에 변수가 변결될 가능성이 없다는 특징이 있지만
    // 전달해 주는 값이 크다면 넘겨줄 때마다 데이터 복사에 의한 비용손실 문제가 발생하는 단점이 있다.
    int intValue6 = 1;
    int intValue7 = 2;

    SwapByValue(intValue6, intValue7);

    cout &lt;&lt; &quot;intValue6 : &quot; &lt;&lt; intValue6 &lt;&lt; &quot;, intValue7 : &quot; &lt;&lt; intValue7 &lt;&lt; endl;
    cout &lt;&lt; endl;

    // CallByAddress는 주소에 의한 호출로 주소 값을 매개 변수로 전달하는 함수 호출을 말한다.
    // 주소에 의한 호출을 테스트 위해 SwapByAddress라는 함수를 정의한다.

    // 메모리 주소값을 저장하는 포인터 변수 value1 value2를 매개 변수로 받아와서 value1이
    // 가리키는 값과 value2가 가리키는 값을 변경하는 함수이다.
    int intValue8 = 1;
    int intValue9 = 2;

    SwapByAddress(&amp;intValue8, &amp;intValue9);

    cout &lt;&lt; &quot;intValue8 : &quot; &lt;&lt; intValue8 &lt;&lt; &quot;, intValue9 : &quot; &lt;&lt; intValue9 &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 참조에 의한 호출
    // 참조에 의한 호출을 테스트 하기 위해 SwapByReference 함수를 정의
    int intValue10 = 1;
    int intValue11 = 2;
    // SwapByReference의 value1은 intValue10을 가리키는 참조자이고, value2는 intValue11을 가리키는 참조자이다.
    // 즉, 참조자는 같은 데이터 공간을 가리키는 변수이지만, 이름만 다를 뿐이다
    // 참조자 별명, 별칭이라고 볼 수 있다.
    SwapByReference(intValue10, intValue11);

    cout &lt;&lt; &quot;intValue10 : &quot; &lt;&lt; intValue10 &lt;&lt; &quot;, intValue11 : &quot; &lt;&lt; intValue11 &lt;&lt; endl;
    cout &lt;&lt; endl;








}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ 문자열 String]]></title>
            <link>https://velog.io/@m_jooong/C-%EB%AC%B8%EC%9E%90%EC%97%B4-String</link>
            <guid>https://velog.io/@m_jooong/C-%EB%AC%B8%EC%9E%90%EC%97%B4-String</guid>
            <pubDate>Tue, 11 Apr 2023 08:39:08 GMT</pubDate>
            <description><![CDATA[<pre><code>
#include &lt;iostream&gt;

/** 문자열 관련 라이브러리*/
#include &lt;string&gt;
/** 문자열의 대, 소문자 변환 라이브러리*/
#include &lt;algorithm&gt;

/** C++ 표준 라이브러리 사용합니다. */
using namespace std;

// 정적할당 test
class Animal
{
public:

    Animal()
    {
        cout &lt;&lt; &quot;정적 할당 생성자&quot; &lt;&lt; endl;
    }

    ~Animal()
    {
        cout &lt;&lt; &quot;정적 할당 소멸자&quot; &lt;&lt; endl;
    }

};

// new 연산자를 이용한 동적 할당을 테스트하기 위해 Lion이라는 클래스 정의
class Lion
{
public:

    Lion()
    {
        cout &lt;&lt; &quot;new 연산자를 이용한 생성자&quot; &lt;&lt; endl;
    }

    ~Lion()
    {
        cout &lt;&lt; &quot;delete 연산자를 이용한 소멸자&quot; &lt;&lt; endl;
    }
};

/**
스마트 포인터로 동적으로 객체 생성
테스트를 위해서 Tiger라는 이름의 클래스 생성
*/
class Tiger
{
public:
    Tiger()
    {
        cout &lt;&lt; &quot;스마트 포인터를 이용한 동적할당 생성자 &quot; &lt;&lt; endl;
    }

    ~Tiger()
    {
        cout &lt;&lt; &quot;스마트 포인터를 이용한 동적할당 소멸자 &quot; &lt;&lt; endl;
    }
};


int main()
{
    /**
   게임 엔진 내부는 수학과 물리덩어리입니다. 문자열이 아닙니다.

   완성도 있는 게임의 조건은 유저에게 정확한 정보를 알려야 합니다.
   문자열로 알려야 합니다.

   올바른 정보를 효율적으로 유저에게 전달하려면 문자열 클래스에서 제공하는
   멤버 함수들을 자유롭게 쓸 수 있어야 합니다.

   */

    // C++에서의 동적할당
    // 1. 정적 할당 : 안쓰더라도 미리 할당해 놓는다. 비효율적인 부분이 발생할 수 있다.
    //      내가 메모리 할당을 할 필요가 없다.
    // 2. new 연산자와 delete연산자를 사용하는 동적할당 : 런타임에서 메모리 할당을 한다.
    //      효율적으로 필요한 부분에서 메모리 할당을 한다. 까다로운 부분이 있다.
    //      하지만 동적으로 객체 생성을 해야한다.
    //      1. new 연산자로 객체 생성을 한다. delete 연산자로 객체 해제를 해 준다.
    //          만일 delete 연산자로 객체 해제를 해 주지 않으면 메모리 누수가 발생한다.
    //          메모리 누수 : 내가 접근할 수 없는, 지울 수 없는 찌꺼기들이 메모리에 쌓인다.
    //          나중에는 앱이나 게임이 강제로 종료될 수 있다.
    // 3. 스마트포인터를 이용한 동적할당  : 내가 객체 해제를 해 줄 필요가 없다.
    //      메모리 누수 발생을 원천적으로 예방할 수 있다. 2011년도에 지원을 시작했다.

    // 정적할당 test를 위해 Animal이라는 클래스 정의
    // {} 범위를 벗어나면 자동으로 객체 해제가 된다.
    // 쓰지도 않는 엄청난 데이터가 Animal 클래스 안에 있다면..
    // 비효율이 발생한다.
    // 
    Animal animal1;
    cout &lt;&lt; endl;

    // new 연산자를 이용한 동적 할당을 테스트하기 위해 Lion이라는 클래스 정의
    Lion* lion1 = new Lion();
    cout &lt;&lt; endl;

    // new 연산자로 객체 생성을 하면 delete 연산자로 객체 해제를 해 주어야 한다.
    // 하지 않는다면 메모리 누수가 발생한다.
    // 포인터 변수는 대상을 변경할 수 있다.
    // 대상을 변경하면 원래 객체는 nullptr가 된다. nullptr에 접근해서 값을 변경하려고
    // 하면 런타임 에러가 발생한다. 복잡한 코드에서는 어느 위치에서 delete 연산자로
    // 메모리 해제를 해 주어야 하는지 상당히 복잡하다.
    // 
    delete lion1;
    cout &lt;&lt; endl;

    /**
    delete 연산자 사용의 복잡성과 메모리 누수 예방을 위해서 스마트 포인터가 생겼다.
    1. unique_ptr : C++ 11( 2011년 )에 지원 시작
    2. shared_ptr : C++ 11( 2011년 )에 지원 시작
    3. weak_ptr   : C++ 11( 2011년 )에 지원 시작
    4. auto_ptr   : C++ 17( 2017년 )에 없어졌다.

    C언어 때는 malloc(말록, memory Allocation), free() 함수로 메모리 관리 했다.
    C++에서 new 연산자, delete 연산자로 메모리 관리를 하면 어렵다. 테스트를 많이 해봐야 한다.

    2011년에 스마트 포인터를 지원하면서 메모리 관리가 쉬워졌다.
    */

    /**
    스마트 포인터로 동적으로 객체 생성
    테스트를 위해서 Tiger라는 이름의 클래스 생성
    */
    unique_ptr&lt;Tiger&gt; uniquePtr0 = make_unique&lt;Tiger&gt;();
    cout &lt;&lt; endl;

    /**
    native C++에서는 스마트 포인터로 메모리 관리를 하는 것이 최상입니다.

    Unreal C++에서 그럴까요? 당연히 아니죠
    Unreal C++에서도 TUniquePtr, TSharedPtr, TSharedRef, TWeakPtr로 메모리 관리를
    할 수는 있지만 많이 안쓰게 됩니다.

    언리얼 엔진에서 메모리 관리
    1. UObject 자식클래스들은 생성자 함수에서 CreateDefaultSubobject() 함수로 동적으로 객체 생성을
        합니다. 엔진이 메모리 관리를 합니다.
    2. UObject 자식클래스들은 생성자 함수 이외에서는 NewObject() 함수로 동적으로 객체 생성을
        합니다. 엔진이 메모리 관리를 합니다.
    3. TArray(native C++에서 vector컨테이너)컨테이너의 요소들은 엔진이 메모리 관리를 합니다.
    4. AActor 자식클래스들은 SpawnActor() 함수로 동적으로 객체 생성을 합니다.
        엔진이 메모리 관리를 합니다.
    5. UObject 자식클래스들과 AActor 자식 클래스가 아닌 클래스들은 스마트 포인터로 메모리 관리를 합니다.
    5. 구조체는 스마트 포인터로 메모리 관리를 해 주어야 합니다. 그런데 구조체에는 필요한 멤버 변수들만
        선언한 후에 구조체 자체를 가볍게 한 후에 정적 할당으로 객체 생성을 합니다. 내가 메모리 관리를
        할 필요가 없습니다.

    구현에 신경쓰지 않고 아이디어에 집중할 수 있도록 해 줍니다.

    모든 UObject 자식클래스들이 엔진이 메모리 관리를 하는 가비지 컬렉션 대상이 된다면 렉이 생길수도
    있습니다.
    따라서 가비지 컬렉션 대상을 줄이기 위해서 약포인터(TWeakObjectPtr)를 지원합니다.
    */

    /**
    문자열을 선언하는 3가지 방법
    */
    cout &lt;&lt; &quot;1. 생성과 동시에 초기화 할 수 있다&quot; &lt;&lt; endl;
    string strnigValue1(&quot; C 공부하고 있어요~ &quot;);
    cout &lt;&lt; &quot;stringValue1&quot; &lt;&lt; strnigValue1 &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;2. 생성한 후에 초기화 할 수 있다.&quot; &lt;&lt; endl;
    string stringValue2;
    stringValue2 = &quot; C++ 공부하고 있어요&quot;;
    cout &lt;&lt; &quot;stringValue2&quot; &lt;&lt; stringValue2 &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;3. 문자열을 선언할 수 있다.&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;문자열 stringValue3을 선언과 동시에 stringValue2의 값을 복사해서 대입한다.&quot; &lt;&lt; endl;
    string stringValue3(stringValue2);
    cout &lt;&lt; &quot;stringValue3&quot; &lt;&lt; stringValue3 &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 문자열 값 반환 */
    string stringValue4 = &quot;Hello World&quot;;

    cout &lt;&lt; &quot;at(index) : 문자열 index위치의 문자를 반환한다.&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;stringValue4.at(4)&quot; &lt;&lt; stringValue4.at(4) &lt;&lt; endl;         // o
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;문자열[index] : 배열처럼 index위치의 문자를 반환한다. &quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;stringValue4[4] : &quot; &lt;&lt; stringValue4[4] &lt;&lt; endl;            // o
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;front() : 문자열 맨 앞의 문자를 반환한다.&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;stringValue4.front() : &quot; &lt;&lt; stringValue4.front() &lt;&lt; endl;  // H
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;back() : 문자열 맨 끝의 문자를 반환한다.&quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;stringValue4.back() : &quot; &lt;&lt; stringValue4.back() &lt;&lt; endl;    // d
    cout &lt;&lt; endl;

    /**
    문자열 크기 반환에 대해서 알아 봅니다. 최적화 이슈입니다.
    문자열을 크기가 증가할 가능성이 있기 때문에 실제로 가지고 있는 문자열의 길이보다
    더 큰 크기의 메모리를 할당합니다.
    이 크기를 Capacity(용량)라고 하며  Capacity() 함수로 이 크기를 반환할 수 있습니다.
    */
    string stringValue5 = &quot;C와 C++ 공부합니다. !!&quot;;

    cout &lt;&lt; &quot;length() : 문자열의 길이를 반환합니다. &quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;stringValue5.length() : &quot; &lt;&lt; stringValue5.length() &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;size() :  문자열이 사용하고 있는 사이즈를 반환합니다. &quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;stringValue5.size() : &quot; &lt;&lt; stringValue5.size() &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;capacity() : 문자열에  할당된 메모리 크기를 반환합니다. &quot; &lt;&lt; endl;
    cout &lt;&lt; &quot;stringValue5.capacaty() : &quot; &lt;&lt; stringValue5.capacity() &lt;&lt; endl;
    cout &lt;&lt; endl;

    /**
     문자열 클래스에서 제공하는 다양한 문자열 함수들로 문자열을 쉽게 가공할 수 있는
     멤버 함수들에 대해 알아보자

    */
    string stringValue6 = &quot;Red&quot;;
    cout &lt;&lt; &quot;stringValue6 : &quot; &lt;&lt; stringValue6 &lt;&lt; endl;  //Red
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;append() : 문자열 뒤에 문자열을 추가한다.&quot; &lt;&lt; endl;
    stringValue6.append(&quot;Orange&quot;);
    cout &lt;&lt; &quot;stringValue6 : &quot; &lt;&lt; stringValue6 &lt;&lt; endl;  //RedOrange
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;append(\&quot;문자열\&quot;), n, m : 문자열 뒤에 문자열을 인덱스 n부터 m까지 문자를 추가한다.&quot; &lt;&lt; endl;
    stringValue6.append(&quot;Yellow&quot;, 2, 3);
    cout &lt;&lt; &quot;stringValue6 : &quot; &lt;&lt; stringValue6 &lt;&lt; endl;      //  RedOrangello
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;append(n, &#39;문자&#39;) : 문자열 뒤에 문자를 n개 만큼 추가한다.&quot; &lt;&lt; endl;
    stringValue6.append(2, &#39;A&#39;);
    cout &lt;&lt; &quot;stringValue6 : &quot;&lt;&lt; stringValue6 &lt;&lt; endl;       //  RedOrangelloAA
    cout &lt;&lt; endl;

    // 초기화
    stringValue6 = &quot;Red&quot;;
    cout &lt;&lt; &quot;stringValue6 : &quot; &lt;&lt; stringValue6 &lt;&lt; endl;      // Red
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;insert(n, \&quot;문자열\&quot;) : 문자열 index n뒤에 문자열을 추가한다.&quot; &lt;&lt; endl;
    stringValue6.insert(2, &quot;Green&quot;);
    cout &lt;&lt; stringValue6 &lt;&lt; endl;       // ReGreend
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;replace(n, m\&quot;문자열\&quot;) : 문자열 index n부터 m까지 문자을 대체한다.&quot; &lt;&lt; endl;
    stringValue6.replace(2, 3, &quot;Blue&quot;);
    cout &lt;&lt; stringValue6 &lt;&lt; endl;       // ReBlueend
    cout &lt;&lt; endl;

    /** 초기화*/
    stringValue6 = &quot;Red&quot;;
    cout &lt;&lt; stringValue6 &lt;&lt; endl;       // Red
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;push_back() : 문자열 뒤에 &#39;문자&#39;를 추가한다.&quot; &lt;&lt; endl;
    stringValue6.push_back(&#39;B&#39;);
    cout &lt;&lt; stringValue6 &lt;&lt; endl;       // RedB
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;pop_back() : 문자열 뒤에 문자를 제거하기&quot; &lt;&lt; endl;
    stringValue6.pop_back();
    cout &lt;&lt; stringValue6 &lt;&lt; endl;       // Red
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;assign(\&quot;문자열\&quot;) : 문자열 전체를 재할당한다.&quot; &lt;&lt; endl;
    stringValue6.assign(&quot;Blue&quot;);        
    cout &lt;&lt; &quot;stringValue6&quot;&lt;&lt; stringValue6 &lt;&lt; endl;       // Blue
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;erase(n) : 문자열 n부터 지워주기&quot; &lt;&lt; endl;
    stringValue6.erase(3);      
    cout &lt;&lt; &quot;stringValue6&quot; &lt;&lt; stringValue6 &lt;&lt; endl;       // Blu
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;clear() : 문자열을 초기화 하기&quot; &lt;&lt; endl;
    stringValue6.clear();
    cout &lt;&lt; &quot;stringValue6 : &quot; &lt;&lt; stringValue6 &lt;&lt; endl;       // Blu
    cout &lt;&lt; endl;

    // 초기화
    stringValue6 = &quot;Red&quot;;
    cout &lt;&lt; &quot;stringValue6 : &quot; &lt;&lt; stringValue6 &lt;&lt; endl;       // Red
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;erase() : 매개 변수 없이 사용하면 문자열 전체를 지워준다 &quot; &lt;&lt; endl;
    stringValue6.erase();
    cout &lt;&lt; &quot;stringValue6 : &quot; &lt;&lt; stringValue6 &lt;&lt; endl;       // 
    cout &lt;&lt; endl;

    // 초기화
    stringValue6 = &quot;Red&quot;;
    cout &lt;&lt; &quot;stringValue6 : &quot; &lt;&lt; stringValue6 &lt;&lt; endl;       // Red
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;empty() : 문자열이 비어 있는지 확인, 비어 있으면 true 아니면 false 반환&quot; &lt;&lt; endl;
    bool IsEmpty = stringValue6.empty() ? true : false;
    cout &lt;&lt; &quot;IsEmpty : &quot; &lt;&lt; IsEmpty &lt;&lt; endl;
    string strEmpty = stringValue6.empty() ? &quot;true&quot; : &quot;false&quot;;
    cout &lt;&lt; &quot;strEmpty : &quot; &lt;&lt; strEmpty &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;erase() : 문자열 전체 지우기 &quot; &lt;&lt; endl;
    stringValue6.erase();
    IsEmpty = stringValue6.empty() ? true : false;
    cout &lt;&lt; &quot;IsEmpty : &quot; &lt;&lt; IsEmpty &lt;&lt; endl;
    strEmpty = stringValue6.empty() ? &quot;true&quot; : &quot;false&quot;;
    cout &lt;&lt; &quot;strEmpty : &quot; &lt;&lt; strEmpty &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 원할한 테스트를 위해서 초기화를 해 줍니다. */
    stringValue6 = &quot;We learn C++&quot;;
    cout &lt;&lt; &quot;stringValue6 : &quot; &lt;&lt; stringValue6 &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;find() : 문자열에서 찾을 문자열을 찾은 뒤에 인덱스를 반환합니다. 찾지 못하면 -1을 반환합니다. &quot; &lt;&lt; endl;
    /** 현재는 가독성을 위해서 변수에 담아서 매개 변수에 전달합니다. */
    string stringForFind = &quot;learn&quot;;
    int index1 = stringValue6.find(stringForFind);

    /**
    예전에는 코드를 한줄이라도 줄이려고 했습니다. 가독성이 떨어집니다.
    &quot;learn&quot;이라는 문자열을 왜 쓰는지 햇갈립니다. 변수에 담아서 넣어주면 &quot;아 찾을 문자열이구나&quot; 라고 알 수가 있습니다.
    지금은 시스템이 좋아져서 굳이 한 줄 없애지 말고, 의미 있는 변수에 담아서 하는 것이 좋습니다.
    */
    // int index2 = stringValue6.find(&quot;learn&quot;); // 안좋은 습관
    /** 만일 index1이 o보다 크거나 같다면?  찾을 문자열을 찾았다면? */
    if (index1 &gt;= 0)
    {
        cout &lt;&lt; stringForFind &lt;&lt; &quot;를 찾았습니다. &quot; &lt;&lt; index1 &lt;&lt; &quot; index입니다. &quot; &lt;&lt; endl;
    } /** 그렇지 않고 만일 찾을 문자열을 못찾았다면? */
    else
    {
        cout &lt;&lt; stringForFind &lt;&lt; &quot;이 없습니다. &quot; &lt;&lt; endl;
    }
    cout &lt;&lt; endl;

    // if else문은 삼항 연산자로 변경할 수 있다.
    string strResult = (index1 &gt;= 0) ? stringForFind + &quot; 찾았다,&quot; : stringForFind + &quot; 찾지 못했다.&quot;;
    cout &lt;&lt; &quot;strResult : &quot; &lt;&lt; strResult &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;substr() : 문자열 전체를 반환하기.&quot; &lt;&lt; endl;
    string stringValue7 = stringValue6.substr();
    cout &lt;&lt; &quot;stringValue7 : &quot; &lt;&lt; stringValue7 &lt;&lt; endl;       // We learn C++
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;substr(n) : n번째 index부터 문자열 끝까지 반환한다.&quot; &lt;&lt; endl;
    stringValue7 = stringValue6.substr(3);      
    cout &lt;&lt; &quot;stringValue7 : &quot; &lt;&lt; stringValue7 &lt;&lt; endl;      // learn C++
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;substr(n, k) : n번째 index부터 사이즈 k까지 문자열을 반환한다.&quot; &lt;&lt; endl;
    stringValue7 = stringValue6.substr(3, 7);
    cout &lt;&lt; &quot;stringValue7 : &quot; &lt;&lt; stringValue7 &lt;&lt; endl;      // learn C
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;resize(n) : 문자열을 n의 크기로 만들어 줍니다. &quot; &lt;&lt; endl;
    stringValue7.resize(15);
    cout &lt;&lt; &quot;stringValue7 : &quot; &lt;&lt; stringValue7 &lt;&lt; &quot;, size : &quot; &lt;&lt; stringValue7.size() &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;resize(n, &#39;문자&#39;) : 문자열을 n의 크기로 만들고, 넘치면 &#39;문자&#39;로 채웁니다. &quot; &lt;&lt; endl;
    stringValue7.resize(20, &#39;a&#39;);
    cout &lt;&lt; &quot;stringValue7 : &quot; &lt;&lt; stringValue7 &lt;&lt; &quot;, size : &quot; &lt;&lt; stringValue7.size() &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;reserve(n) : n만큼 메모리를 미리 할당합니다. &quot; &lt;&lt; endl;
    stringValue7.reserve(30);
    cout &lt;&lt; &quot;stringValue7 : &quot; &lt;&lt; stringValue7 &lt;&lt; &quot;, capacity : &quot; &lt;&lt; stringValue7.capacity() &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;compare() : 문자열을 비교한다. 문자열이 서로 같으면 0을 반환하고, 다르면 -1을 반환한다.&quot; &lt;&lt; endl;
    // stringValue8 와 stringValue9의 문자열은 같은 문자열일까?
    // 같은 문자열로 처리를 해 줘야한다.
    string stringValue8 = &quot;Korean&quot;;
    string stringValue9 = &quot;KoreaN&quot;; // 문자열은 오타가 날 수 있다.

    // 문법적으로는 맞지만 이렇게 하면 안된다.
    if (stringValue8.compare(stringValue9) == 0)
    {
        cout &lt;&lt; stringValue8 + &quot; 과&quot; &lt;&lt; stringValue9 &lt;&lt; &quot; 는 같은 문자열 입니다.&quot; &lt;&lt; endl;
    }
    else
    {
        cout &lt;&lt; stringValue8 + &quot; 과&quot; &lt;&lt; stringValue9 &lt;&lt; &quot; 는 다른 문자열 입니다.&quot; &lt;&lt; endl;
    }
    cout &lt;&lt; endl;

    // 문자열을 오타가 날 수 있기 때문에 소문자. 대문자 한쪽으로 몰아서 해줘야한다,
    cout &lt;&lt; &quot;toupper(), tolower() : 문자열을 대문자 또는 소문자로 변경해준다.&quot; &lt;&lt; endl;
    string stringValue10 = &quot;we study cpp language&quot;;
    string stringValue11 = &quot;THAT&#39;S REALLY AMAZING&quot;;

    // 대문자는 소문자로 소문자는 대문자로 변경하기
    transform(stringValue10.begin(), stringValue10.end(), stringValue10.begin(), toupper);
    cout &lt;&lt; &quot;stringValue10 : &quot; &lt;&lt; stringValue10 &lt;&lt; endl;

    transform(stringValue11.begin(), stringValue11.end(), stringValue11.begin(), tolower);
    cout &lt;&lt; &quot;stringValue11 : &quot; &lt;&lt; stringValue11 &lt;&lt; endl;
    cout &lt;&lt; endl;

    /** 개발중에 오타가 날 수 있습니다. 이후에 오타는 수정해 줍니다. */
    string stringValue12 = &quot;woRld&quot;;
    string stringValue13 = &quot;WoRlD&quot;;

    transform(stringValue12.begin(), stringValue12.end(), stringValue12.begin(), toupper);
    transform(stringValue13.begin(), stringValue13.end(), stringValue13.begin(), toupper);

    if (stringValue12.compare(stringValue13) == 0)
    {
        cout &lt;&lt; stringValue12 + &quot;과 &quot; &lt;&lt; stringValue13 &lt;&lt; &quot;은 같은 문자열입니다. &quot; &lt;&lt; endl;
    }
    else
    {
        cout &lt;&lt; stringValue12 + &quot;과 &quot; &lt;&lt; stringValue13 &lt;&lt; &quot;은 다른 문자열입니다. &quot; &lt;&lt; endl;
    }
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot; +=, append() : 문자열을 합쳐보기&quot; &lt;&lt; endl;
    string stringValue14 = &quot;&quot;;
    stringValue14 += &quot;We &quot;;
    stringValue14 += &quot;study &quot;;
    stringValue14.append(&quot;C++ &quot;);
    stringValue14 += &quot;programming language.!! &quot;;

    cout &lt;&lt; &quot;stringValue14 : &quot; &lt;&lt; stringValue14 &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;move() : 문자열을 이동할 수 있다.&quot; &lt;&lt; endl;
    string stringValue15 = &quot;We study C++ programming language!!&quot;;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;stringValue15 : &quot; &lt;&lt; stringValue15 &lt;&lt; endl;
    string stringValue16 = move(stringValue15);

    cout &lt;&lt; &quot;stringValue15 : &quot; &lt;&lt; stringValue15 &lt;&lt; endl;
    cout &lt;&lt; &quot;stringValue16 : &quot; &lt;&lt; stringValue16&lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;erase(), remove() : 문자열에서 특정 문자만 제거 할 수 있다,&quot; &lt;&lt; endl;
    string stringValue17 = &quot;We study C++ programming language!!&quot;;
    cout &lt;&lt; &quot;문자열에서 공백과 m을 없애 보자&quot; &lt;&lt; endl;

    stringValue17.erase(remove(stringValue17.begin(), stringValue17.end(), &#39; &#39;), stringValue17.end());
    stringValue17.erase(remove(stringValue17.begin(), stringValue17.end(), &#39;m&#39;), stringValue17.end());

    cout &lt;&lt; &quot;stringValue17 : &quot; &lt;&lt; stringValue17 &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;replace() : 문자열을 일부 교체 할 수 있다.&quot; &lt;&lt; endl;
    string stringValue18 = &quot;We study C++ programming language!!&quot;;
    string findString(&quot;study&quot;);
    string replaceString(&quot;learn&quot;);

    stringValue18.replace(stringValue18.find(findString), findString.length(), replaceString);

    cout &lt;&lt; &quot;stringValue18 : &quot; &lt;&lt; stringValue18 &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;stoi() : string to integer 문자열을 정수로 변경하기&quot; &lt;&lt; endl;
    string stringValue19 = &quot;1024&quot;;
    string stringValue20 = &quot;3.141592&quot;;
    string stringValue21 = &quot;123 korean&quot;;

    // 문자열 &quot;1024&quot;를 stoi() 함수로 정수값 1024로 변환
    int intValue1 = stoi(stringValue19);
    // 문자열 &quot;3.141592&quot;를 stoi() 함수로 소수점 이하는 버려진채 정수값 3으로 변환
    int intValue2 = stoi(stringValue20);
    // 문자열 &quot;123 korean&quot;을 stoi() 함수로 문자열이 제거된 체 정수값 123만 변환
    int intValue3 = stoi(stringValue21);

    cout &lt;&lt; &quot;intValue1 : &quot; &lt;&lt; intValue1 &lt;&lt; &quot;, intValue2 : &quot; &lt;&lt; intValue2 &lt;&lt; &quot;, intValue3 : &quot; &lt;&lt; intValue3 &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;to_string() : 숫자를 문자열로 변경 가능하다.&quot; &lt;&lt; endl;
    int intValue4 = 10;
    string stringValue22 = 10 + &quot;번 반복이 필요하다.&quot;;
    string stringValue23 = intValue4 + &quot;번 반복이 필요하다.&quot;;

    cout &lt;&lt; &quot;stringValue22 : &quot; &lt;&lt; stringValue22 &lt;&lt; endl;
    cout &lt;&lt; &quot;stringValue23 : &quot; &lt;&lt; stringValue23 &lt;&lt; endl;
    cout &lt;&lt; endl;

    string stringValue24 = to_string(10) + &quot;번 필요하다.&quot;;
    string stringValue25 = to_string(intValue4) + &quot;번 필요하다.&quot;;

    cout &lt;&lt; &quot;stringValue24 : &quot; &lt;&lt; stringValue24 &lt;&lt; endl;
    cout &lt;&lt; &quot;stringValue25 : &quot; &lt;&lt; stringValue25 &lt;&lt; endl;
    cout &lt;&lt; endl;

}</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ 형변환 TypeCasting]]></title>
            <link>https://velog.io/@m_jooong/C-%ED%98%95%EB%B3%80%ED%99%98-TypeCasting</link>
            <guid>https://velog.io/@m_jooong/C-%ED%98%95%EB%B3%80%ED%99%98-TypeCasting</guid>
            <pubDate>Tue, 11 Apr 2023 08:35:53 GMT</pubDate>
            <description><![CDATA[<pre><code>#include &lt;iostream&gt;

/** 문자열 관련 라이브러리*/
#include &lt;string&gt;
/** 배열의 사이즈를 가져오기 위한 라이브러리*/
#include &lt;array&gt;

/** C++ 표준 라이브러리*/
using namespace std;

/** 테스트를 위해서 Lion이라는 이름의 클래스를 정의해 주도록 합니다. */
class Lion
{
public:
    // 생성자들을 정의해 준다.
    // : 클론 되는 초기화 리스트로 멤버 변수의 초기화를 하고 있다.
    // 변환 생성자라고도 한다.
    Lion(int eyeSight) : m_EyeSight(eyeSight)
    {
        cout &lt;&lt; &quot; Lion(int) &quot; &lt;&lt; endl;
    }

    Lion(string name) : m_Name(name)
    {
        cout &lt;&lt; &quot;Lion(string)&quot; &lt;&lt; endl;
    }

    Lion(int eyeSight, string name) : m_EyeSight(eyeSight), m_Name(name)
    {
        cout &lt;&lt; &quot;Lion(int, string)&quot; &lt;&lt; endl;
    }

    void SetInfo()
    {
        cout &lt;&lt; &quot;EyeSight : &quot; &lt;&lt; m_EyeSight &lt;&lt; &quot;, Name : &quot; &lt;&lt; m_Name &lt;&lt; endl;
    }


    // int 타입으로의 형병환 연산자 오버로딩이다.
    // 형변환 함수라고도 한다
    // 형변환 연산자 오버로딩은 형변환 연산자를 실행하는 동안에 객체 자체의 값을 바꾸지 않는다는
    // 것을 보장하기 위해서 const 키워드를 붙여 준다.
    operator int()  const
    {
        return m_EyeSight;
    }

    // 문자열 타입으로 형변환 연산자 오버로딩이다.
    // 형변환 함수 (type conversion function)라고도 한다.
    // 형변환 연산자 오버로딩은 형변환 연산자를 실행하는 동안에 객체 자체의 값을 바꾸지 않는다는
    // 것을 보장하기 위해서 const 키워드를 붙여 준다.
    operator string() const
    {
        // to_string() : 매개 변수로 입력받은 값을 문자열로 변경해주는 함수이다.
        string info = to_string(m_EyeSight) + &quot; : &quot; + m_Name;
        return info;
    }

private:
    int m_EyeSight;
    string m_Name;

};

// 전역범위에서 함수를 정의하도록 한다.
// 전역범위는 함수 밖을 의미한다.
void SetMessage(string info)
{
    cout &lt;&lt; &quot;Info : &quot; &lt;&lt; info &lt;&lt; endl;
}

int main()
{
    /**
    형변환은 C언어 스타일의 형변환과 C++ 스타일의 형변환이 있습니다.
    C언어 스타일의 형변환은 2가지 종류가 있습니다.
    1. 묵시적 형변환(Implicit Cast) : 컴파일러가 자동적으로 형변환을 시키는 것을 의미합니다.
    주로 대입연산자에서 발생합니다.
    2. 명시적 형변환(Explicit Cast) : 명시적으로 자료형을 직접 변경해 주는 것을 의미합니다.
    변수 앞에 소괄호() 를 통해서 변경할 수 있습니다.
    형변환은 3가지의 모습을 가지고 있습니다.
    */

    /**
    실수 타입을 정수 타입으로 형변환 합니다.
    실수 타입도 4바이트이고 정수 타입도 4바이트이다. 하지만 실수 타입은 소수점 아래 값이 있기 때문에
    실수 타입이 정수 타입보다 범위가 더 크다.
    양동이물(실수)을 그릇에 넣는 것은 물이 넘칠지언정 상관이 없다.
    형변환은 조심해야한다.
    */
    float floatValue1 = 3.14159265f;
    int intValue1 = floatValue1;        // 묵시적 형변환
    int intValue2 = (int)floatValue1;   // 명시적 형변환
    int intValue3 = int(floatValue1);   // 명시적 형변환

    cout &lt;&lt; &quot;floatValue1 : &quot; &lt;&lt; floatValue1 &lt;&lt; endl;
    cout &lt;&lt; &quot;float to int -&gt; intValue1 : &quot; &lt;&lt; intValue1 &lt;&lt; endl;    // 3
    cout &lt;&lt; &quot;float to int -&gt; intValue2 : &quot; &lt;&lt; intValue2 &lt;&lt; endl;    // 3
    cout &lt;&lt; &quot;float to int -&gt; intValue3 : &quot; &lt;&lt; intValue3 &lt;&lt; endl;    // 3
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 실수 타입을 정수 타입으로 형변환 하면 실수 타입의 소수점 아래 값들이 모두 없어진다.
    int intValue4 = 3.141592f;
    float floatValue4 = 1024;

    cout &lt;&lt; &quot;intValue4 : &quot; &lt;&lt; intValue4 &lt;&lt; &quot; , floatValue4 : &quot; &lt;&lt; floatValue4 &lt;&lt; endl;  // 3, 1024
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    //  평균을 구해보자
    int Math = 90;
    int Kor = 85;
    int Eng = 95;
    int History = 97;

    int Sum = Math + Kor + Eng + History;
    int Average = Sum / 4;

    cout &lt;&lt; &quot;Sum : &quot; &lt;&lt; Sum &lt;&lt; &quot;, Average : &quot; &lt;&lt; Average &lt;&lt; endl;
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 평균이 91.75가 나와야 하는데 , 91이 나온다
    // 정수 / 정수 = 정수
    // 실수 / 정수 = 실수
    // 정수 / 실수 = 실수
    // 실수 / 실수 = 실수

    // 문장 수정
    //int AverageScore = (float)Sum / 4;  // 명시적 형변환, 값이 다르다
    float AverageScore = (float)Sum / 4; // 명시적 형변환

    cout &lt;&lt; &quot;Sum : &quot; &lt;&lt; Sum &lt;&lt; &quot;, Average : &quot; &lt;&lt; AverageScore &lt;&lt; endl;  // 367, 91.75
    cout &lt;&lt; endl;
    cout &lt;&lt; endl;


    // 테스트를 위해 Lion이라는 클래스 정의

    // 생성자 호출로 객체생성을 해준다.
    // 객체 생성은 다양한 방식이 있다.
    Lion lion1 = Lion(10);
    Lion lion2(2);
    Lion lion3 = 25;
    lion3 = 30;                 // 변환 생성자에 의한 묵시적 형변환
    Lion lion4 = (Lion)30;     // 명시적 형변환 

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 문자열을 매개 변수로 가지고 있는 생성자를 호출해 준다.
    // C++은 C언어의 거의 모든 문법을 포함하는데
    // C언어 때는 문자열 타입이 없었다.
    // C언어 때는 블리언 타입도 없었다.
    // 문자열을 기본 자료형이 아니다.
    // 기본 자료형 : 변수를 선언하고 내가 값을 주지 않아도 기본 값이 주어진다.
    //      char, int, long, float, double, bool
    // 문자열 타입은 외부 라이브러리이다. #include &lt;string&gt;
    // 에러가 생기니 문자열 타입으로 명시적 형변환을 해준다.
    //Lion lion5 = &quot;Simba&quot;;   // x
    Lion lion5 = (string)&quot;Simba&quot;;       // 변환 생성자에 의한 명시적 형변환
    Lion lion6 = string(&quot;KingLion&quot;);
    lion6 = (string)&quot;White&quot;;            // 변환 생성자에 의한 명시적 형변환
    lion6 = string(&quot;Black&quot;);

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    // 정수 타입과 문자열 타입을 모두 매개 변수로 가지고 있는 생성자 호출하기
    Lion lion7(30, &quot;Simba&quot;);
    Lion lion8 = { 25, &quot;KingLion&quot; };
    lion8 = { 30, &quot;White&quot; };
    Lion lion9{ 20, &quot;Black&quot; };

    cout &lt;&lt; endl;
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;정수 타입을 매개변수로 가진 생성자로 객체 생성 &quot; &lt;&lt; endl;
    // 문자열 타입을 선언하고 값을 주지 않으면 nullptr이다. 빈 문자열이 아니다
    lion1.SetInfo();
    lion2.SetInfo();
    lion3.SetInfo();
    lion4.SetInfo();
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;문자열 타입을 매개변수로 가진 생성자로 객체 생성&quot; &lt;&lt; endl;
    // 정수 타입에 쓰레기 값이 들어간다.
    lion5.SetInfo();
    lion6.SetInfo();
    cout &lt;&lt; endl;

    cout &lt;&lt; &quot;정수 타입과 문자열 타입을 매개 변수로 가진 생성자로 객체 생성&quot; &lt;&lt; endl;
    lion7.SetInfo();
    lion8.SetInfo();
    lion9.SetInfo();
    cout &lt;&lt; endl;

    // 변환 생성자로 정수값을 Lion타입으로 형변환 해보자
    // 반대로 Lion타입을 정수값으로 형변환 가능할까
    // 에러가 나면서 변환이 되지 않는다.
    //int intValue5 = lion9;          // x 
    //int intValue6 = (int)lion9;     // x   명시적 형변환

    // 형변환 자체도 연산자이다 형변환 연산자이다.
    // 연산자 오버로딩으로 해결할 수 있다.
    // int 타입으로 형변환 연산자 오버로딩을 해 준다.
    // 형변환 함수(type conversion)이라고 한다.
    int intValue5 = lion9;          // 암묵적(묵시적) 형변환
    int intValue6 = (int)lion9;     // 명시적 형변환
    cout &lt;&lt; endl;

    // 문자열 타입을 Lion타입으로 형변환 하기
    // 반대로 Lion타입을 문자열 타입으로 형변환하기   x
    //string strLion8 = lion8;              // x
    //string strLion9 = (string)lion9;      // x 
    cout &lt;&lt; endl;

    // 연산자 오버로딩을 해결 할 수 있다
    // 문자열 타입으로의 형변환 연산자 오버로딩을 해 준다.
    // 형변환 연산자 오버로딩을 형변환 함수 (type conversion function)라고도 한다.
    string strLion8 = lion8;            // 암묵정(묵시적) 형변환
    string strLion9 = (string)lion9;    // 명시적 형변환

    // 다양한 방법으로 Lion 객체를 문자열로 변경해본다.
    // Lion객체의 생성자 중 하나가 문자열을 매개 변수로 가지고 객체를 생성하기 때문이다
    // 반대로 객체가 가지고 있는 문자열을 문자열 변수에 넣어주는 것이다.
    string strLion = lion8;

    // 지금까지는 C++에서 제공하는 기본적인 형변환이다
    // 이후 상속에서의 형변환에 대해 알아보자.

    // 객체지향 언어의 4대 특징
    // 1. 캡슐화 : 멤버 변수의 보호
    // 2. 상속
    // 3. 다향성 : 가상함수와 동적 바인딩
    // 4. 추상화 : 순수가상함수와 추상클래스

    // SetMessage 함수는 매개변수로 문자열 타입이다.
    // 따라서 Lion 객체가 문자열로 묵시적 형변환이 된다고 볼 수 있다.
    SetMessage((string)lion8);                              // 명시적 형변환
    cout &lt;&lt; &quot;(string)lion8 &quot; &lt;&lt; (string)lion8 &lt;&lt; endl;      // 명시적 형변환
    cout &lt;&lt; endl;

    SetMessage(lion8);                                      // 묵시적 형변환
    cout &lt;&lt; &quot;lion8 : &quot; &lt;&lt; lion8 &lt;&lt; endl;                      
    cout &lt;&lt; endl;

    string strLion8 = lion8;                                // 묵시적 형변환 
    cout &lt;&lt; &quot;strLion8 : &quot; &lt;&lt; endl;
    cout &lt;&lt; endl;

}
</code></pre>]]></description>
        </item>
        <item>
            <title><![CDATA[C++ 상수 Const]]></title>
            <link>https://velog.io/@m_jooong/C-%EC%83%81%EC%88%98-Const</link>
            <guid>https://velog.io/@m_jooong/C-%EC%83%81%EC%88%98-Const</guid>
            <pubDate>Thu, 06 Apr 2023 07:05:57 GMT</pubDate>
            <description><![CDATA[<pre><code>#include &lt;iostream&gt;

/** 문자열 관련 라이브러리*/
#include &lt;string&gt;

/** C++ 표준 라이브러리 사용합니다. */
using namespace std;

/**
const 변수는 반드시 선언시 초기화를 해야 하며 초기화가 되지 않으면 컴파일 에러가 발생합니다.
그래서 const의 멤버 변수를 const로 선언시에는 반드시 초기화 리스트로 초기화 해야 합니다.

테스트를 위해서 Lion이라는 이름의 클래스와 Tiger라는 이름의 클래스를 정의해 주도록 합니다.
*/

/**
Lion클래스의 num 멤버 변수는 생성자에서 초기화 리스트로 1로 초기화를 하고 있는데
이는 const int num = 1; 과 동일한 의미입니다.
*/
class Lion
{
    const int num;
    /**
    클래스 이름과 동일한 함수가 생성자 함수입니다.
    생성자 함수는 객체를 생성하면서 멤버 변수의 초기화를 담당합니다.
    : (콜론) 뒤가 초기화 리스트로 멤버 변수를 초기화 하고 있습니다.
    */
    Lion() : num(1)  // const int num = 1;
    {

    }
};

/**
Tiger클래스의 num 멤버 변수는 생성자에서 초기화 리스트를 사용하지 않고 함수 내부에서 초기화를 시도하고 있습니다.
이것은 초기화가 아니라 const int num; 으로 const변수를 선언한 다음에 num = 1;을 시도하는 것입니다.
따라서 const 변수를 1로 수정한다는 의미이므로 컴파일 에러가 발생합니다.

따라서 주석처리 해 주도록 합니다.
*/
class Tiger
{
    const int num;

    //Tiger()
    //{
    //    // num = 1; //  컴파일 에러가 납니다. 초기화 리스트로 초기화를 해 주지 않아서 에러가 납니다. 
    //    // const int num;
    //    // num = 1;
    //}
};

/**
전처리 지시자는 #define, #include, #endif, #pragma등과 같이 #으로 시작하는 문구를 말하는데
여기서 #define은 매크로라고 하면 이를 이용해서 상수를 정의할 수 있습니다.
매크로를 이용해서 상수를 정의해 주도록 합니다.
*/
#define WIDTH 3
#define HEIGHT 4

/**
enum상수에 대해서 알아 봅니다.
enum상수를 정의해 주도록 합니다.
*/
enum EWidthHeight
{
    Width = 3,
    Height = 5,

    /**
    enum타입은 단점이 있습니다.
    정수형만 가능하기 때문에 PI = 3.14, 와 같은 상수의 선언은 불가능합니다.
    */
    // PI = 3.14, // (X)
};

/**
상수는 함수의 매개 변수와 함께 사용하는 경우가 많습니다.

매개변수 : Parameter, 인수(Argument)

테스트를 위해서 ConstParameter라는 이름의 함수를 정의해 주도록 합니다.
*/

/**
함수를 호출하는 사람에게 intValue변수의 값을 변경하지 말라고 하는 것입니다.
intValue변수의 값을 변경하지 못합니다.
*/
void ConstParameter(const int intValue)
{
    cout &lt;&lt; &quot;intValue : &quot; &lt;&lt; intValue &lt;&lt; endl;

    // intValue = 10; // (X)
}

/**
반환형이 있는 함수에 const키워드가 붙으면 어떻게 될까요?
테스트를 위해서 Animal이라는 이름의 클래스를 정의해 주도록 합니다.
*/
class Animal
{
private:
    int m_EyeSight = 100;
public:
    /** 반환형이 있는 함수에 const키워드를 붙이면 멤버 변수의 값을 변경하지 못한다는 것을 보장합니다.*/
    int GetEyeSight() const;
};

int main()
{
    /**
    const는 constant의 약자로 사전적 의미로 &quot;상수&quot;를 의미합니다.
    말 그대로 const는 그 대상을 변경하지 않는 &quot;상수&quot;를 의미합니다.

    const 위치에 따라 의미하는 바는 완전히 달라집니다.
     1. 자료형 앞에 상수가 있다,
     2. 자료형과 변수 이름 사이에 상수가 있다
     3. 자료형 앞에도 자료형과 변수 이름 사이에도 상수가 있다,
     4. 매개 변수에 상수가 있다.
     5. 함수 끝에 상수가 있다
    */

    /**
    C++ 문법중에서 자연스럽게, 디테일하게 알아야 하는 문법적 요소
    1. 포인터  Pointer
    2. 참조자  Reference
    3. 상수   Const
    4. 동적할당 Dynamic Memory Allocation
    5. 스마트 포인터
        . unique_ptr : 객체의 유일한 소유권을 가지는 스마트 포인터
        . shared_ptr : 객체간의 공유가 가능한 스마트 포인터
        . weak_ptr   : shared_ptr의 고질적인 문제인 순환참조 문제를 해결한
                    약한 참조의 스마트 포인터
    */

    /**
    일반 변수의 경우 const키워드가
    자료형 앞에 붙던지
    자료형과 변수 이름 사이에 붙던 결과는 동일하다.

    보통 const 위치가 맨 앞인 첫 번째 형식을 많이 사용합니다.
    다음과 같이 선언하면 intValue1과 intValue2는 변할 수 없는 상수가 됩니다.
    또한 함수의 반환형이나 매개변수가 const 변수형일 때도 동일한 의미입니다.
    */
    /** 자료형 앞에 const 키워드를 붙입니다. */
    const int intValue1 = 1;
    // intValue1 = 2; // (X)

    /** 자료형과 변수 이름 사이에 const 키워드를 붙입니다. */
    int const intvalue2 = 1;
    // intValue2 = 2; // (X)

    /**
    const 변수는 반드시 선언시 초기화를 해야 하며 초기화가 되지 않으면 컴파일 에러가 발생합니다.
    그래서 const의 멤버 변수를 const로 선언시에는 반드시 초기화 리스트로 초기화 해야 합니다.

    테스트를 위해서 Lion이라는 이름의 클래스와 Tiger라는 이름의 클래스를 정의해 주도록 합니다.
    */

    // 변수의 종류
    // 1. 멤버 변수 : 클래스 안에서 선언된 변수이다. 클래스는 멤버 함수와 멤버 변수로 구성된다
    // 2. 매개 변수 : 함수에 전달해주는 변수이다. 파라미터, 인수(Argument)라고 한다.
    // 3. 로컨 변수 : 함수 안에서 선언된 변수이다.
    // 4. 전역 변수 : 전역 공간에서 선언된 변수이다. 어디서든 접근이 가능하다. global 키워드가 붙는다.
    // 5. 정적 변수 : 객체가 생성되기 전에 이미 메모리에 있는 변수이다. Static 키워드가 붙는다.

    /**
    포인터와 const를 사용할 때는 세가지 경우가 있습니다.
    첫번째, const위치가 맨 앞에 있으면서 포인터 변수가 가리키는 값에 대해서 상수화 시키는 경우입니다.
    */
    int intValue3 = 1;

    /**
    int포인터 타입의 intPtr1이라는 이름의 포인터 변수를 선언했습니다.
    intValue3변수의 주소값을 intPtr1 포인터 변수에 대입함으로써 초기화했습니다.
    그리고 *intPtr1(intPtr1포인터 변수가 가리키는 값)을 상수화 했습니다.
    */
    const int* intPtr1 = &amp;intValue3;

    /**
    intPtr1 포인터 변수가 가리키는 값을 상수화 했습니다.

    *intPtr1 = 2;는 intPtr1이 const 변수이기 때문에 컴파일 에러가 발생하지만
    intValue3 = 2; 는 intValue3가 non-const(비-상수)변수이기 때문에 정상입니다.
    즉, 포인터 변수가 가리키는 intValue3 자체가 상수화가 되는 것이 아닙니다.
    */
    // *intPtr1 = 2; // (X) 컴파일 에러
    intValue3 = 2;

    /** 두번째는 const 위치가 자료형과 변수 이름 사이에 있으면서 포인터 변수 자체를 상수화 시키는 경우입니다. */
    int intValue4 = 1;
    int intValue5 = 2;

    /**
    int포인터 타입의 intPtr2라는 이름의 포인터 변수를 선언했습니다.
    intValue4변수의 주소값을 intPtr2포인터 변수에 대입함으로써 초기화 했습니다.
    그리고 intPtr2포인터 변수의 주소값 자체를 상수화 했습니다.
    */
    int* const intPtr2 = &amp;intValue4;

    /**
    포인터 변수란 대상의 주소값을 저장하는 변수입니다.
    즉 위의 자기 자신의 주소를 상수화 시키는 것이기 때문에 intValue5의 주소값으로 변경하려고 하면
    컴파일 에러가 발생합니다.
    */
    // intPtr2 = &amp;intValue5; // (X) 컴파일 에러가 납니다. 

    /**
    세번째는 자료형 앞에 const키워가 있고, 자료형과 변수 이름 사이에도 const키워드가 있습니다.
    */
    int intValue6 = 1;
    int intValue7 = 2;

    /**
    int포인터 타입의 intPtr3라는 이름의 포인터 변수를 선언했습니다.
    intValue6의 주소값을 intPtr3 포인터 변수에 대입함으로써 초기화 했습니다.
    자료형 앞에 const키워드를 두어서 포인터 변수가 가리키는 값을 상수화했습니다.
    자료형과 변수 이름 사이에 const키워드를 두어서 포인터 주소값 자체를 상수화 했습니다.
    */
    const int* const intPtr3 = &amp;intValue6;

    // *intPtr3 = 2; // (X) 컴파일 에러
    // intPtr3 = &amp;intValue7; // (X) 컴파일 에러

    /**
    C언어 때는 일반변수와 포인터 변수가 있습니다.
    C++ 언어에서는 참조자를 지원합니다.
    */

    /**
    C++에서는 참조자(Reference)가 있기 때문에 포인터를 사용할 일이 그리 많지 않습니다.
    일반 변수
    포인터 변수
    참조자 변수보다는 그냥 참조자라고 합니다.

    만약 포인터를 상수화 시키려면 const int* const ptr = &amp;num; 와 같이 다소 번거롭고
    가독성이 떨어지는 코드가 되겠지만 ,
    참조자는 애초에 참조하는 대상을 변경할 수 없는 특징이 있기 때문에
    const int&amp; ref = num; 의 형태가 됩니다.
    */

    /**
    C/C++을 공부하다 보면 다양한 방식의 상수 선언 법을 알게 됩니다.
    #define, const, enum 세가지 상수 선언 방식에 대해서 알아 봅니다.
    */

    /**
    #define 상수 (매크로)에 대해서 알아 봅니다.

    소스코드를 빌드한다는 것은
    1. 전처리(Preprocess)
    2. 컴파일(Compile)
    3. 어셈블(Assemble)
    4. 링크(Link)
    라는 과정을 거쳐서 실행파일(.exe)를 만들게 됩니다.

    첫 과정인 전처리기(Preprocessor)가 소스코드를 쪽 읽어서 전처리 지시자(Preprocess Directive)로
    처리된 부분을 해석하여 소스코드를 변형시켜주는 것을 의미합니다.
    */

    /**
    전처리 지시자는 #define, #include, #endif, #pragma등과 같이 #으로 시작하는 문구를 말하는데
    여기서 #define은 매크로라고 하면 이를 이용해서 상수를 정의할 수 있습니다.
    매크로를 이용해서 상수를 정의해 주도록 합니다.
    */

    /** 문장을 추가해 줍니다. */
    int intArr1[WIDTH][HEIGHT];

    /** const 상수에 대해서 알아 봅니다. */
    const int width = 3;
    const int height = 5;
    int intarr2[width][height];

    /**
    enum상수에 대해서 알아 봅니다.
    enum상수를 정의해 주도록 합니다.
    */

    /** 문장을 추가해 줍니다. */
    int intArr3[EWidthHeight::Width][EWidthHeight::Height];

    /**
    상수는 함수의 매개 변수와 함께 사용하는 경우가 많습니다.

    매개변수 : Parameter, 인수(Argument)

    테스트를 위해서 ConstParameter라는 이름의 함수를 정의해 주도록 합니다.
    */

    /**
    1. 자료형 앞에 const키워드가 붙어서 포인터 변수가 가리키는 값을 상수화 합니다.
    2. 자료형과 변수 이름 사이에 const키워드가 붙어서 포인터 변수의 주소 자체를 상수화 합니다.
    3. 자료형 앞에, 그리고 자료형과 변수이름 사이에 const키워드가 붙어서 포인터 변수가 가리키는 값을
        상수화 하고, 포인터 변수의 주소 자체를 상수화 합니다.
    4. 함수의 매개 변수에 const키워드를 붙여서 매개 변수의 값이 변경되지 않는다는 것을 보장합니다.
        협업하는 프로그래머의 있을 수 있는 실수를 방지합니다.
    5. 반환형이 있는 함수에 const키워드를 붙여서 멤버 변수의 값이 변경되지 않는다는 것을 보장합니다.
        협업하는 프로그래머의 있을 수 있는 실수를 방지합니다.
    */

    /**
    상수에는 2가지 상수가 존재합니다.

    1. 컴파일 시간에 알 수 있는 살수를 컴파일 시간 상수(Compile time constant)
    2. 실행시간에 알 수 있는 상수를 런타임 상수(Runtime constant)

    constexpr, const는 둘다 상수를 만들어주는 키워드 이지만

    const는 컴파일 시간, 런타임 시간 상수 모두 만들 수 있고,
    constexpr은 컴파일 시간 상수만 만들수 있습니다.
    */
    int intValue8 = 10;

    const int intValue9 = 20;       // 컴파일 시간 상수
    const int intValue10 = intValue8; // 런타임 상수

    constexpr int intValue11 = 20;  // 컴파일 시간 상수
    // constexpr int intValue12 = intValue8; // (X) 런타임 상수

    /** 지금까지 보았던 모든 포인터는 상수(const)가 아닌 값을 가리키는 비-상수(non-const) 포인터입니다. */
    int intValue12 = 5;
    int* intPtr12 = &amp;intValue12;
    *intPtr12 = 6;

    /**
    값이 상수인 경우는 어떻게 될까요?
    컴파일이 되지 않습니다. 상수 변수는 값을 변경할 수 없습니다.
    만일 상수가 아닌 포인터가 상수 변수를 가리킨 다음에 역참조 연산자로 값을 변경할 수 있다면
    const 의 의도를 위반하게 되므로 상수가 아닌 포인터는 상수 변수를 가리킬 수 없습니다.
    */
    const int intValue13 = 5;
    // int* intPtr13 = &amp;intValue13; // (X)
    // *intPtr13 = 6;          // (X)

    /**
    int* intPtr13 = &amp;intValue13;
    상수를 가리키는 포인터는 상수 변수의 주소를 가리키는 비-상수 포인터입니다.
    상수 변수에 대한 포인터를 선언하려면 자료형 앞에 const키워드를 붙이면 됩니다.
    */
    const int intValue14 = 5;
    const int* intPtr14 = &amp;intValue14;
    // *intPtr14 = 6; // (X)

    /**
    상수 변수에 대한 포인터는 상수가 아닌 변수를 가리킬 수 있습니다.
    상수 변수에 대한 포인터는 변수가 초기에 const로 정의되어 있는지에 관계 없이 포인터를 통해
    접근할 때 변수를 상수로 취급합니다.
    */
    int intValue15 = 5;
    const int* intPtr15 = &amp;intValue15;
    intValue15 = 6;
    // *intPtr15 = 10; // (X)

    /** 상수를 가리키는 포인터는 상수를 가리킬 뿐, 상수 자체가 아니므로 다른 값을 가리킬 수 있습니다. */
    int intValue17 = 5;
    const int* intPtr17 = &amp;intValue17;
    int intValue18 = 6;
    intPtr17 = &amp;intValue18;

    /**
    포인터 자체를 상수로 만들 수 있습니다. 상수 포인터는 초기화 후에 가리키는 주소를 변경할 수 없는 포인터입니다.
    포인터 자체를 상수화하려면 자료형 뒤에 const 키워드를 붙이면 됩니다.
    */
    int intValue19 = 5;
    int* const intPtr19 = &amp;intValue19;
    // intPtr19 = &amp;intValue18; // (X)

    /**
    일반 상수 변수와 마찬가지로 상수 포인터는 선언시 초기화해야 합니다.
    즉, 상수 포인터는 항상 같은 주소를 가리킵니다.
    */
    int intValue20 = 5;
    int intValue21 = 6;
    int* const intPtr20 = &amp;intValue20;
    // intPtr20 = &amp;intValue21; // (X)

    /** 포인터가 상수일뿐, 가리키는 변수는 상수가 아니므로 포인터를 역참조하여 값을 변경하는 것은 가능합니다. */
    int intValue22 = 5;
    int* const intPtr22 = &amp;intValue22;
    *intPtr22 = 6;

    /**
    자료형 앞뒤에 const키워드를 사용해서 상수를 가리키는 상수  포인터를 선언할 수 있습니다.
    상수를 가리키는 상수 포인터는 다른 주소를 가리키도록 수정할 수 없으며, 역참조 연산자를 통해 값을
    수정할 수도 없습니다.
    */
    int intValue23 = 5;
    const int* const intPtr23 = &amp;intValue23;
    // *intPtr23 = 6; // (X)

    /**
    반환형이 있는 함수에 const키워드가 붙으면 어떻게 될까요?
    테스트를 위해서 Animal이라는 이름의 클래스를 정의해 주도록 합니다.
    */
}

int Animal::GetEyeSight() const
{
    /**
    반환형이 있는 함수에 const키워드를 붙이면 멤버 변수의 값을 변경하지 못한다는 것을 보장합니다.
    협업하는 프로그래머의 있을 수 있는 실수를 원천봉쇄합니다.
    */
    // m_EyeSight = 200; // (X)
    return m_EyeSight;
}
</code></pre>]]></description>
        </item>
    </channel>
</rss>