C++

위키百科, 우리 모두의 百科事典.

C++
패러다임 프로그래밍 패러다임 : 節次的 프로그래밍 , 函數兄 프로그래밍 , 客體 志向 프로그래밍 , 제네릭 프로그래밍
設計者 비야네 스트롭스트룹
發表日 1985年 (39年 前) ( 1985 )
最近 버전 C++20 (ISO/IEC 14882:2020)
最近 버전 出市日 2020年 12月 15日 (3年 前) ( 2020-12-15 )
미리보기 버전 C++23
미리보기 버전 出市日 2022年 3月 17日 (2年 前) ( 2022-03-17 )
資料型 體系 C++
파일 擴張字 .cc, .cpp, .cxx, .C, .c++, .h, .hh, .hpp, .hxx, .h++
웹사이트 isocpp .org
主要 具現體
LLVM 클랭 , GCC , 마이크로소프트 비주얼 C++ , 엠바카데로 C++ 빌더 , IBM XL C++
影響을 받은 言語
에이다 , 알골 68 , C , CLU , ML , 時뮬라
影響을 준 言語
에이다 95 , C# , C99 , 샤프 , D , 자바 , 루아 , , PHP , 파이썬 , 러스트 , , V

C++ AT&T 벨 硏究所 비야네 스트롭스트룹 이 C言語 基盤으로 1985年에 發表하여 發展한 프로그래밍 言語 이다.

歷史 [ 編輯 ]

C++ 標準
鳶島 C++ 標準 非公式 名稱
1998 ISO/IEC 14882:1998 [1] C++98
2003 ISO/IEC 14882:2003 [2] C++03
2011 ISO/IEC 14882:2011 [3] C++11 , C++0x
2014 ISO/IEC 14882:2014 [4] C++14 , C++1y
2017 ISO/IEC 14882:2017 [5] C++17 , C++1z
2020 ISO/IEC 14882:2020 [6] C++20 , C++2a

1979年, 덴마크의 컴퓨터 科學者 비야네 스트롭스트룹 은 C++의 先驅者格 言語인 "C with Classes" 作業에 着手하였다. [7] 새로운 言語를 만들려는 意義는 博士 論文을 위한 스트롭스트룹의 프로그래밍 經驗에서 비롯되었다.

처음에 스트롭스트룹의 "C with Classes"는 C 컴파일러(Cpre)에 클래스 , 相續 클래스 , 스트롱 타이핑 , 인라인 擴張 , 基本 引受 를 包含한 여러 機能들을 追加하였다. [8]

