<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Smilejiro log</title>
    <link>https://smilejiro.tistory.com/</link>
    <description>2025.08.18 ~ ing</description>
    <language>ko</language>
    <pubDate>Sat, 4 Apr 2026 12:47:07 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>Smilejiro</managingEditor>
    <image>
      <title>Smilejiro log</title>
      <url>https://tistory1.daumcdn.net/tistory/6921170/attach/91c77162f6a342cd8925575887ecb14f</url>
      <link>https://smilejiro.tistory.com</link>
    </image>
    <item>
      <title>[Arch&amp;amp;OS] 컴퓨터 하드웨어 구성</title>
      <link>https://smilejiro.tistory.com/46</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;컴퓨터 프로그램은 소프트웨어적 개념이지만, 실제로는 하드웨어 위에서만 동작할 수 있다.&lt;br /&gt;이번 글에서는 CPU, 메모리, 버스, 레지스터와 같은 컴퓨터 하드웨어의 핵심 구성 요소들을 정리하고, 각 요소가 어떻게 협력하여 하나의 프로그램을 실행시키는지 살펴보고자한다.&lt;/blockquote&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image (1).png&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;797&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2QO3v/btsPV1hPPDf/saJWkKKPkKwKPWyD9jPteK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2QO3v/btsPV1hPPDf/saJWkKKPkKwKPWyD9jPteK/img.png&quot; data-alt=&quot;출처 : 뇌자극 시스템 프로그래밍&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2QO3v/btsPV1hPPDf/saJWkKKPkKwKPWyD9jPteK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2QO3v%2FbtsPV1hPPDf%2FsaJWkKKPkKwKPWyD9jPteK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;575&quot; height=&quot;375&quot; data-filename=&quot;image (1).png&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;797&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;출처 : 뇌자극 시스템 프로그래밍&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 메인 메모리(Main Memory)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;메인 메모리는 우리가 흔히 말하는 RAM을 말한다.&lt;/li&gt;
