C++

C++는 AT&amp;T 벨 연구소의 비야네 스트롭스트룹이 C언어 기반으로 1983년 발표하여 발전한 프로그래밍 언어이다.
역사.
1979년, 덴마크의 컴퓨터 과학자 비야네 스트롭스트룹은 C++의 선구자격 언어인 "C with Classes" 작업에 착수하였다. 새로운 언어를 만들려는 의의는 박사 논문을 위한 스트롭스트룹의 프로그래밍 경험에서 비롯되었다.
처음에 스트롭스트룹의 "C with Classes"는 C 컴파일러(Cpre)에 클래스, 상속 클래스, 스트롱 타이핑, 인라인 확장, 기본 인수를 포함한 여러 기능들을 추가하였다.
1983년, "C with Classes"라는 이름은 가상 함수, 함수 이름, 연산자 오버로딩, 참조, 제약조건, type-safe free-store 메모리 할당 (new/delete), 개선된 자료형 검사, BCPL 스타일의 1줄 코멘트(//)를 포함한 새로운 기능들을 추가하면서 "C++"로 변경되었다.
1985년 C++ 프로그래밍 언어 제1판이 출시되었으며 당시 공식표준이 없었기 때문에 이 언어의 절대적인 참조 문헌이 되었다. 최초의 C++ 상용 구현체는 같은 해 10월에 출시되었다.
특징.
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++ 표준의 모든 사항을 완전하게 지원하는 컴파일러는 현재 손꼽을 정도이다.
덧붙여 예부터 전해 내려온 절차적인 성격도 그대로 남아 "만능" 설계로, 유연함과 강력함은 다른 언어에 비할 바가 아니지만, 복잡한 언어가 되고 말았다. 이런 점 때문에 보다 객체지향성을 강화하여, 만능설계를 지향하기보다는 단순한 설계를 목표로 한 새로운 언어들인 Java, C#, D 언어 등이 나오기도 했다.
캡슐화.
캡슐화는 2가지 요소를 만족하도록 언어적으로 구현 되어야 한다.
C++에서는 객체의 저장공간의 위치(this로 표현되는 객체의 데이터 위치 주소값)를 함수에 넘김으로써 데이터와 메서드를 결합한다. this는 객체의 위치 주소값인 포인터이다.
객체 지향 프로그래밍에서 작성된 프로그램 코드는 재사용이 중요한 요소이다. 재사용하려면 다른 개발자가 사용할 때, 필요한 사용방법만 알면된다. 클래스 내면 깊숙히 알 필요가 없는 경우가 많다. 따라서 객체를 설계할 때, 경우에 따라 멤버 변수나 멤버 함수를 다 알릴 필요가 없다. 어떤 요소들은 내부에서 사용하고 비공개로 설정할 필요가 있다. 해당 객체를 사용하거나 상속해서 사용할 때, 필요한 요소만을 공개하고 API을 작성하여 공개하면 된다. 이런 비공개의 방법으로 은닉을 설정하고 캡슐화의 한요소가 된다.
키워드 3개가 있다. private, protected, public을 사용해서 접근을 제한할 수 있다.
class MyObject {
public:
 int getData(); // 은닉된 데이터는 메서드를 사용하여 인터페이스로 쓸 수 있다.
private: // 이 지정자는 자기 클래스에서만 액세스를 한정한다. 은닉하는 방법으로 사용.
 int m_data;
int MyObject::getData()
 return this-&gt;m_data; // this가 자동으로 넘어온다.
여기서 데이터와 메서드 결합은 멤버함수를 구성할 때 this라는 포인터로 상징되는 것을 개발자 코드내에 코딩없이도 자동으로 넘겨 주어 해당 클래스 내의 멤버변수들을 사용하게 하였다. 이렇게 언어적으로 결합한다.
this는 자동으로 객체의 공간위치값이 메모리의 주소값이다. 이것을 포인터로 사용하였다. 이것으로 결국 어떤 객체인지를 구별하는 수단으로 사용하여, 데이터와 메서드를 결합한다. MyObject::가 붙는 클래스의 멤버함수는 실행할 때 자동으로 모두 this가 넘어간다. static 메서드는 this가 제외된다.
this가 멤버 함수에 넘어가는 방법으로 CPU의 레지스터를 사용할 수도 있다. 멤버 함수에서 멤버 변수를 사용할 때 레지스터에 저장된 객체의 위치 주소값으로 하여 내부 멤버변수의 상대주소값과 합하여 위치값을 다시 설정하고 액세스 하면 된다. 이것은 마치 struct의 시작주소와 내부변수의 상대적 위치값의 합으로 표현하는 주소체계와 유사하다.
예제.
Hello world 프로그램.
C++ 표준 라이브러리 스트림 기능을 사용하여 표준 출력을 통해 codice_1를 출력한다.
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언어에서 전역변수, 지역변수가 있듯이 객체도 선언 위치에 따라 생성과 소멸이 다르다.
객체 만들기 :
객체 소멸 :
접근자.
클래스는 캡슐화가 가능하다. 따라서 객체를 설계할 때는 특정 멤버변수나 멤버함수를 외부에서 접근을 제한할 필요가 있다.
접근 제어 키워드 3가지:
객체의 생성.
C언어에서는 전역변수와 지역변수 그리고 동적할당에 의한 데이터 저장공간을 만들 수 있다. 마찬가지로 C++에서도 전역변수로 객체를 생성할 수도 있고 지역변수로 생성하는 것도 가능하다. 또한 new를 통해 동적으로 객체를 생성 시킬 수 있다.
정적 할당 객체.
C++에서 변수를 잡듯이 객체도 선언을 통해 이루어진다. C에서 전역변수와 지역변수로 나누어는 것과 같이, 객체 역시 같은 방식으로 전역 또는 지역 객체로 선언할 수 있다.
전역 정적 객체는 main() 함수가 실행되기 전 저장공간이 생성되고, 생성자가 호출된다. 객체가 생성되면 메모리에 데이터 저장공간이 생기고 바로 생성자가 호출된다. 따라서 전역 정적 객체 생성자의 호출은 main함수보다 먼저 이루어진다.
동적 할당 객체.
new에 의해 생성 되고, delete에 의해 삭제된다. new로 생성 되면, new 실행 시점에서 객체의 저장공간인 메모리를 확보하고 생성자가 자동실행된다. 동적객체는 힙영역에 존재하고 포인터를 넘겨 받아서 객체 포인터 변수에 주소값을 저장하고 처리한다.
'new'의 코딩은 함수에 넣을 수 밖에 없으므로 main 함수 시작 이후에야 가능하다.
이미 설정된 메모리 공간을 이용하여 객체 정의하기.
C/C++은 포인터를 사용한다. 이것은 객체의 크기만 확보되면 객체를 사용하는데 아무 문제가 없다. 따라서 이미 설정된 변수를 포인터를 이용하여 객체화 해서 사용할 수 있다.
typedef struct MsgBuff {
 MsgBuff *link;
 int szpkg;
 int szdata;
 void *data;
} MsgBuff;
class A {
public:
 int num;
char gbuff[1024];
int main(int argc, char* argv[])
 MsgBuff *pmsg = (MsgBuff*) gbuff;
 int szpkg = sizeof(A)+sizeof(pmsg-&gt;link)+sizeof(int)*2;
 pmsg-&gt;link = NULL;
 pmsg-&gt;szdata = sizeof(A);
 pmsg-&gt;szpkg = szpkg;
 A *pa = (A*) &amp;pmsg-&gt;data;
 pa-&gt;num = 10;
 std::cout « pa-&gt;num « std::endl;
 return 0;
블럭에서의 정적 클래스 생성과 소멸.
using namespace std;
class A {
public:
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;
실행결과:
모든 함수는 블럭을 포함하므로 함수내에서 생성된 정적객체는 함수의 블럭이 끝나면 소멸자가 호출되고 객체의 저장공간은 사라진다. 위의 예처럼 임의의 블럭에서 생성된 정적객체 역시 자기의 블럭이 끝나면 소멸자가 호출되고 사라진다.
클래스 변수 선언 시, 클래스 간 교착상태.
클래스 내에서 멤버변수로 다른 클래스를 사용할 수 있다. 정적 멤버변수와 포인터가 가능하다. 그러나 2개의 클래스가 서로 정적인 객체를 선언하면 교착상태로 빠져 객체의 크기를 결정할 수 없다. 따라서 불가능해 진다.
struct(구조체) 와 class(클래스)는 동일.
흔히 구조체는 클래스 이전에 선언되고 주로 여러종류의 기억공간을 선언하기 위한 형태로만 보는 경우가 일반적인데, 이는 틀린 생각이다. 구조체 역시 클래스와 동일하게 생성자와 소멸자를 지정할 수 있고, 코딩이 가능하며 내부호출과 캡슐화가 가능하다. 따라서, 하나의 물체(Object)를 하나의 구조체(struct) 로 선언하고 사용할 수 있다. 따라서, 구조체 내에서도 모든 함수와 명령을 클래스와 동일하게 사용 가능하다. 다만, 멤버에 대해 접근 지정자를 써 주지 않는 경우 구조체는 public이 되고, 클래스는 private이 된다는 차이가 있다.