1983年, "C with Classes"라는 이름은 假想 函數 , 函數 이름, 演算子 오버로딩 , 參照, 制約條件, type-safe free-store 메모리 割當 (new/delete), 改善된 資料型 檢事, BCPL 스타일의 1줄 코멘트(//)를 包含한 새로운 機能들을 追加하면서 "C++"로 變更되었다.

1985年 C++ 프로그래밍 言語 第1판이 出市되었으며 當時 公式標準이 없었기 때문에 이 言語의 絶對的인 參照 文獻이 되었다. [9] 最初의 C++ 常用 具現體는 같은 해 10月에 出市되었다. [7]

特徵 [ 編輯 ]

C 言語 에 客體志向 프로그래밍을 支援하기 위한 內容이 덧붙여진 것이라고 할 수도 있지만 [10] , 애初부터 客體志向을 念頭에 두고 만들어진 言語와는 다르게, 團地 더 좋은 C 言語로서 手續型 言語로 取扱하기도 한다. 初期의 C++은 C 위에 놓인 트랜스레이터로 具現되었다. 卽, C++ 프로그램을 一旦 C 프로그램으로 變換하고 나서 C 컴파일러로 컴파일하는 式이었고 따라서 C 言語에 對해 上位 互換性을 갖는 言語였다.

그 後, C 言語의 標準 規格이 바뀔 때 const 數式 等 C++의 機能이 C 言語에 받아들이기도 했다. 現在 C 言語와 C++와의 사이에는 嚴格한 互換性은 없다. 特히 C99 의 出現으로 C 言語와의 互換性은 깨져 버렸다. 따라서 C99 以後로 C++은 C의 수퍼셋(superset)李 아니다. 그러나, C++17 標準案에서는 다시 C言語가 C++의 眞部分集合이 될 것이 確實해 보인다. 現在 C와 C++가 明確한 區別 없이 婚材되어 使用되는 컴파일러가 大部分이지만 C99 以後의 文法을 C++ 컴파일러에서 컴파일할 境遇 誤謬가 發生할 수 있다.

다음과 같은 다양한 機能을 가지고 있어 C++ 言語의 標準 規格은 몹시 複雜하다. C++ 標準의 모든 事項을 完全하게 支援하는 컴파일러는 現在 손꼽을 程度이다.

  • 多重 相續
  • 템플릿
  • 演算子 오버로드
  • 例外 處理
  • 實行時 兄 識別

덧붙여 예부터 傳해 내려온 節次的인 性格도 그대로 남아 "萬能" 設計로, 悠然함과 强力함은 다른 言語에 비할 바가 아니지만, 複雜한 言語가 되고 말았다. 이런 點 때문에 보다 客體志向性을 强化하여, 萬能設計를 志向하기보다는 單純한 設計를 目標로 한 새로운 言語들인 자바 , C# , D 言語 等이 나오기도 했다.

캡슐化 [ 編輯 ]

캡슐化 는 2가지 要素를 滿足하도록 言語的으로 具現 되어야 한다.

  • 데이터와 메서드 結合

C++에서는 客體의 貯藏空間의 位置(this로 表現되는 客體의 데이터 位置 住所값)를 函數에 넘김으로써 데이터와 메서드를 結合한다. this는 客體의 位置 住所값인 포인터이다.

  • 外部에 데이터나 메서드를 隱匿

客體 志向 프로그래밍 에서 作成된 프로그램 코드는 再使用이 重要한 要素이다. 재사용하려면 다른 開發者가 使用할 때, 必要한 使用方法만 알면된다. 클래스 內面 깊숙히 알 必要가 없는 境遇가 많다. 따라서 客體를 設計할 때, 境遇에 따라 멤버 變數 멤버 函數 를 다 알릴 必要가 없다. 어떤 要素들은 內部에서 使用하고 非公開로 設定할 必要가 있다. 該當 客體를 使用하거나 相續해서 使用할 때, 必要한 要素만을 公開하고 API을 作成하여 公開하면 된다. 이런 非公開의 方法으로 隱匿을 設定하고 캡슐化의 한要素가 된다.

키워드 3個가 있다. private, protected, public을 使用해서 接近을 制限할 수 있다.

class
 MyObject
 {

public
:

     MyObject
()
 {
 }


     int
 getData
();
  // 隱匿된 데이터는 메서드를 使用하여 인터페이스로 쓸 수 있다.


private
:
 // 이 指定者는 自己 클래스에서만 액세스를 限定한다. 隱匿하는 方法으로 使用.

     int
 m_data
;

};


int
 MyObject::getData
()

{

   return
 this
->
m_data
;
 // this가 自動으로 넘어온다.

}

여기서 데이터와 메서드 結合은 멤버函數를 構成할 때 this라는 포인터로 象徵되는 것을 開發者 코드內에 코딩없이도 自動으로 넘겨 주어 該當 클래스 內의 멤버變數들을 使用하게 하였다. 이렇게 言語的으로 結合한다.

this는 自動으로 客體의 空間位置값이 메모리의 住所값이다. 이것을 포인터로 使用하였다. 이것으로 結局 어떤 客體인지를 區別하는 手段으로 使用하여, 데이터와 메서드를 結合한다. MyObject:: 가 붙는 클래스의 멤버函數는 實行할 때 自動으로 모두 this가 넘어간다. static 메서드는 this가 除外된다.

this가 멤버 函數에 넘어가는 方法으로 CPU의 레지스터를 使用할 수도 있다. 멤버 函數에서 멤버 變數를 使用할 때 레지스터에 貯藏된 客體의 位置 駐소값으로 하여 內部 멤버變數의 相對住所값과 合하여 位置값을 다시 設定하고 액세스 하면 된다. 이것은 마치 struct의 始作住所와 內部變數의 相對的 位置값의 合으로 表現하는 住所體系와 類似하다.

예제 [ 編輯 ]

Hello world 프로그램 [ 編輯 ]

C++ 標準 라이브러리 스트림 機能을 使用하여 標準 出力 을 통해 Hello, world! 를 出力한다.

#
 include
 <iostream>
 //iostream이라는 헤더를 가져온다


using
 namespace
 std
;
 //namespace의 std 모듈을 使用한다


int
 main
()
 {
 //메인메소드의 始作地點이다.


    cout
 <<
 "Hello, world!"
 <<
 endl
;
 //"Hello, World!" 콘솔로 出力한다.


    return
 0
;
 //0을 리턴海 프로그램을 確實히 終了시킨다.

}
//메인메소드를 끝낸다

C++20의 모듈 機能을 利用하면 다음과 같이 쓸 수 있다.

import
 std
.
core
;


using
 namespace
 std
;


int
 main
()
 {


    cout
 <<
 "Hello, world!"
 <<
 endl
;


    return
 0
;

}

可及的이면 void main을 使用하지 말자. 컴퓨터는 프로그램이 0이 아닌 數를 返還하면

그 프로그램이 제대로 終了되었다 생각하지 않는다. 卽 int main으로 數字 0을 리턴하여

잘 終了되었다는 걸 컴퓨터에게 알려주자.

客體의 生成과 消滅 [ 編輯 ]

客體를 具現하기 위해 클래스 의 宣言이 必要하다. 構造的인 設定을 하고 生成하면 된다.

客體의 宣言 [ 編輯 ]

客體의 模樣은 클래스 를 使用하여 刑을 宣言하여 프로그램 한다. C言語에서 全域變數, 地域變數가 있듯이 客體도 宣言 位置에 따라 生成과 消滅이 다르다.

客體 만들기 :

  1. 클래스 로 客體의 構造를 만든다. 멤버 變數와 멤버 函數로 構成된다.
  2. 政敵 또는 動的으로 客體를 生成한다.
  • 轉役 政敵 客體 : main() 函數 前에 客體의 메모리 空間을 生成하고 生聖子가 自動 實行된다. 全域型은 메모리 맵 에서 割當된 特定領域을 使用한다. 따라서 應用 프로그램이 始作하기 위해 運營 體制 로부터 割當 받아 使用한다.
  • 地域 政敵 客體 : 客體가 宣言된 時點에서 客體의 메모리 空間을 生成하고 生聖子가 自動 實行된다. 地域變數처럼 主로 스택 에 割當된다.
  • 動的 客體 : new에 依해 힙領域에 客體의 메모리 空間을 生成하고 生聖子가 自動 實行된다.

客體 消滅 :

  • 轉役 政敵 客體 : main() 函數 return後 消滅된다. 應用 프로그램의 終了와 同時에 消滅된다.
  • 地域 政敵 客體 : 函數 블럭 또는 客體가 生成된 任意의 自己 블럭이 끝나면 消滅된다.
  • 動的 客體 : delete에 依해 消滅된다.

接近者 [ 編輯 ]

클래스는 캡슐化 가 可能하다. 따라서 客體를 設計할 때는 特定 멤버變數나 멤버函數를 外部에서 接近을 制限할 必要가 있다.

接近 制御 키워드 3가지:

  • private : 自己 클래스에서만 接近을 許容한다.
  • public : 모두 接近을 許容한다.
  • protected : 自己 클래스와 相續을 받은 子息 클래스에서만 接近을 許容한다.

客體의 生成 [ 編輯 ]

C言語에서는 全域變數와 地域變數 그리고 動的割當에 依한 데이터 貯藏空間을 만들 수 있다. 마찬가지로 C++에서도 全域變數로 客體를 生成할 수도 있고 地域變數로 生成하는 것도 可能하다. 또한 new를 通해 動的으로 客體를 生成 시킬 수 있다.

政敵 割當 客體 [ 編輯 ]

C++에서 變數를 잡듯이 客體도 宣言을 통해 이루어진다. C에서 全域變數와 地域變數로 나누어는 것과 같이, 客體 亦是 같은 方式으로 轉役 또는 地域 客體로 宣言할 수 있다.

轉役 政敵 客體는 main() 函數가 實行되기 前 貯藏空間이 生成되고, 生聖子가 呼出된다. 客體가 生成되면 메모리에 데이터 貯藏空間이 생기고 바로 生聖子가 呼出된다. 따라서 轉役 政敵 客體 生聖子의 呼出은 main函數보다 먼저 이루어진다.

動的 割當 客體 [ 編輯 ]

new에 依해 生成 되고, delete에 依해 削除된다. new로 生成 되면, new 實行 時點에서 客體의 貯藏空間人 메모리를 確保하고 生聖子가 自動實行된다. 動的客體는 힙領域에 存在하고 포인터를 넘겨 받아서 客體 포인터 變數에 住所값을 貯藏하고 處理한다.

'new'의 코딩은 函數에 넣을 수 밖에 없으므로 main 函數 始作 以後에야 可能하다.

이미 設定된 메모리 空間을 利用하여 客體 定義하기 [ 編輯 ]

C/C++은 포인터를 使用한다. 이것은 客體의 크기만 確保되면 客體를 使用하는데 아무 問題가 없다. 따라서 이미 設定된 變數를 포인터를 利用하여 客體化 해서 使用할 수 있다.

#include
 <iostream>


typedef
 struct
 MsgBuff
 {

    MsgBuff
 *
link
;

    int
  szpkg
;

    int
  szdata
;

    void
 *
data
;

}
 MsgBuff
;


class
 A
 {

public
:

    A
()
 {
 num
 =
 0
;
 }

    int
 num
;

};


char
 gbuff
[
1024
];


int
 main
(
int
 argc
,
 char
*
 argv
[])

{

    MsgBuff
 *
pmsg
 =
 (
MsgBuff
*
)
 gbuff
;

    int
 szpkg
 =
 sizeof
(
A
)
+
sizeof
(
pmsg
->
link
)
+
sizeof
(
int
)
*
2
;

    pmsg
->
link
 =
 NULL
;

    pmsg
->
szdata
 =
 sizeof
(
A
);

    pmsg
->
szpkg
 =
 szpkg
;


    A
 *
pa
 =
 (
A
*
)
 &
pmsg
->
data
;

    pa
->
num
 =
 10
;

    std
::
cout
 <<
 pa
->
num
 <<
 std
::
endl
;


    return
 0
;

}

블럭에서의 政敵 클래스 生成과 消滅 [ 編輯 ]

#include
 <iostream>

using
 namespace
 std
;


class
 A
 {

public
:

   A
()
 {
 num
 =
 0
;
 }

   A
(
int
 n
)
 :
 num
(
n
)
 {
 cout
 <<
 "生聖子 呼出 : "
 <<
 this
 <<
 endl
;
  }

   ~
A
()
 {
 cout
<<
 "消滅子 呼出 : "
 <<
 this
 <<
 endl
;
 }

   int
 getNum
()
 {
 return
 num
;
 }


private
:

   int
 num
;

};


int
 main
()

{

   int
 num
;


   cout
 <<
 "블럭 始作 합니다."
 <<
 endl
;

   {
  // 블럭 始作하면 只今부터 宣言되는 變數나 클래스는 블럭이 끝나면 사라진다.

      A
 a
(
10
);


      num
 =
 a
.
getNum
();

      cout
 <<
 "블럭 안에서 a.getNum() = "
 <<
 a
.
getNum
()
 <<
 endl
;


   }
 // 블럭이 끝나면 客體 a는 消滅됨. 消滅自家 呼出된다.

   cout
 <<
 "블럭 끝났습니다. num = "
 <<
 num
 <<
 endl
;

   return
 0
;

}

實行結果:

블럭 始作 합니다.
生聖子 呼出 : 0039FCD0
블럭 안에서 a.getNum() = 10
消滅子 呼出 : 0039FCD0
블럭 끝났습니다. num = 10

모든 函數는 블럭을 包含하므로 函數內에서 生成된 政敵客體는 函數의 블럭이 끝나면 消滅子 가 呼出되고 客體의 貯藏空間은 사라진다. 위의 例처럼 任意의 블럭에서 生成된 政敵客體 亦是 自己의 블럭이 끝나면 消滅自家 呼出되고 사라진다.

클래스 變數 宣言 時, 클래스 間 膠着狀態 [ 編輯 ]

클래스 內에서 멤버變數로 다른 클래스를 使用할 수 있다. 政敵 멤버變數와 포인터가 可能하다. 그러나 2個의 클래스가 서로 政敵인 客體를 宣言하면 膠着狀態로 빠져 客體의 크기를 決定할 수 없다. 따라서 不可能해 진다.

膠着狀態 한쪽의 크기 決定
class
 B
;

class
 A
 {

   int
 num
;

   B
 b
;

};

class
 B
 {

   int
 num
;

   A
 a
;

};

class
 B
;

class
 A
 {

   int
 num
;

   B
 *
b
;

};

class
 B
 {

   int
 num
;

   A
 a
;

};

이 境遇 A 클래스는 B 클래스를 멤버變數로 잡았다. 이렇게 하려면 于先 B 클래스의 멤버變數들의 데이터 貯藏空間의 크기가 決定되어야 한다. 그러나 B 클래스에서 다시 A 클래스를 宣言함으로써 크기를 決定할 수 없는 狀態가 된다. 따라서 이런境遇는 不可能 하다. 結局 한쪽에서 포인터를 使用하여 먼저 크기를 確定해 주어야 한다.
위와 같은 境遇 A클래스의 客體 貯藏空間의 크기는 決定할 수 있다. 모든 포인터는 CPU의 메모리 住所體系가 이미 決定되어 있으므로 크기 計算이 可能하고 各 멤버變數의 住所位置도 決定할 수 있다. A클래스가 決定되었으므로 이제 B클래스도 決定할 수 있다.


클래스 內에서 클래스 變數 宣言 時 膠着狀態

再歸的 宣言 變數의 크기 決定
class
 A
 {

   int
 num
;

   A
 a
;

};

class
 A
 {

   int
 num
;

   A
 *
a
;

};

마찬가지로 貯藏空間의 크기를 決定할 수가 없다. 포인터 變數이므로 크기를 決定할 수 있어서 可能하다.

客體의 예 [ 編輯 ]

/// 파일 : MyObject.h ////////////////////////////////////


class
 MyObject
 {
 // 클래스의 始作

public
:

   MyObject
();
   // 生聖子1

   MyObject
(
int
 age
,
 char
 *
name
);
  // 生聖子2 : 生聖子는 여러가지가 可能하다.

   virtual
 ~
MyObject
();
  // 消滅子


   // 멤버變數 age, name, fdyn가 privated이므로 다른 客體에서 接近이 不可能 하다.

   // 따라서 멤버函數로 解決한다. setAge, getAge,setName,getName


   void
 setAge
(
int
 age
)
 {
 this
->
age
 =
 age
;
 }
  // 函數 本體를 클래스 內에 코딩할 수 있다.

                    // 모든 函數를 헤더의 클래스 안에 코딩하면 클래스 全體를 把握하는데 不便할 수 있다.

                    // 그리고 파일을 cpp와 h로 나누는 意味가 毁損될 수 있다.

   int
 getAge
()
 {
 return
 age
;
 }


   void
 setName
(
char
 *
n
,
 int
 opt
 =
 0
);
  // 萬若 opt을 使用하지 呼出하면 自動으로 0을 設定한다.

   char
*
 getName
();


   static
 int
 counter
;


private
:

   int
 age
;

   char
 *
name
;

   int
  fdynm
;
  // name 變數의 메모리 空間을 new (malloc())로 만들었는지를 설정

};


/// 파일 : MyObject.cpp //////////////////////////////////

#include
 <iostream>

#include
 "MyObject.h"

using
 namespace
 std
;


MyObject
::
MyObject
()
 // 生聖子1

{

   age
 =
 0
;

   name
 =
 NULL
;

   fdynm
 =
 0
;


   cout
 <<
 "+生聖子1 MyObject() : "
 <<
 this
 <<
 endl
;

}


MyObject
::
MyObject
(
int
 age
,
 char
 *
name
)
 // 生聖子2

{

   this
->
age
 =
 age
;

   this
->
name
 =
 name
;


   cout
 <<
 "+生聖子2 MyObject("
<<
 age

 <<
","
<<
 name
 <<
 ") : "
 <<
 this
 <<
 endl
;

}


MyObject
::~
MyObject
()
 // 消滅子

{

	cout
 <<
 "-消滅子 MyObject("
<<
 name
 <<
") : "
 <<
 this
 <<
 endl
;


	if
 (
fdynm
)
 {
 // name을 貯藏할 空間을 new로 만들었다면 削除 한다.

		cout
 <<
 " delete name = "
 <<
 name
 <<
 endl
;

		delete
 []
 name
;

		name
 =
 NULL
;

	}

}


int
 MyObject
::
counter
 =
 0
;
 // static은 各 客體마다 貯藏空間이 確保 되지 않는다.

                            // 全體에서 單 하나의 變數 空間 만이 存在한다.

                            // public이므로 어디에서나 接近이 可能하다.


char
*
 MyObject::getName
()
 {
 return
 name
;
 }


void
 MyObject::setName
(
char
 *
n
,
 int
 opt
)

{

	if
 (
fdynm
)
 delete
 []
 name
;

	name
 =
 n
;

	fdynm
 =
 opt
;

}


/// 파일 : main.cpp //////////////////////////////////

#include
 <iostream>

#include
 "MyObject.h"

using
 namespace
 std
;


//// 全域變數 //////////////////


MyObject
 gMe
(
19
,
 "洪吉童"
);
 // 客體를 生成하고, 生聖子2을 呼出 한다.


int
 main
(
int
 argc
,
 char
*
 argv
[])

{

	cout
 <<
 "main() 始作.
\n
"
;


	MyObject
 *
pm
 =
 &
gMe
;


	MyObject
::
counter
++
;

	cout
 <<
 MyObject
::
counter
 <<
 " "
 <<
 pm
->
getName
()
 <<
 " / "

 <<
 pm
->
getAge
()
 <<
 endl
;


	MyObject
 kim
;
 // 客體를 生成하고, 生聖子1을 呼出 한다.

	pm
 =
 &
kim
;

	char
 *
pname
 =
 new
 char
[
50
];

	strcpy
(
pname
,
 "李舜臣"
);

	pm
->
setName
(
pname
,
 1
);

	pm
->
setAge
(
33
);


	pm
->
counter
++
;

	cout
 <<
 MyObject
::
counter
 <<
 " "
 <<
 pm
->
getName
()
 <<
 " / "

 <<
 pm
->
getAge
()
 <<
 endl
;


	pm
 =
 new
 MyObject
();
 // 客體를 動的으로 만든다. 生聖子1 使用.

	pm
->
setName
(
"世宗大王"
);

	pm
->
setAge
(
33
);


	MyObject
::
counter
++
;

	cout
 <<
 MyObject
::
counter
 <<
 " "
 <<
 pm
->
getName
()
 <<
 " / "

 <<
 pm
->
getAge
()
 <<
 endl
;

	delete
 pm
;


	cout
 <<
 "main() 끝.
\n
"
;


	return
 0
;

}

</
source
 >

實行結果
 :

 +
生聖子2
 MyObject
(
19
,
洪吉童
)
 :
 00F
DD174

 main
()
 始作
.

 1
 洪吉童
 /
 19

 +
生聖子1
 MyObject
()
 :
 0031F
9
C4

 2
 李舜臣
 /
 33

 +
生聖子1
 MyObject
()
 :
 004
D4948

 3
 世宗大王
 /
 33

 -
消滅子
 MyObject
(
世宗大王
)
 :
 004
D4948

 main
()
 .

 -
消滅子
 MyObject
(
李舜臣
)
 :
 0031F
9
C4

    delete
 name
 =
 李舜臣

 -
消滅子
 MyObject
(
洪吉童
)
 :
 00F
DD174


===
 客體의
 메모리
 救助
 ===


客體는
 클래스에
 依해
 規定된
 救助에
 따라
 메모리
 空間을
 確保하고
 메모리에
 [[
액세스
 (
마이크로프로세서
)
|
액세스
]]
 함으로써
 데이터
 處理가
 된다
.
  救助는
 基本的으로
 struct와
 別로
 다를
 바가
 없다
.
 멤버變數만을
 모아
 順序대로
 羅列하여
 特定
 크기의
 메모리를
 確保하면
 된다
.
 struct에
 C
++
 必要한
 몇가지
 追加될
  있다
.


위의
  프로그램의
 客體構造를
 알기
 爲해
 다음과
 같이
 프로그램
 하면
:


<
syntaxhighlight
 lang
=
"cpp"
>

#include
 <iostream>

#include
 <stdio.h>

#include
 "MyObject.h"

using
 namespace
 std
;


MyObject
 hong
(
19
,
 "洪吉童"
);


int
 main
(
int
 argc
,
 char
*
 argv
[])

{

	MyObject
 *
pm
 =
 &
hong
;


	printf
(
"sizeof(MyObject)=%d
\n
"
,
 sizeof
(
MyObject
)
 );

	printf
(
"&pm=0x%08X, sizeof(pm)=%d
\n
"
,
 &
pm
,
 sizeof
(
pm
)
 );

	printf
(
"pm=0x%08X
\n
"
,
 pm
 );


	printf
(
"&hong=0x%08X, sizeof(hong)=%d
\n
"
,
 &
hong
,
 sizeof
(
hong
)
 );

	printf
(
"&counter=0x%08X, value=%d
\n
"
,
 &
MyObject
::
counter
,
 MyObject
::
counter
);

	printf
(
"&age=0x%08X, value=%d
\n
"
,
 &
hong
.
age
,
 hong
.
age
 );

	printf
(
"&name=0x%08X, value=%s
\n
"
,
 &
hong
.
name
,
 hong
.
name
 );

	printf
(
"&fdynm=0x%08X, value=%d
\n
"
,
 &
hong
.
fdynm
,
 hong
.
fdynm
 );


	MyObject
 lee
(
23
,
 "李舜臣"
);

	printf
(
"&lee=0x%08X
\n
"
,
 &
lee
);


        return
 0
;

}

實行結果 (x86, 32비트) 예 :

+生聖子2 MyObject(19,洪吉童) : 00ACC170
sizeof(MyObject)=16
&pm=0x003EFBA8, sizeof(pm)=4
pm=0x00ACC170
&hong=0x00ACC170, sizeof(hong)=16
&counter=0x00ACC184, value=0
&age=0x00ACC174, value=19
&name=0x00ACC178, value=洪吉童
&fdynm=0x00ACC17C, value=0
+生聖子2 MyObject(23,李舜臣) : 003EFB90
&lee=0x003EFB90
-消滅子 MyObject(李舜臣) : 003EFB90
-消滅子 MyObject(洪吉童) : 00ACC170
x86 32비트 環境에서 客體 救助 예. virtual使用한 境遇.

消滅子 에서 virtual 을 붙이는 가장 重要한 理由는 相續과 關聯하여 消滅者를 正確히 實行하기 위해서이다. 消滅者를 呼出할 때, 이 테이블을 보고 呼出한다.

' static int MyObject::counter ' 變數는 客體와 分離하여 한個의 全域變數로 處理된다. 따라서 이것은 客體의 메모리 크기에 들어가지 않는다. sizeof 演算子에 依해 바이트數를 얻은면 16바이트가 된다. 여러個의 같은 클래스의 客體가 存在해도 이 變數는 하나만 存在할 뿐이다. 그리고 靜寂으로 處理되므로 全域變數만 可能하다.

이제 virtual 을 削除하고 客體를 만들면 멤버變數들로만 構成된 構造를 갖는다.

實行結果 (x86, 32비트) 예 :

+生聖子2 MyObject(19,洪吉童) : 0083C138
sizeof(MyObject)=12
&pm=0x003CFBFC, sizeof(pm)=4
pm=0x0083C138
&hong=0x0083C138, sizeof(hong)=12
&counter=0x0083C148, value=0
&age=0x0083C138, value=19
&name=0x0083C13C, value=洪吉童
&fdynm=0x0083C140, value=0
+生聖子2 MyObject(23,李舜臣) : 003CFBE8
&lee=003CFBE8
-消滅子 MyObject(李舜臣) : 003CFBE8
-消滅子 MyObject(洪吉童) : 0083C138
x86 32비트 環境에서 客體 救助 예. virtual 이 없는 境遇.

이것은 다음 struct 와 메모리 構造가 같다.

/// 파일 : MyStruct.h ///

#ifndef MYSTRUCT_H

#define MYSTRUCT_H


typedef
 struct
 {

   static
 int
 counter
;


   int
 age
;

   char
 *
name
;

   int
  fdynm
;

}
 MyStruct
;


void
 setMyStruct
(
MyStruct
*
 pthis
,
 int
 age
,
 char
 *
name
,
 int
 opt
 =
 0
);


#endif


// 파일 : MyStruct.cpp /////////

#include
 <stdio.h>

#include
 "MyStruct.h"


int
 MyStruct
::
counter
 =
 0
;


void
 setMyStruct
(
MyStruct
*
 pthis
,
 int
 age
,
 char
 *
name
,
 int
 opt
)

{

   pthis
->
age
 =
 age
;

   pthis
->
name
 =
 name
;

   if
 (
pthis
->
fdynm
)
 delete
 []
 pthis
->
name
;

   pthis
->
fdynm
 =
 0
;

}


// 파일 : main.cpp ////////

#include
 <stdio.h>

#include
 "MyStruct.h"


int
 main
()

{

   MyStruct
 stdata
;

   stdata
.
fdynm
 =
 0
;

   setMyStruct
(
&
stdata
,
 11
,
 "Song"
);


   printf
(
"&stdata=0x%08X, sizeof(stdata)=%d
\n
"
,
 &
stdata
,
 sizeof
(
stdata
)
 );

   printf
(
"&counter=0x%08X, value=%d
\n
"
,
 &
MyStruct
::
counter
,
 MyStruct
::
counter
);

   printf
(
"&age=0x%08X, value=%d
\n
"
,
 &
stdata
.
age
,
 stdata
.
age
 );

   printf
(
"&name=0x%08X, value=%s
\n
"
,
 &
stdata
.
name
,
 stdata
.
name
 );

   printf
(
"&fdynm=0x%08X, value=%d
\n
"
,
 &
stdata
.
fdynm
,
 stdata
.
fdynm
 );

   // ...

}

實行結果 (x86, 32비트) 예 :

&stdata=0x0036FBC8, sizeof(stdata)=12
&counter=0x011EC14C, value=0
&age=0x0036FBC8, value=11
&name=0x0036FBCC, value=Song
&fdynm=0x0036FBD0, value=0
x86 32비트 環境에서 C言語의 struct 메모리 救助 예.

멤버 變數 [ 編輯 ]

클래스 內部의 變數를 말 한다. 클래스의 屬性(attribute)이다. 基本 資料型과 다른 클래스 들도 正義가 可能하다.

멤버函數는 프로그램 코드이므로 結局 機械語 코드 묶음에 存在한다. 멤버函數가 實行될 때, 客體의 變數들로 構成된 메모리 構造體의 始作 駐소값으로 傳達되어 造作된다.

客體 空間의 액세스 時, 客體領域 超過 액세스 問題 [ 編輯 ]

C에서도 마찬가지이지만, C++는 團地 메모리의 住所값을 利用하여 액세스하는 單純한 方法을 使用한다. 따라서 配列等에서 定義된 크기보다 큰 인덱스로 쓰기하면, 쓰기 自體에는 아무 問題없이 써진다. 그러나 變數가 차지하고 있는 空間을 넘어서는 問題는 C++에서도 그대로 適用된다. 자바와는 달리 어떤 保護策이 없다.

#include
 <iostream>


class
 A
 {

public
:

   A
()
 {
 num
 =
 0
;
 }

   A
(
int
 n
)
 {
 num
 =
 n
;
 }


   int
 num
;

};


int
 main
(
int
 argc
,
 char
*
 argv
[])

{

    A
 a
(
10
);

    char
 buff
[
4
];

    char
 *
pstr
 =
 buff
;


    std
::
cout
 <<
 "num="
 <<
 a
.
num
 <<
 std
::
endl
;

    printf
(
"&a=0x%08X
\n
"
,
 &
a
);

    printf
(
"buff=0x%08X
\n
"
,
 buff
);


    for
 (
int
 cnt
 =
 0
;
cnt
 <
 16
;
cnt
++
)

	*
pstr
++
 =
 cnt
;


    std
::
cout
 <<
 "num="
 <<
  a
.
num
 <<
 std
::
endl
;


    return
 0
;

}

實行 結果 예 (x86 32비트 CPU, 마이크로소프트 비주얼스튜디오): [note 1]

num=10
&a=0x0027F848
buff=0x0027F83C
num=252579084

여기에서 10이어야 하는 값이 252579084로 바뀌어 졌다. 이것은 16바이트를 쓰면서 buff領域을 넘어서기 때문이다. buff와 客體 a와는

0x0027F848-0x0027F83C=0xC=12

의 空間差異가 난다. 따라서 12바이트 以上 쓰기 하면 a 領域의 값이 變한다.


Notes:

  1. 實行結果에서 메모리 配置는 CPU와 컴파일러/링커에 따라 다를 수 있다. 3個의 變數 位置는 컴파일러 마다 조금씩 差異가 있을 수 있다.

멤버 函數 [ 編輯 ]

클래스의 行爲(behavior)를 定義한 것으로 機能的으로 設定된 프로그램 묶음이다.

this [ 編輯 ]

모든 멤버函數는 멤버變數들로 構成된 構造的 貯藏空間이 必要하다. 各各의 다른 客體는 다른 메모리 空間에 存在 한다. 따라서 여러個의 客體를 區別한 포인터 變數가 必要하다. this는 客體의 位置를 定義하는 포인터 變數라고 생각하면 된다.

어느 客體에 造作을 할것인가를 決定하는 포인터이다. 'this'는 클래스 內에 變數 宣言이 必要없고 이미 定義된 키워드이다.

캡슐化 의 方法으로 멤버函數는 this을 通해 멤버變數와 묶는 方法으로 使用한다.

다음 禮義 構造體와 클래스에서

struct
 MyStruct
 {

   int
 opt
;

   int
 age
;

   char
 *
name
;

};


class
 MyObject

{

public
:

   MyObject
()
 {
 opt
 =
 age
 =
 0
;
 name
 =
 NULL
;}

   void
 MyObject
::
setMyObject
(
int
 age
,
 char
 *
name
,
 int
 opt
 =
 0
);


private
:

   int
 opt
;

   int
 age
;

   char
 *
name
;

};


void
 setMyStruct
(
MyStruct
*
 pthis
,
 int
 age
,
 char
 *
name
,
 int
 opt
/* = 0*/
)

{

   pthis
->
opt
 =
 opt
;

   pthis
->
age
 =
 age
;

   pthis
->
name
 =
 name
;

}


void
 MyObject::setMyObject
(
int
 age
,
 char
 *
name
,
 int
 opt
/* = 0*/
)

{

   this
->
opt
 =
 opt
;

   this
->
age
 =
 age
;

   this
->
name
 =
 name
;

}

위의 例에서 C言語의 struct는 構造體 內의 變數들을 묶어서 메모리에 割當한다.

  • C 言語의 struct : void setMyStruct(MyStruct* pthis , int age, char *name, int opt = 0);
  • C++ 客體의 멤버函數 : void MyObject:: setMyObject(int age, char *name, int opt = 0);

위의 2個의 差異는 'MyObject::'을 붙이면 this 포인터가 自動으로 들어간다. 이를 通해 멤버函數를 클래스와 統合한다. 그러나 C言語의 函數는 어떤 變數의 構造體와 連結이 없다. 必要하면 포인터나 變數를 引受를 통해 넘길 뿐이다. 그러나 C++에서는 this는 반드시 包含 시키는 差異가 있다. static 멤버函數는 this가 넘어가는 것은 除外된다.

static 멤버 函數 [ 編輯 ]

this가 客體의 位置 住所값을 取扱하는 自動 포인터로써 멤버函數가 呼出되면 自動으로 따라 다닌다. 이말은 이미 客體가 存在 한다는 것이다. 그러나 static을 使用하면 特定 客體의 this을 使用하지 않는다. 客體가 이미 存在하는 것은 相關없이 이미 存在하는 客體의 포인터 값을 모른다. 따라서 呼出 할때, 特定 客體가 미리 生成되지 않아도 된다. 이미 生成되었다면 오히려 引受로 넘겨 주어야 한다.

class
 A
 {

public
:

   A
(
int
 n
)
 {
 num
 =
 n
;
 }

   int
 num
;

   int
 add
(
int
 n2
)
 {
 return
 (
num
 +=
 n2
);
 }


   static
 int
 add
(
A
 *
pa
,
 int
 n2
);

};


int
 A::add
(
A
 *
pa
,
 int
 n2
)

{

    //num += n2;  // 誤謬 : this을 使用할 수 없다. 客體의 포인터가 넘어오지 않는다.

 // error C2597: illegal reference to non-static member 'A::num'

    pa
->
num
 +=
 n2
;

    return
 pa
->
num
;

}


int
 main
()

{

    A
 a
(
10
);

    int
 r
 =
 A
::
add
(
&
a
,
 20
);
     // 結果 30

    std
::
cout
 <<
 r
 <<
 std
::
endl
;


    r
 =
 a
.
add
(
&
a
,
 10
);
           // 結果 40

    std
::
cout
 <<
 r
 <<
 std
::
endl
;


    return
 0
;

}

위의 프로그램 예제 코드 처럼, 客體가 없는 狀態에서 實行되는 것이 static 멤버函數이기 때문에 客體의 멤버變數를 使用하지 않아도 된다. 클래스 이름으로 呼出하면 되고 設令 이미 存在하는 客體의 멤버變數로 하더라고 this 가 넘어가지 않으므로 別 差異가 없다. 캡슐化 되지 않는 C 言語의 函數와 別 差異가 없다. C 言語의 函數와의 差異는 但只 '어느 클래스에 屬하는냐'만의 意味만 갖는다.

struct 使用 函數, 客體 멤버變數, static 멤버函數 比較 [ 編輯 ]

struct 使用 函數 客體 멤버變數 static 멤버函數
struct
 MyStruct
 {


   int
 num
;


};





int
 add
(
struct
 MyStruct
 *
pthis
,
 int
 n
)

{
 return
 (
pthis
->
num
 +=
 n
);
 }


// 使用하기

   struct
 MyStruct
 st
 =
 {
 10
 };

   int
 num
;

   num
 =
 add
(
&
st
,
 1
);

class
 MyObject
 {

public
:

   int
 num
;


   MyObject
(
int
 n
)
 :
 num
(
n
)
 {
 }

   int
 add
(
int
 n
);


};


int
 MyObject::add
(
int
 n
)

{
  return
 (
this
->
num
 +=
 n
);
 }


// 使用하기

   MyObject
 obj
(
20
);

   int
 num
;

   num
 =
 obj
.
add
(
1
);

class
 MyObject
 {

public
:

   int
 num
;


   MyObject
(
int
 n
)
 :
 num
(
n
)
 {
 }

   static
 int
 add
(
 MyObject
 *
pthis
,
 int
 n
);

   static
 int
 add
(
int
 n1
,
int
 n2
){
return
 n1
+
n2
;}

};


int
 MyObject::add
(
MyObject
 *
pthis
,
 int
 n
)

{
 return
 (
pthis
->
num
 +=
 n
);
 }


// 使用하기

   MyObject
 obj
(
20
);

   int
 num
 =
 MyObject
::
add
(
&
obj
,
 1
);

   num
 =
 obj
.
add
(
&
obj
,
 1
);

   num
 =
 MyObject
::
add
(
1
,
 2
);

struct(構造體) 와 class(클래스)는 同一 [ 編輯 ]

흔히 構造體는 클래스 以前에 宣言되고 主로 여러種類의 記憶空間을 宣言하기 위한 形態로만 보는 境遇가 一般的인데, 이는 틀린 생각이다. 構造體 亦是 클래스와 同一하게 生聖子와 消滅者를 指定할 수 있고, 코딩이 可能하며 內部呼出과 캡슐化가 可能하다. 따라서, 하나의 物體(Object)를 하나의 構造體(struct) 로 宣言하고 使用할 수 있다. 따라서, 構造體 內에서도 모든 函數와 命令을 클래스와 同一하게 使用 可能하다. 다만, 멤버에 對해 接近 指定者를 써 주지 않는 境遇 構造體는 public이 되고, 클래스는 private이 된다는 差異가 있다.

같이 보기 [ 編輯 ]

各州 [ 編輯 ]

  1. “ISO/IEC 14882:1998” . International Organization for Standardization. 2017年 1月 15日에 原本 文書 에서 保存된 文書 . 2018年 11月 23日에 確認함 .  
  2. “ISO/IEC 14882:2003” . International Organization for Standardization. 2021年 8月 13日에 原本 文書 에서 保存된 文書 . 2018年 11月 23日에 確認함 .  
  3. “ISO/IEC 14882:2011” . International Organization for Standardization. 2016年 5月 27日에 原本 文書 에서 保存된 文書 . 2018年 11月 23日에 確認함 .  
  4. “ISO/IEC 14882:2014” . International Organization for Standardization. 2016年 4月 29日에 原本 文書 에서 保存된 文書 . 2018年 11月 23日에 確認함 .  
  5. “ISO/IEC 14882:2017” . International Organization for Standardization. 2013年 5月 17日에 原本 文書 에서 保存된 文書 . 2017年 12月 2日에 確認함 .  
  6. “ISO/IEC 14882:2020” . International Organization for Standardization. 2020年 12月 16日에 原本 文書 에서 保存된 文書 . 2020年 12月 16日에 確認함 .  
  7. Stroustrup, Bjarne (2010年 3月 7日). “Bjarne Stroustrup's FAQ: When was C++ invented?” . 《stroustrup.com》 . 2010年 9月 16日에 確認함 .  
  8. Stroustrup, Bjarne. “A History of C ++ : 1979? 1991” (PDF) .  
  9. Stroustrup, Bjarne. “The C++ Programming Language” Fir版 . 2010年 9月 16日에 確認함 .  
  10. C++ 은 C 言語를 背景으로 만들어졌기 때문에 C 言語에는 없는 客體志向 프로그래밍을 올린거라 말하면 된다.

外部 링크 [ 編輯 ]