C++

C++ 프로그래밍 언어 (책) df=yes **C++**는 AT&T; 벨 연구소의 비야네 스트롭스트룹이 C언어 기반으로 1985년에 발표하여 발전한 프로그래밍 언어이다.
# 역사
{| class="wikitable floatright" |+C++ 표준 |- !scope="col"| 연도 !scope="col"| C++ 표준 !scope="col"| 비공식 명칭 |- !scope="row"| 1998 | | ISO/IEC 14882:1998url-status=live || C++98 |- !scope="row"| 2003 | | ISO/IEC 14882:2003url-status=live || C++03 |- !scope="row"| 2011 | | ISO/IEC 14882:2011url-status=live || C++11, C++0x |- !scope="row"| 2014 | | ISO/IEC 14882:2014url-status=live || C++14, C++1y |- !scope="row"| 2017 | | ISO/IEC 14882:2017url-status=live || C++17, C++1z |- !scope="row"| 2020 | | ISO/IEC 14882:2020url-status=live || C++20, C++2a |} 1979년, 덴마크의 컴퓨터 과학자 비야네 스트롭스트룹은 C++의 선구자격 언어인 "C with Classes" 작업에 착수하였다.accessdate = 16 September 2010 새로운 언어를 만들려는 의의는 박사 논문을 위한 스트롭스트룹의 프로그래밍 경험에서 비롯되었다. 처음에 스트롭스트룹의 "C with Classes"는 C 컴파일러(Cpre)에 클래스, 상속 클래스, 스트롱 타이핑, 인라인 확장, 기본 인수를 포함한 여러 기능들을 추가하였다.url=http://www.stroustrup.com/hopl2.pdf 1983년, "C with Classes"라는 이름은 가상 함수, 함수 이름, 연산자 오버로딩, 참조, 제약조건, type-safe free-store 메모리 할당 (new/delete), 개선된 자료형 검사, BCPL 스타일의 1줄 코멘트(//)를 포함한 새로운 기능들을 추가하면서 "C++"로 변경되었다. 1985년 C++ 프로그래밍 언어 제1판이 출시되었으며 당시 공식표준이 없었기 때문에 이 언어의 절대적인 참조 문헌이 되었다.accessdate = 16 September 2010 최초의 C++ 상용 구현체는 같은 해 10월에 출시되었다.
# 특징
C 언어에 객체지향 프로그래밍을 지원하기 위한 내용이 덧붙여진 것이라고 할 수도 있지만C++ 은 C 언어를 배경으로 만들어졌기 때문에 C 언어에는 없는 객체지향 프로그래밍을 올린거라 말하면 된다., 애초부터 객체지향을 염두에 두고 만들어진 언어와는 다르게, 단지 더 좋은 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이라는 헤더를 가져온다 using namespace std; //namespace의 std 모듈을 사용한다 int main() { //메인메소드의 시작지점이다. cout link)+sizeof(int)*2; pmsg->link = NULL; pmsg->szdata = sizeof(A); pmsg->szpkg = szpkg; A *pa = (A*) &pmsg-;>data; pa->num = 10; std::cout num 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 #include "MyObject.h" using namespace std; MyObject::MyObject() // 생성자1 { age = 0; name = NULL; fdynm = 0; cout age = age; this->name = name; cout getName() getAge() setName(pname, 1); pm->setAge(33); pm->counter++; cout getName() getAge() setName("세종대왕"); pm->setAge(33); MyObject::counter++; cout getName() getAge() age = age; pthis->name = name; if (pthis->fdynm) delete [] pthis->name; pthis->fdynm = 0; } // 파일 : main.cpp //////// #include #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 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 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 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이 된다는 차이가 있다.