&lt;li&gt;하드디스크에 저장된 프로그램은 더블 클릭을 통해 실행되는데, 이때 프로그램이 직접 실행되는 것이 아니라 메인 메모리로 적재된 후 실행된다.&lt;/li&gt;
&lt;li&gt;따라서 메인 메모리는 단순한 저장 공간이 아니라, 프로그램 실행을 위한 핵심 무대라 할 수 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프로그램은 하드디스크에만 있으면 '죽어 있는' 상태이고, &lt;b&gt;메인 메모리에 올라와야만 '살아 움직이는' 것이다.&lt;/b&gt;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 입출력 버스(Input/Output Bus)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴퓨터의 구성 요소들은 데이터를 주고받아야 한다. 이때 사용되는 경로가 바로 버스(Bus)이다.&lt;/li&gt;
&lt;li&gt;버스는 기능에 따라 주소 버스, 데이터 버스, 컨트롤 버스로 나뉜다.&lt;/li&gt;
&lt;li&gt;CPU, 메모리, 하드디스크 등 모든 하드웨어는 이 버스를 통해 연결되어 통신한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 하드디스크의 데이터를 메인 메모리로 옮길 수도 있고, 메인 메모리의 데이터를 CPU가 읽을 수도 있는 것이다. 이러한 연결성을 보장하는 것이 바로 &lt;b&gt;버스 시스템&lt;/b&gt;이다&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. ALU(Arithmetic Logic Unit)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 &quot;프로그램은 CPU에서 실행된다&quot;라고 말한다. 그러나 CPU 안에서도 실제 연산을 담당하는 핵심 블록은 ALU다.&lt;/li&gt;
&lt;li&gt;ALU는 산술 연산(+, - 등)과 논리 연산(AND, OR 등)을 처리한다.&lt;/li&gt;
&lt;li&gt;복잡해 보이는 소프트웨어 로직도 CPU 입장에서 보면 결국 이 단순한 연산들의 조합으로 이루어진다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 컨트롤 유닛(Control Unit)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;컴파일된 실행 파일에는 CPU가 수행할 명령어 집합이 들어 있다.&lt;/li&gt;
&lt;li&gt;하지만 ALU는 이 명령어를 직접 해석할 수 없다.&lt;/li&gt;
&lt;li&gt;이때 컨트롤 유닛이 명령어를 해석하고, 그 결과에 따라 ALU나 다른 CPU 내부 블록에 적절한 제어 신호를 보낸다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 컨트롤 유닛은 단순한 보조 장치가 아니라, 명령어를 해석하여 CPU 동작을 총괄하는 지휘관 역할을 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5. 레지스터(Register Set)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;덧셈 명령어가 도착했다면, 피연산자 숫자는 어디에 저장될까?&lt;/li&gt;
&lt;li&gt;새로운 연산 요청이 들어올 때까지 데이터를 임시 저장하는 공간이 필요하다.&lt;/li&gt;
&lt;li&gt;이를 위해 CPU 내부에는 레지스터라는 초고속 저장 장치가 존재한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;레지스터는 보통 32비트, 64비트 크기를 가지며, CPU 종류에 따라 다양한 개수와 용도를 가진다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉, 메인 메모리가 프로그램의 '큰 무대'라면, 레지스터는 ALU 바로 옆에서 데이터를 직접 전달하는 '작은 대기실'이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;6. 버스 인터페이스(Bus Interface)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;모든 하드웨어는 I/O 버스를 통해 연결되어 있다.&lt;/li&gt;
&lt;li&gt;하지만 CPU가 버스를 사용하려면, 단순히 이러한 버스를 연결하는 것만으로는 부족하다.&lt;/li&gt;
&lt;li&gt;데이터를 주고 받는 방식(프로토콜)을 이해해야 하는데, 이 역할을 담당하는 것이 바로 버스 인터페이스다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CPU는 버스 인터페이스를 통해 내부 데이터를 버스로 내보내거나, 버스를 통해 들어오는 외부 데이터를 받아들인다.&lt;br /&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;즉,&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;b&gt;버스 인터페이스는 CPU와 외부 세계를 이어주는 번역기&lt;/b&gt;라 할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;image (2).png&quot; data-origin-width=&quot;1462&quot; data-origin-height=&quot;296&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/b9ticU/btsPV2gMuJQ/bOf0POTacJGlkq6SwM6xtK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/b9ticU/btsPV2gMuJQ/bOf0POTacJGlkq6SwM6xtK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/b9ticU/btsPV2gMuJQ/bOf0POTacJGlkq6SwM6xtK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2Fb9ticU%2FbtsPV2gMuJQ%2FbOf0POTacJGlkq6SwM6xtK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;869&quot; height=&quot;176&quot; data-filename=&quot;image (2).png&quot; data-origin-width=&quot;1462&quot; data-origin-height=&quot;296&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;추가. 클럭 신호(Clock Pulse)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;클럭 신호는 CPU의 구성 요소는 아니지만, 컴퓨터 동작에 필수적이다.&lt;/li&gt;
&lt;li&gt;연산 장치와 출력 장치가 서로 다른 속도로 동작하면 데이터 충돌이나 중복 출력이 발생할 수 있다.&lt;/li&gt;
&lt;li&gt;이를 방지하기 위해 클럭 신호가 모든 장치의 속도를 동기화 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;예를 들어, 연산 장치가 지나치게 빠르면 데이터가 덮어씌워지고, 출력 장치가 빠르면 같은 데이터가 반복 출력될 수 있다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;그래서 보통 속도가 더 느린 장치를 기준으로 클럭이 맞춰진다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;PS. 중학생때 개별 부품들을 직접 조립하여 PC를 맞춘 경험이 있다. &lt;br /&gt;성능 향상을 위해 CPU 오버클럭을 공부하던 중, 오버 클럭을 잘못 시도하다가 문제가 발생한 사례들을 보면서 포기했었는데...&lt;br /&gt;실제 오버클럭을 시도하다가 CPU가 불안정해지는 이유도 이러한 클럭 신호의 기능을 마비시킬 수 있기 때문이라 한다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;정리&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;컴퓨터 하드웨어는 다음과 같은 흐름으로 협력한다.&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;프로그램은 하드디스크에서 메인 메모리로 올라온다.&lt;/li&gt;
&lt;li&gt;CPU는 버스를 통해 데이터를 읽어들이고, 컨트롤 유닛이 명령어를 해석한다.&lt;/li&gt;
&lt;li&gt;필요한 연산은 ALU에서 수행되고, 중간 데이터는 레지스터에 임시 저장된다.&lt;/li&gt;
&lt;li&gt;버스 인터페이스와 I/O 버스를 통해 CPU는 외부 장치와 소통한다.&lt;/li&gt;
&lt;li&gt;이 모든 과정은 클럭 신호에 의해 동기화 된다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;결국, 우리가 작성한 프로그램은 이처럼 하드웨어 구성 요소 간의 정밀한 협력 덕분에 실행될 수 있는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-style=&quot;style6&quot; data-ke-type=&quot;horizontalRule&quot; /&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;기존 노션에 작성된 글을 블로그로 그대로 이전하려하니 부분 부분 아쉬운게 보여 리마인드 하며, 사실상 재작성하고 있다. ㅜ&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;많은 양이라 부담스럽긴 하지만, 최대한 요약하여 꾸준히 이전 작업을 해야겠다..!&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;되도록이면 지나치게 단순한 이론 파트는 제외하고, 쟁점이 되거나 기술적으로 매우 중요한 개념들을 위주로 작성할 예정이다.&lt;/p&gt;</description>
      <category>Study/Architecture &amp;amp; OS</category>
      <author>Smilejiro</author>
      <guid isPermaLink="true">https://smilejiro.tistory.com/46</guid>
      <comments>https://smilejiro.tistory.com/46#entry46comment</comments>
      <pubDate>Tue, 19 Aug 2025 14:02:37 +0900</pubDate>
    </item>
    <item>
      <title>[C++] 다형성, 가상 함수</title>
      <link>https://smilejiro.tistory.com/45</link>
      <description>&lt;blockquote data-ke-style=&quot;style2&quot;&gt;본문은 C++에서의 다형성의 정의, 시점에 따른 구분, 가상 함수의 동작 원리, 가상 함수의 장점/단점에 대해 학습한 내용을 기반으로 작성되었습니다. (오류가 있다면 댓글을 달아주세요.)&lt;/blockquote&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&amp;nbsp;&lt;/h2&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;1. 다형성(&lt;span style=&quot;background-color: #ffffff; text-align: start;&quot;&gt;Polymorphism&lt;/span&gt;)&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;같은 이름의 함수나 연산자에 대해 다른 동작을 하도록 하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;다형성은 &lt;b&gt;정적 다형성(Compile Time)&lt;/b&gt;, &lt;b&gt;동적 다형성(Run Time)&lt;/b&gt;으로 구분된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;정적 다형성&lt;/b&gt;&lt;b&gt;(Compile-Time)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;함수 호출과 해당 함수 정의 간의 연결은 &lt;b&gt;컴파일 되는 시점에 결정&lt;/b&gt;된다. 컴파일 타임 다형성은 모든 결정이 컴파일 시점에 이루어지므로 &lt;b&gt;실행 속도가 빠르다&lt;/b&gt;는 장점이 있지만, 일단 컴파일 되면 동작이 고정되므로 &lt;b&gt;유연성이 떨어진다&lt;/b&gt;.&lt;/li&gt;
&lt;li&gt;컴파일 타임 다형성의 주요 메커니즘으로는 &lt;b&gt;함수 오버로딩&lt;/b&gt;과 &lt;b&gt;연산자 오버로딩&lt;/b&gt;이 있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;동적 다형성(Run-Time)&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;b&gt;런타임에 객체의 실제 타입을 확인&lt;/b&gt;한 후, 어떤 함수 호출이 해당 객체와 연결되어야하는지를 결정한다. 즉, 함수 호출의 결정이 프로그램 실행 중에 이루어진다. 런타임 다형성은 컴파일 타임 다형성에 비해 약간의 &lt;b&gt;성능 오버헤드가 발생&lt;/b&gt;할 수 있지만, 객체의 실제 타입에 따라 다른 동작을 수행할 수 있는 &lt;b&gt;유연성과 확장성&lt;/b&gt;을 제공한다. 이는 복잡하고 확장 가능한 시스템에서 특히 중요한데, 객체의 정확한 타입이 런타임까지 알려지지 않는 시나리오에 필수적인 동적 동작을 가능하게 한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; &lt;span data-token-index=&quot;0&quot;&gt;컴파일 타임 다형성 vs 런타임 다형성 비교&lt;/span&gt; &lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;아래의 표는 컴파일 타임 다형성과 런타임 다형성 간의 핵심적인 차이점을 요약한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100%;&quot; border=&quot;1&quot; data-ke-align=&quot;alignLeft&quot; data-ke-style=&quot;style12&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;구분&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.2326%;&quot;&gt;&lt;b&gt;컴파일 타임 다형성 (Compile-Time Polymorphism)&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 41.8605%;&quot;&gt;&lt;b&gt;런타임 다형성 (Run-Time Polymorphism)&lt;/b&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;정의&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.2326%;&quot;&gt;컴파일 시점에 함수/연산자 호출이 결정&lt;/td&gt;
&lt;td style=&quot;width: 41.8605%;&quot;&gt;런타임 시점에 실제 객체 타입에 따라 함수 호출 결정&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;다른 이름&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.2326%;&quot;&gt;정적 다형성 (Static Polymorphism), 초기 바인딩 (Early Binding)&lt;/td&gt;
&lt;td style=&quot;width: 41.8605%;&quot;&gt;동적 다형성 (Dynamic Polymorphism), 지연 바인딩 (Late Binding)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;바인딩 시점&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.2326%;&quot;&gt;컴파일 시점 (Compile Time)&lt;/td&gt;
&lt;td style=&quot;width: 41.8605%;&quot;&gt;런타임 시점 (Runtime)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;성능&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.2326%;&quot;&gt;빠름 (Faster)&lt;/td&gt;
&lt;td style=&quot;width: 41.8605%;&quot;&gt;느림 (Slower)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;유연성&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.2326%;&quot;&gt;낮음 (Less flexible)&lt;/td&gt;
&lt;td style=&quot;width: 41.8605%;&quot;&gt;높음 (More flexible)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;주요 구현 방법&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.2326%;&quot;&gt;함수 오버로딩 (Function Overloading), 연산자 오버로딩 (Operator Overloading)&lt;/td&gt;
&lt;td style=&quot;width: 41.8605%;&quot;&gt;가상 함수 (Virtual Functions), 함수 오버라이딩 (&lt;span style=&quot;background-color: #f9f9f9; color: #333333; text-align: start;&quot;&gt;Function &lt;/span&gt;Overriding)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;상속 요구사항&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.2326%;&quot;&gt;필요 없음 (Not required)&lt;/td&gt;
&lt;td style=&quot;width: 41.8605%;&quot;&gt;필요함 (Requires inheritance)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 12.7907%;&quot;&gt;&lt;b&gt;오류 감지&lt;/b&gt;&lt;/td&gt;
&lt;td style=&quot;width: 45.2326%;&quot;&gt;컴파일 시점 (Compile time)&lt;/td&gt;
&lt;td style=&quot;width: 41.8605%;&quot;&gt;런타임 시점 (Runtime)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;2. 가상 함수(Virtual Function)&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;가상 함수의 정의 및 목적 &lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;기본 클래스에서 선언되고 &lt;b&gt;파생 클래스에서 재정의 될 수 있는 함수&lt;/b&gt;이다. 이는 주로 같은 함수를 여러 파생 클래스에서 다르게 구현해야 하는 경우에 사용된다.&lt;/li&gt;
&lt;li&gt;가상 함수는 &lt;b&gt;C++에서 런타임 다형성을 구현&lt;/b&gt;하는 초석이다. 가상 함수는 기본 클래스에서 virtual 키워드를 사용하여 선언되고, 파생 클래스에서 재정의 되는 멤버함수이다. 가상 함수의 주요 목적은 &amp;ldquo;동적 디스패치&amp;rdquo;를 가능하게 하여, 함수 호출이 포인터나 참조의 정적 타입이 아닌 런타임에 객체의 실제 타입에 기반하여 해결되도록 보장하는 것이다.&lt;/li&gt;
&lt;li&gt;일반적으로 C++ 컴파일러는 함수를 호출할 때 컴파일 타임에 고정된 메모리 주소로 변환시킨다. 이를 정적 바인딩이라고 한다. 그러나 상위 클래스 타입의 포인터나 참조가 하위 클래스의 객체를 가리킬 때, 비가상 함수를 호출하면 포인터의 정적 타입(상위 클래스)에 해당하는 함수가 호출된다. 이는 다형성의 본래 목적에 부합하지 않는다. 가상 함수는 이러한 문제를 해결하기 위해 도입 되었다. 가상 함수를 선언하면, 포인터 타입이 아닌 포인터가 가리키는 객체의 실제 타입에 따라 멤버함수를 선택하게 된다. 이 메커니즘은 개방/폐쇄 원칙(확장에는 개방적이고 수정에는 폐쇄적)을 준수하는 유연하고 확장 가능한 코드를 작성하는 데 필수적이다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;정적 바인딩과 동적 바인딩&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;바인딩은 함수 호출을 해당 함수의 정의에 연결하는 과정을 의미한다. C++에서는 두 가지 주요 바인딩 방식이 존재한다.&lt;/li&gt;
&lt;li&gt;정적 바인딩(컴파일 바인딩)은 컴파일 타임에 호출할 함수 심볼을 결정하는 방식이다. 비가상 함수는 모두 정적 바인딩 된다.&lt;/li&gt;
&lt;li&gt;동적 바인딩(런타임 바인딩)은 함수 호출과 함수 정의 간의 연결을 런타임까지 지연시킨다. 이는 가상 함수를 통해 구현되며, 포인터나 참조의 정적 타입이 아닌, 포인터가 가리키는 객체의 실제 타입에 따라 함수를 선택하게 한다. 가상 함수에 의해 촉진되는 정적 바인딩에서 동적 바인딩으로의 전환은 다형적 동작을 가능하게 하는 근본적인 메커니즘이다. 정적 바인딩은 컴파일 타임 효율성과 예측 가능성을 제공하는 반면, 동적 바인딩은 객체의 정확한 타입이 런타임까지 알려지지 않는 복잡하고 확장 가능한 시스템에 필요한 결정적인 유연성을 제공한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;순수 가상 함수와 추상 클래스&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1755513055777&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;class CGameObject // 추상 클래스
{
public:
    virtual void Update(float deltaTime) = 0; // 순수 가상 함수
};

class CPlayer final : public CGameObject
{
public:
    void Update(float deltaTime) override {
        // 플레이어 업데이트 로직
    }
};

class CMonster final : public CGameObject
{
public:
    void Update(float deltaTime) override {
        // 몬스터 업데이트 로직
    }
};&lt;/code&gt;&lt;/pre&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;순수 가상 함수는 파생 클래스에서 반드시 재정의해야 하는 가상 함수이다. 순수 가상 함수는 기본 클래스에서 선언되지만 정의를 가지지 않으며, 함수 선언뒤에 = 0;을 붙여 선언한다.&lt;/li&gt;
&lt;li&gt;하나 이상의 순수 가상 함수를 포함하는 클래스를 추상 클래스라고 한다. 추상 클래스는 그 자체로는 객체를 인스턴스화 할 수 없다. 즉, 추상 클래스의 객체를 직접 생성하는 것은 불가능하다. 이는 추상 클래스가 완전한 구현을 제공하지 않고, 파생 클래스들이 구현해야 할 &amp;ldquo;계약&amp;rdquo; 또는 &amp;ldquo;인터페이스&amp;rdquo; 역할을 하기 때문이다.&lt;/li&gt;
&lt;li&gt;클래스를 추상적으로 만듦으로써 개발자는 모든 구체적인 파생 클래스가 특정 구현을 제공하도록 보장하며 공통 인터페이스 준수를 보장할 수 있다.. 이는 견고하고, 유지 관리 가능하며 확장 가능한 코드를 촉진하여 &amp;ldquo;계약에 의한 설계&amp;rdquo; 원칙과 일치한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;override, final 키워드&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;override는 파생 클래스의 함수가 기본 클래스의 가상 함수를 재정의하려는 의도를 명시적으로 나타낸다.&lt;/li&gt;
&lt;li&gt;override를 사용하면 컴파일 타임에 오류를 감지할 수 있다. 일반적인 오류를 방지하는 안전망 역할을 하며, 함수 타입의 일부가 아니며 함수 선언의 마지막에 위치한다.&lt;/li&gt;
&lt;li&gt;final 지정자는 가상 함수가 더 이상 파생 클래스에서 재정의되는 것을 막거나, 클래스 자체가 더 이상 상속될 수 없도록 제한 하는 데 사용된다.
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;&lt;span data-token-index=&quot;0&quot;&gt;&lt;b&gt;가상 함수에 사용될&lt;/b&gt; &lt;b&gt;때&lt;/b&gt; :&lt;/span&gt; final은 해당 가상 함수가 어떤 파생 클래스에서도 재정의될 수 없음을 의미한다. 이는 특정 구현이 상속 계층 구조의 특정 지점에서 최종적이어야 함을 명시할 때 유용하다.&lt;/li&gt;
&lt;li&gt;&lt;span data-token-index=&quot;0&quot;&gt;&lt;b&gt;클래스에 사용될 때&lt;/b&gt; : &lt;/span&gt;final은 해당 클래스가 다른 클래스에 의해 상속될 수 없음을 의미한다. 이는 클래스의 설계가 더 이상 확장되어서는 안 된다는 것을 명확히 할 때 사용된다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;가상 함수를 재정의 할때에는 virtual 키워드를 다시 붙이지 않아도 자동으로 가상함수로 인식된다.&lt;/li&gt;
&lt;li&gt;하지만, C++11부터 도입된 override 지정자를 사용하는 것을 강력히 권장한다. 해당 키워드는 함수가 기본 클래스의 가상 함수를 재정의 하려는 의도를 명시적으로 나타내어 컴파일 타임에 시그니처 불일치와 같은 오류를 잡아낼 수 있도록 돕는다. 이는 코드 가독성을 향상시키고, 개발자가 기존 가상 함수를 재정의하는 대신 실수로 새 함수를 생성할 수 있는 버그를 방지한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;3. 가상 함수 테이블(Virtual Function Table)의 이해&lt;/b&gt;&lt;/span&gt;&lt;span style=&quot;color: #009a87;&quot;&gt;&lt;b&gt;&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;가상 함수 테이블의 정의 및 구조&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;가상 함수 테이블(Virtual Function Table), 줄여서 VTable은 C++ 컴파일러가 런타임 다형성을 구현하기 위해 사용하는 핵심 메커니즘이다.&lt;/li&gt;
&lt;li&gt;VTable은&amp;nbsp;클래스마다&amp;nbsp;하나씩&amp;nbsp;존재하며,&amp;nbsp;해당&amp;nbsp;클래스의&amp;nbsp;가상&amp;nbsp;함수&amp;nbsp;주소(함수&amp;nbsp;포인터)를&amp;nbsp;저장한다.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;클래스가 가상 함수를 포함하면, 컴파일러는 해당 클래스의 모든 객체에 숨겨진 포인터인 가상 포인터(Virtual Pointer, VPTR)를 데이터 멤버로 삽입한다. 이 VPTR은 해당 객체의 클래스 VTable을 가리킨다. 모든 객체는 각자의 VPTR을 가지지만, 동일한 클래스의 모든 객체는 동일한 VTable을 공유한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt; &lt;span data-token-index=&quot;0&quot;&gt;VTable의 결정 시점 및 VPTR 초기화&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;일반적으로 VTable의 레이아웃은 컴파일 타임에 결정된다. 이는 VTable의 내용(가상 함수의 주소)이 컴파일 시점에 결정될 수 있기 때문이다.&lt;/li&gt;
&lt;li&gt;반면, VPTR은 런타임에 객체가 생성될 때 초기화된다. 컴파일러는 각 클래스의 생성자 내부에 this-&amp;gt;__vptr를 해당 클래스의 VTable을 가리키도 초기화하는 숨겨진 코드를 삽입한다. 상속 계층 구조에서 객체가 생성될 때, VPTR은 생성자 흐름에 따라 업데이트 된다.&lt;/li&gt;
&lt;li&gt;Derived 클래스 객체가 생성될 때 (단일 상속 기준) :&lt;br /&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;Derived 생성자가 Base 생성자를 호출한다.&lt;/li&gt;
&lt;li&gt;Base 생성자가 실행되면서 VPTR을 Base의 VTable을 가리키도록 설정한다.&lt;/li&gt;
&lt;li&gt;Base 생성자가 반환된다.&lt;/li&gt;
&lt;li&gt;Derived 생성자가 실행되면서 VPTR을 Derived의 VTable을 가리키도록 업데이트한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span data-token-index=&quot;0&quot;&gt;가상 함수 동작 원리&lt;/span&gt;&lt;/b&gt;&lt;span data-token-index=&quot;0&quot;&gt;&lt;/span&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span data-token-index=&quot;0&quot;&gt;가상 함수 호출 메커니즘은 런타임 다형성을 가능하게 하는 동적 바인딩의 핵심이다. 기본 클래스 포인터나 참조를 통해 파생 클래스 객체의 가상 함수를 호출할 때, 다음 단계를 거쳐 올바른 함수를 결정하고 실행한다.&lt;/span&gt;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt; VPTR 접근 :&lt;/b&gt; 가상 함수가 호출되면, 컴파일러는 호출하는 객체의 숨겨진 데이터 멤버인 VPTR에 접근한다. 이 VPTR은 객체 내부에 저장되어 있으며, 해당 객체의 실제 클래스에 해당하는 VTable을 가리키고 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; VTable 탐색 :&lt;/b&gt; VPTR이 가리키는 VTable은 해당 클래스의 모든 가상 함수에 대한 함수 포인터 배열이다. 컴파일러는 호출하려는 가상 함수의 VTable 내에서의 &amp;ldquo;슬롯 번호&amp;rdquo;를 알고 있다. 해당 &quot;슬롯 번호&quot;를 통해 함수 포인터를 읽는다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;함수 주소 로드 :&lt;/b&gt; VTable에서 해당 슬롯 번호에 저장된 함수 포인터를 찾아 실제 호출할 함수의 메모리 주소를 로드한다. 만약 파생 클래스가 기본 클래스의 가상함수를 재정의했다면, VTable에는 파생 클래스의 함수 주소가 저장되어있을것이고, 재정의하지 않았다면 기본 클래스의 함수 주소가 저장되어 있을 것이다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 함수 호출 :&lt;/b&gt; 로드된 함수 주소를 사용하여 실제 함수를 호출한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;즉,&amp;nbsp;이&amp;nbsp;과정은&amp;nbsp;&amp;ldquo;vptr&amp;nbsp;로드&amp;nbsp;&amp;rarr;&amp;nbsp;VTable에서&amp;nbsp;함수&amp;nbsp;포인터&amp;nbsp;로드&amp;nbsp;&amp;rarr;&amp;nbsp;함수&amp;nbsp;호출&amp;rdquo;의&amp;nbsp;세&amp;nbsp;단계로&amp;nbsp;요약할&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp; &lt;br /&gt;이&amp;nbsp;메커니즘&amp;nbsp;덕분에&amp;nbsp;컴파일&amp;nbsp;시점에&amp;nbsp;호출할&amp;nbsp;함수가&amp;nbsp;확정되지&amp;nbsp;않아도,&amp;nbsp;런타임에&amp;nbsp;객체의&amp;nbsp;실제&amp;nbsp;타입에&amp;nbsp;따라&amp;nbsp;올바른&amp;nbsp;함수가&amp;nbsp;실행된다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;4. 가상 함수의 장단점 및 성능 오버헤드&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;가상 함수는 C++ 런타임 다형성을 구현하는 데 필수적이고 강력한 기능이지만, 장점과 단점에 대해서 명확히 인지하고 사용하는 것이 중요하다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;장점&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;런타임 다형성 구현 :&lt;/b&gt; 지나치게 많이 언급했지만, 역시나 가장 중요한 장점이다. 가상 함수의 가장 큰 장점은 런타임 다형성을 가능하게 한다는 것이다. 이를 통해 런타임에 객체의 실제 타입에 따라 올바른 함수 구현이 호출되도록 보장한다. 런타임 다형성이 있기에 우리는 기본 클래스의 포인터나 참조를 통해 파생 클래스 객체를 일관된 방식으로 처리할 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 유연성 및 확장성 :&lt;/b&gt; 가상 함수는 기존 코드의 기능을 쉽게 확장할 수 있도록한다. 새로운 파생 클래스를 추가하고 가상 함수를 재정의 함으로써 기존 기본 클래스 코드를 수정하지 않고도 새로운 동작을 통합할 수 있다. 이는 코드 재사용성을 촉진하고 유지보수성을 향상시킨다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 추상 클래스 및 인터페이스 지원 :&lt;/b&gt; 순수 가상 함수를 통해 추상 클래스를 정의하고 인터페이스를 강제할 수 있다. 이는 견고하고 예측 가능한 소프트웨어 설계를 가능하게 한다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt; 코드 가독성 및 유지 보수성 :&lt;/b&gt; 동일한 이름의 메서드나 연산자가 서로 다른 동작을 수행하므로 코드의 가독성이 높아진다. 또한, 구현 세부사항을 인터페이스로부터 분리하여 유지보수를 용이하게한다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;단점&lt;/span&gt;&lt;/b&gt;&lt;/h4&gt;
&lt;ol style=&quot;list-style-type: decimal;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;&lt;b&gt;성능 오버헤드 : &lt;/b&gt;가상함수 호출은 비가상 함수 호출에 비해서는 약간의 성능 오버헤드를 발생시킨다. 이는 런타임에 VTable을 통해 함수 주소를 참조하는 추가적인 단계 때문이다. (VPTR을 참조 -&amp;gt; vTable에서 함수 포인터 참조)&lt;br /&gt;이러한 두번의 추가적인 메모리 접근은 두 번의 캐시 미스 가능성을 발생 시킬 수 있으며, 실제 캐시 미스 발생 시 성능에 큰 영향을 미칠 수 있다.&lt;/li&gt;
&lt;li&gt;&lt;b&gt;인라인 최적화 불가 : &lt;/b&gt;가상 함수는 런타임에 호출할 함수를 결정하기에, 컴파일러가 일반적으로 해당 함수를 인라인화 할 수 없다. 인라인화는 함수 호출의 오버헤드를 제거하여 성능을 향상시키는 매우 핵심적인 컴파일러 최적화 기법이다.&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이외에도 객체 슬라이싱 위험, 메모리 사용량 증가, 복잡성 증가와 같은 단점이 있지만 위의 두 단점이 핵심이다.&lt;/p&gt;
&lt;hr contenteditable=&quot;false&quot; data-ke-type=&quot;horizontalRule&quot; data-ke-style=&quot;style6&quot; /&gt;
&lt;h2 style=&quot;color: #000000; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;&lt;b&gt;마치며&lt;/b&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;오늘은&amp;nbsp;다형성이&amp;nbsp;무엇인지,&amp;nbsp;왜&amp;nbsp;필요한지,&amp;nbsp;언제&amp;nbsp;사용되는지,&amp;nbsp;그리고&amp;nbsp;시점에&amp;nbsp;따른&amp;nbsp;다형성의&amp;nbsp;구분에&amp;nbsp;대해&amp;nbsp;학습했다.&amp;nbsp; &lt;br /&gt;다형성의&amp;nbsp;개념과&amp;nbsp;가상&amp;nbsp;함수,&amp;nbsp;VTable의&amp;nbsp;동작&amp;nbsp;원리를&amp;nbsp;깊이&amp;nbsp;이해하고,&amp;nbsp;성능에&amp;nbsp;대한&amp;nbsp;잠재적&amp;nbsp;영향도&amp;nbsp;함께&amp;nbsp;살펴보았다. &lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #333333; text-align: start;&quot;&gt;특히, 성능 오버헤드에 대해 학습하며 큰 즐거움을 느꼈다.&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실제 프로젝트를 진행하면서, 나는 추상 클래스를 설계하고 제공할 인터페이스를 고민하는 과정을 즐겼다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇기에 좀 더 집중해서 학습이 가능했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;마지막으로 이런 질문을 남긴 채 글을 마무리한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;게임 개발에서 성능은 강조가 무의미할 정도로 중요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그렇다고 해서, 우리는 런타임 다형성의 강력한 힘을 포기할 수 있을까?&lt;/p&gt;</description>
      <category>Study/C++</category>
      <author>Smilejiro</author>
      <guid isPermaLink="true">https://smilejiro.tistory.com/45</guid>
      <comments>https://smilejiro.tistory.com/45#entry45comment</comments>
      <pubDate>Mon, 18 Aug 2025 20:33:33 +0900</pubDate>
    </item>
    <item>
      <title>Notion -&amp;gt; Tistory</title>
      <link>https://smilejiro.tistory.com/notice/44</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;노션에 작성된 글들을 정리하여 티스토리로 이전합니다.&lt;/p&gt;</description>
      <author>Smilejiro</author>
      <guid isPermaLink="true">https://smilejiro.tistory.com/notice/44</guid>
      <pubDate>Mon, 18 Aug 2025 17:58:55 +0900</pubDate>
    </item>
  </channel>
</rss>