Language

[ C++98, 03, 11, 14, 17 ]

궁금한게 많은 개발자 2021. 6. 18. 15:34

C++98

ISO 표준으로 공식 등록된 첫 버전. 이름 그대로 1998년에 등록

class 가 추가
C++98버전의 class에서는 constructor, destructor, member fuction, friend, user defined data type, virtual function, pure virtual function, pure virtual class, inheritance, multiple inheritance. 

C언어에 비해 강력한 type checking

User-defined data type이 많이 사용되는 C++ 입장에서는 당연한 결과이기도 합니다.
하지만, 익숙해지면 오히려 에러도 잘 잡히고, 잠재적인 버그도 많이 걸러주기 때문에 좋은 점

새로운 주석 형식 ( // )이 추가

C에서는 사실 주석 달려면 작정하고 해야할 정도로 살짝 귀찮았었죠.

const 타입이 추가
- #define 으로 사용하던 상수를 대체하여 literal이 아닌 type을 가진 constant를 사용할 수 있게 되었습니다.
- 함수의 argument로도 사용할 수 있어서, 이 경우 pointer를 함수에 전달할 때 발생할 수 있는 side-effect를 설계과정에서 차단
- 부가적으로 이미 type이 지정되고, 해당 type으로 value가 존재하기 때문에 상수 사용에 따른 자동 형변환 등의 오버헤드를 줄여줄 수 있습니다.

inline 함수가 추가되었습니다.

이 부분은 전적으로 run-time performance에 관련된 부분이라고 봅니다. 선택적인 사항이기도 합니다만, 간단한 기능의 함수를 아무런 성능상의 부담없이 함수로 분리할 수 있는 여건이 마련된 것이죠.

단, 주의할 점은 inline 함수는 논리적으로 함수를 #include 하듯이 쓰는 녀석인지라 주의할 점이 있습니다.

즉, 너무 큰 함수를 inline으로 설계하거나, inline 함수를 너무 남용해서 공룡같은 함수를 만들어낼 가능성도 존재한다는 겁니다. 특히나 한정적인 메모리를 가진 embedded system에서 (역시나) 한정된 성능의 하드웨어 하에서 성능을 끌어올린답시고 남용하다간 code overflow 라는 신기한 경험을 하게 될 가능성도 있습니다.

default argument가 제공

레퍼런스 타입이 추가

요거 참 유용합니다. 이 덕분에 C++에서도 Call-by-reference가 가능. 특히나 class로 대변되는 user-defined type을 매개변수로 전달할 때 심각한 암묵적인 형변환이나 복사문제에서 해방될 수 있습니다. 단, 그 장점만큼이나 side effect는 주의해서 사용해야 합니다. 하지만, const 만 잘 활용해도 이런 문제는 거의 해결할 수 있습니다.

함수 overloading이 지원됩니다. (연산자 overloading이 지원됩니다.)

심지어 연산자도 하나의 operator function으로 정의될 수 있기 때문에 overloading 할 수 있습니다.
한 가지 주의할 부분은 연산자를 overloading할 경우 그 우선순위는 원래의 연산자(기본 type에서 쓰이는)가 가지는 우선순위를 그대로 따른다는 점에 유의하셔야 합니다.

extern "C" {} 를 이용하여 C 스타일 코드를 링크할 수 있습니다.

C에 익숙하고 C++가 C를 완전히 포함하고 있다고 '착각' 하시는 분들에게는 이게 도대체 왜 필요한건지 모를 수도 있습니다. 실제로 프로그램 코드가 컴파일 되면 우리가 보고 있는 함수들의 이름은 눈에 보이는 대로의 이름을 가지지 않습니다. 만약, 눈에 보이는 대로의 이름을 가지고 있다면 overloading된 함수들은 이름만으로 구분지을 수 없을테니까요.

template가 지원

exception handling이 지원

C++ 스타일의 입출력 스트림 라이브러리가 제공

cout << "Hello, C++" << endl;

C++ 스타일의 메모리 할당 연산자 new와 delete가 제공됩니다.

C에서 malloc과 free를 쓰던 부분을 대체할 수 있는 연산자입니다. C++답게 type을 기반으로 만들어진 것이라 malloc처럼 일일이 byte 단위로 계산해줘야하는 번거로움은 사라졌습니다. 심지어 이것도 연산자라고 overloading이 가능하기 때문에 활용방법이 많습니다.

 

 

 

C++03

C++03의 가장 큰 특징은 STL이 정식으로 C++의 표준 라이브러리로 제공되었다는 점

bool type이 새로 추가

C++스타일의 type casting은 네 가지다. (static_cast, dynamic_cast, reinterpret_cast, const_cast)
C 스타일로 이 상속관계에 있는 클래스들을 함부로 형변환 했다가는 이 virtual table을 싹 날려먹어서 run-time 에러를 유발할 가능성이 생기기 때문이다. (실제로 C++98에서는 이런 문제를 해결할 방법이 없었다) 그래서 만들어 진 것이 dynamic_cast이다. dynamic_cast를 사용할 경우, virtual table을 포함한 object를 안전하게 형변환 할 수 있다. 그러다보니, 원래 C 스타일의 형변환과 비슷한 방식도 가능해야겠다 싶으니 static_cast와 reinterpret_cast도 만들어졌고, 변수의 상수성을 날려버리는 const_cast도 만들어졌다.

(실제로 C 스타일의 형변환을 실행하면 static_cast, reinterpret_cast, const_cast 가 동시에 행해지는 역할

RTTI(run-time-type-information)는 사실 중요한 부분이다. C나 C++를 사용할 경우, 특히 void* 타입으로 매개변수를 전달받았을 때 실제로 이놈이 뭘 가리키고 있는 포인터인지 알면 좋겠다는 경우를 많이 겪어봤을거다. C++에서는 이런 경우가 더 빈번히 발생하는데, 복잡한 구조의 클래스 계층 때문에 발생하는 경우가 많다. 그래서, typeid 이라는 연산자를 제공해서 이러한 문제를 해결할 수 있도록 해주고 있다. 그런데, 이거 사용하는걸 별로 권장하질 않는다. 이유는 딱 하나, "느리다"는 이유다.

사용방법은 그리 어렵지 않다. #include <typeinfo> 해주고 쓰면된다. typeid(int) 라고 적던가, typeid(i) 라고 적으면 해당 타입이나 변수의 type_info를 얻어낼 수 있다. 하지만, run-time 이라는 이름이 들어간 순간 "느리다".

대부분 "느리다"의 문제는 "꼭 필요할 때만 써라"는 결론을 얻게 되고, 꼭 필요한 순간을 최소화 하기 위해서는 "잘 설계해라"는 결론이 얻어진다. 왠만하면 잘 설계해서 RTTI는 쓸 일 없게 만드는게 정신건강에 이롭다.

namespace등장

STL은 원래 C++의 표준이 아니었다. 흔히 Generic Programming이라는 표현을 쓰는 '데이터 타입에 구애받지 않은 프로그램 구현'을 목표로 한 시도가 이전에도 많이 있었다. 그러던 중 C++의 template가 이에 적합하다는 의견
STL은 C++의 표준 라이브러리로 포함되었고, 덕분에 C++만 배우면 쉽게 스택이나 큐 같은 자료구조도 사용할 수 있게 되었다.

 

 

C++11

auto 타입
auto 타입은 초기화 과정에서 타입이 결정

range-for statement for( auto& i : ut )

nullptr 더이상 #define NULL 0 은 쓸 일이 없다.

final

C++에도 드디어 final이 생겼다. 더 이상 계승할 수 없는 클래스를 꼼수 안쓰고 만들 수 있게 되었다. (이전까지는 private와 friend를 꼬아서 쓰는 꼼수로만 가능했다)

extern template
C++03에서는 template을 여러 파일에서 동시에 사용하기 위해서는 일일이 include해주고, 그러다보면 컴파일에 걸리는 시간이 엄청나게 증가할 가능성이 있었는데, C++11에서는 이를 방지하기 위해 template도 extern으로 선언할 수 있도록 개선되었다.

lambda expression
C++11에서 가장 생소하게 느껴지는 부분이 아닐까 싶은 lambda expression이 추가

기존의 함수 포인터를 이용할 때, 함수포인터를 vector 형태 등으로 묶음을 만들어 사용할 경우 일일이 함수를 정의하고, 각각의 이름을 지어서, 다시 그 함수들의 포인터를 vector에 집어넣는 불편함이 있었다면, 함수의 이름은 지정할 필요없이 lambda function들을 정의해서 vector에 집어넣을 수 있게 되었다.

[](int x, int y) { return x + y; 

https://drasley.tistory.com/51

 

C++ 버전별 변천사 #3 - C++11

이번에 소개할 버전은 C++11입니다. 한 가지 사과의 말씀을 드려야할 것이 C++11을 정리하려다보니 내가 여지껏 C++0x라는 명칭을 잘못 사용하고 있었더군요. C++0x는 C++11이 원래 2008년에 표준화될 계

drasley.tistory.com