C는 C ++와 어떻게 다릅니 까?


21

많은 사람들이 C ++이 C와는 완전히 다른 언어라고 말했지만 Bjarne 자신은 C ++이 C에서 확장 된 언어이므로 그 ++유래 가 어디인지에 대해 말했습니다 . 그렇다면 왜 C와 C ++가 완전히 다른 언어라고 계속 말하는가? C ++의 확장 기능 이외의 C와 C ++의 차이점은 무엇입니까?


3
사용 방법으로 인해. 확실히 C ++로 C를 쓸 수는 있지만 그렇게해서는 안됩니다.
Ed S.

답변:


18

C ++ 개발이 시작된 1980 년대에 C ++은 거의 C의 적절한 수퍼 셋이었습니다. 이것이 바로 시작이었습니다.
그러나 언어 간 호환성이 항상 중요한 것으로 여겨지더라도 시간이 지남에 따라 C와 C ++ 모두 진화하고 서로 달라졌습니다.

또한 C와 C ++의 기술적 차이로 인해 해당 언어의 일반적인 관용구가 만들어졌으며 '좋은 습관'으로 간주되는 것이 더욱 다양해졌습니다.

이것이 "C / C ++와 같은 언어는 없다"또는 "C와 C ++는 서로 다른 언어이다"와 같은 말을하는 사람들의 원동력입니다. C와 C ++ 컴파일러 모두에 허용되는 프로그램을 작성할 수는 있지만 일반적으로 코드는 좋은 C 코드의 예나 좋은 C ++ 코드의 예가 아닌 것으로 간주됩니다.


첫 번째 단락이 맞지 않다고 생각합니다. C는 항상 암시 적 캐스팅을 void *받았지만 C ++은 결코 캐스트 하지 않았다고 생각합니다. (공감하지 않았 음)
대안적인

5
@mathepic : "항상"을 정의하십시오. C는 C ++에서 void * 유형을 사용했습니다. K & R C에서의 malloc 숯불 복귀시켰다 *
네만 Trifunovic

19

Stroustrup 자신 은 FAQ에서 다음 과 같이 대답합니다 .

C ++은 거의 모든 C를 하위 집합으로 유지하는 C의 직계 자손입니다. C ++는 C보다 강력한 유형 검사를 제공하고 C보다 광범위한 프로그래밍 스타일을 직접 지원합니다. C ++는 C를 사용하여 수행 된 프로그래밍 스타일을 더 나은 유형 검사 및보다 많은 표기법 지원 (손실없이)으로 지원한다는 점에서 "더 나은 C"입니다 효율성). 같은 의미에서 ANSI C는 K & R C보다 나은 C입니다. 또한 C ++는 데이터 추상화, 객체 지향 프로그래밍 및 일반 프로그래밍을 지원합니다.

C.에 "완전히 다른"메이크업의 C ++에서 해당 객체 지향 프로그래밍 및 일반 프로그래밍을위한 그것의 지원을 할 수 있습니다 거의 (당신이 엄격한 유형 검사 돌볼만큼)를 C ++ 컴파일러로 컴파일 한 후 순수 C를 작성하고. 그러나 여전히 C를 작성하고 있습니다. C ++을 작성하지 않습니다.

C ++를 작성하는 경우 객체 지향 및 템플릿 기능을 사용하고 있으며 C에서 볼 수있는 것과는 다릅니다.


"C에서 볼 수있는 것과는 다릅니다." 이 문구는 웃기게 들린다! "C 참조". C의 C! 이것은 일종의시입니다.
Galaxy

13

간단히 말해 C에서 관용어로 간주되는 것은 C ++에서 관용적이지 않습니다.

C와 C ++는 사람들이 사용하는 방식 때문에 실제로는 매우 다른 언어입니다. C는 미니멀리즘을 목표로합니다. C ++은 많은 기능을 가진 매우 복잡한 언어 입니다.

C는 거의 모든 언어에서 쉽게 호출 할 수 있으며 종종 플랫폼의 ABI를 정의하지만 C ++은 다른 라이브러리에서 사용하기가 매우 어렵습니다. 대부분의 언어에는 C로 FFI 또는 인터페이스가 있으며 C ++로 구현 된 언어 (예 : Java)도 있습니다.


4
C 스타일 코드가 C ++에서 비 이디어 틱한 것은 아닙니다. C 스타일 코딩은 예외 안전이 없기 때문에 실제로 C ++에서 문제가 됩니다.
dan04

4

C ++이 객체 지향 프로그래밍을 지원한다는 명백한 사실 외에도, 당신은 여기에 당신의 대답이 있다고 생각합니다 : http://en.wikipedia.org/wiki/Compatibility_of_C_and_C++

이 기사에는 C에서는 좋지만 C ++에서는 그렇지 않은 것을 보여주는 코드 예제가 포함되어 있습니다. 예를 들어 :

int *j = malloc(sizeof(int) * 5); /* Implicit conversion from void* to int* */

C 프로그램을 C ++로 포팅하는 것은 종종 간단하며 대부분 컴파일 오류 수정 (캐스트, 새 키워드 추가)으로 구성됩니다.


4
이와 같은 프로그램을 이식해도 C ++ 프로그램은 제공되지 않습니다. C ++ 컴파일러에서 컴파일 할 수있는 C를 제공합니다. 그것은 C ++로 만들지 않습니다 (여전히 결과 코드 C를 호출합니다 (클래스가있는 C조차도 아님)).
Martin York

@MartinYork 나쁜 C라고 부르면 의미가 다를 수 있다고 지적하고 동의합니다. 결과는 분명히 C입니다.
중복 제거기

2

C ++는 새로운 기능뿐만 아니라 새로운 개념과 관용구를 C에 추가합니다. C ++과 C는 밀접하게 관련되어 있지만, 언어로 효과적으로 작성하려면 해당 언어의 스타일로 생각해야합니다. 최고의 C 코드조차도 C ++의 다른 강점과 관용구를 활용할 수 없으므로 실제로 C ++ 코드 가 나쁘지 않을 가능성이 높습니다 .


2

"확장 된 기능"은 V ++에서 추가 된 것처럼 variadic 매크로 또는 그와 비슷하게 들립니다. C ++의 "확장 된 기능" 은 언어를 완전히 개편 한 것으로, 새로운 C ++ 기능이 원래 C 기능보다 훨씬 우수하여 대부분의 경우 원래 C 기능이 완전하고 완전히 중복되므로 최상의 C 사례를 대체합니다. . C ++가 단순히 C를 확장한다고 제안하는 것은 현대 전투 탱크가 전쟁을 벌일 목적으로 버터 나이프를 확장한다는 것을 암시합니다.


C ++에 C가 가지고 있지 않은 더 유용한 기능 중 하나의 예를 열거 할 수 있습니까?
Dark Templar

2
@DarkTemplar : RAII를 사용한 손쉬운 모드 리소스 관리는 어떻습니까? 아니면 템플릿을 사용하여 좋은 일반적인 데이터 구조? 먼저 시작하십시오.
DeadMG

1

차이점은 C에서는 절차 적으로 생각하고 C ++에서는 객체 지향 방식으로 생각한다는 것입니다. 언어는 매우 비슷하지만 접근 방식은 매우 다릅니다.


C에도 구조체가 없습니까? C 파일 자체는 별도의 모듈 (기본적으로 객체)이 아닌가? 절차 적 객체 지향과 객체 지향의 정확한 차이점이 무엇인지 잘 모르겠습니다.
Dark Templar

1
당신은 내 요점을 설명했습니다. 절차 적 또는 객체 지향적 인 방식으로 언어 또는 사고 방식으로 글을 쓸 수있게하는 것은 언어의 제한이 아닙니다.
Ant

0

C ++는 구문 용어로 C의 수퍼 세트 일 수 있습니다. 즉 C 프로그램의 모든 구성은 C ++ 컴파일러로 컴파일 할 수 있습니다.

그러나 C 프로그램을 사용했을 때와 거의 같은 방식으로 C ++ 프로그램을 작성하지는 않습니다. 이 목록은 끝이 없을 수도 있고 철저한 보고서로 추가하기 위해 더 많은 연구를 수행해야 할 수도 있습니다. 그러나 주요 차이점을 만드는 몇 가지 포인터를 사용하고 있습니다.

현재 게시물의 요점은 C ++에는 C와 동등한 것이 컴파일 가능하더라도 훌륭한 C ++ 프로그래머가 프로그래밍 모범 사례로 사용해야하는 다음과 같은 기능이 있다는 것입니다.

C ++에서 C보다 어떻게해야합니까?

  1. 클래스 및 상속. 그것은 프로그래밍 표현을 매우 강력하게 만드는 체계적인 객체 지향을 허용하는 가장 중요한 차이점입니다. 나는이 점을 더 잘 설명 할 필요가 없다고 생각합니다. C ++에 있다면 거의 항상 클래스를 사용하는 것이 좋습니다.

  2. 민영화-수업, 심지어 구조물에는 개인 회원이 있습니다. 이것은 클래스의 캡슐화를 가능하게합니다. C와 동등한 것은 응용 프로그램이 내부 변수에 액세스 할 수 없도록 응용 프로그램에 객체를 void *로 유형 캐스팅하는 것입니다. 그러나 C ++에서는 public 클래스와 private 클래스를 가진 요소를 가질 수 있습니다.

  3. 참조로 전달하십시오. C ++에서는 전달 포인터가 필요한 참조를 기반으로 수정을 허용합니다. 참조 별 통과는 코드를 매우 깨끗하게 유지하고 포인터 위험에 대해 더 안전합니다. C 스타일 포인터를 전달 하면 작동하지만 작동하지만 C ++ 인 경우 가능한 한 더 좋습니다.

  4. 새롭고 삭제 대 malloc 및 무료. new () 및 delete () 문은 메모리를 할당 및 할당 해제 할뿐만 아니라 체인에서 소멸자의 일부로 코드를 실행할 수도 있습니다. C ++를 사용하는 경우 실제로 malloc을 사용하고 무료로 사용하는 것은 좋지 않습니다.

  5. IO 유형 및 연산자 오버로드 연산자 오버로드는 코드를 잘 읽거나 이해하기 쉽게 작성합니다. << 및 >> io 연산자와 동일합니다. 이 작업을 수행하는 C 방법은 함수 포인터를 사용하는 것이지만 어지럽고 고급 프로그래머에게만 해당됩니다.

  6. "문자열"을 사용합니다. C의 char *는 모든 곳에서 작동합니다. 따라서 C와 C ++는 거의 같습니다. 그러나 C ++에 있다면 String 클래스를 사용하는 것이 항상 훨씬 좋습니다 (거의 모든 것 인 배열의 실행 위험을 방지하는 String 클래스를 사용하는 것이 더 안전합니다).

나는 여전히 C ++ 1 에서 열광하지 않을 것이다 . 템플릿-많은 코드에서 무거운 템플릿을 사용하지는 않지만 라이브러리에 매우 강력한 것으로 판명 될 수있다. C에는 그와 거의 동등한 것이 없습니다. 그러나 평상시에는 특히 수학적으로 누락 된 경우.

  1. 스마트 포인터-예, 매우 똑똑합니다! 그리고 가장 똑똑한 것들처럼-그들은 좋은 시작하고 나중에 더러워집니다! 나는 사용하고 싶지 않다

C에 대해 좋아하고 C ++에서 놓친 것들

  1. 함수 포인터를 사용한 다형성 알고리즘 C에서는 복잡한 알고리즘을 실행할 때 함수 포인터 세트를 사용할 수 있습니다. 이것은 진정한 다형성 을 강력한 방식으로 만듭니다. 당신이 C에있을 때 ++는 CAN 함수 포인터를 사용 -하지만 그건 나쁜입니다. 당신은 방법을 사용해야합니다-그렇지 않으면 지저분한 준비를하십시오. C ++ 클래스에서 다형성의 유일한 형태는 함수와 연산자 오버로딩이지만 매우 제한적입니다.

  2. 간단한 스레드. 스레드를 만들 때 pthread는 매우 간단하고 관리 가능합니다. 클래스에 "비공개"인 스레드를 작성해야 할 때가됩니다 (따라서 개인 멤버에 액세스 할 수 있도록). 이 부스트 기본 C에서 아무것도하지만 ++ - 프레임 워크의 유형.

디판


0

특정 언어 기능은 추가하더라도 언어가 실제로 필요한 방식을 완전히 바꿀 수 있습니다. 일례로이 경우를 고려하십시오.

lock_mutex(&mutex);

// call some functions
...

unlock_mutex(&mutex);

위의 코드가 C ++로 구현 된 함수 호출과 관련된 경우, 함수 호출 중 하나가 발생하여 예외적 인 경로에서 뮤텍스를 잠금 해제하지 않으므로 문제가 발생할 수 있습니다.

소멸자는 프로그래머가 그 시점에서 리소스를 해제 / 해제하는 것을 잊어 버리지 않도록 더 이상 편의의 영역에 있지 않습니다. RAII는 사소하지 않은 예제에서 발생할 수있는 모든 단일 코드 행을 예상 할 수 없기 때문에 실질적인 요구 사항이됩니다 (해당 행은 지금 던질 수는 없지만 나중에 변경 될 수 있음은 말할 것도 없습니다). 다른 예를 들어 보자.

void f(const Foo* f1)
{
    Foo f2;
    memcpy(&f2, f1, sizeof f2);
    ...
}

이러한 코드는 일반적으로 C에서 무해하지만 C ++의 지옥 불 지배적 인 혼란과 같습니다. 불러 memcpy가 이러한 객체의 비트와 바이트를 넘어서고 복사 생성자와 같은 것을 우회하기 때문입니다. 이러한 기능이 좋아 memset, realloc, memcpy, 등, C 개발자들 사이 매일 도구는 비트 오히려 균일 한 방법으로 사물을 보는 데 사용하고 메모리에 바이트 동안, C의 더 복잡하고 풍부한 유형 시스템 ++와 조화되지 않습니다. C ++은 사용자 정의 형식에 대한 훨씬 더 추상적 인 관점을 권장합니다.

따라서 이러한 유형의 작업은 더 이상 C ++을 올바르게 사용하려는 사람은 C의 단순한 "슈퍼 셋"으로 간주하여 더 이상 C ++에 사용할 수 없습니다. 이러한 언어는 매우 다른 사고 방식, 훈련 및 사고 방식을 가장 효과적으로 사용해야합니다. .

나는 C ++을 모든면에서 낫게 보는 캠프에 있지 않으며 실제로 가장 좋아하는 타사 라이브러리는 대부분 어떤 이유로 든 C 라이브러리입니다. 왜 정확한지 모르겠지만 C 라이브러리는 본질적으로 더 미니멀 한 경향이 있습니다 (아마도 그러한 풍부한 유형의 시스템이 없기 때문에 개발자는 크고 계층화 된 추상화 세트를 작성하지 않고도 필요한 최소한의 기능을 제공하는 데 더 집중할 수 있기 때문입니다) 비록 종종 내 목적에 맞게 사용법을 단순화하고 조정하기 위해 C ++ 래퍼를 배치하는 것이지만, 그렇게 할 때조차도 미니멀리스트 특성이 선호됩니다. 나는 그런 자질을 찾는 데 여분의 시간이 걸리는 사람들을 위해 도서관의 매력적인 특징으로 미니멀리즘을 정말 좋아합니다.

나는 C ++을 훨씬 더 자주 선호하지 않지만 실제로는 헤더에 C를 사용하더라도 C ++로 구현 하기는하지만 실제로 가장 넓은 이진 호환성 (및 FFI)을 위해 C API를 사용해야합니다. 그러나 때로는 메모리 할당 자 수준이나 매우 낮은 수준의 데이터 구조와 같이 실제로 저수준으로 갈 때 (내장 프로그래밍을하는 사람들 사이에 추가 예제가 있다고 확신 할 때) 때로는 도움이 될 수 있습니다. 작업중 인 유형과 데이터에는 vtable, costructors 및 destructors와 같은 특정 기능이 없다고 가정 할 수 있으므로 셔플, 복사, 무료, 재 할당 할 비트 및 바이트로 처리 할 수 ​​있습니다. 특히 저수준 문제의 경우 C가 제공하는 훨씬 간단한 유형의 시스템으로 작업하는 것이 도움이 될 수 있습니다.

설명

여기에 하나의 흥미로운 의견이 조금 더 깊이 응답하고 싶었습니다 (여기의 의견은 문자 제한에 너무 엄격합니다).

memcpy(&f2, f1, sizeof f2); Foo가 소유 포인터를 가지고 있거나 C를 다루는 도구가 없기 때문에 더 나쁜 경우 C에서 "지옥 화재 통치 혼란"입니다.

그것은 공정한 요점이지만 내가 집중하고있는 모든 것은 주로 C ++의 유형 시스템과 RAII에 중점을 둡니다. 이러한 X-rayish 바이트 - 복사 이유 중 하나 memcpy또는 qsort기능의 종류가 적은 C의 실제 위험의 포즈는 파괴한다는 것입니다 f1f2(그들은 심지어 적지 않은 파괴를 필요로하는 경우) 소멸자가 그림으로 이동하면 위의 반면, 명시 적있다 묵시적이고 자동화됩니다 (종종 개발자에게 큰 가치가 있음). 그것은 vptr과 같은 숨겨진 상태를 언급하지 않았으며 그러한 기능이 바로 불완전 할 것입니다. f1포인터를 소유하고 있다면f2shallow는 일부 임시 컨텍스트에서 복사하고, 소유하는 포인터를 두 번 명시 적으로 해제하지 않으면 아무런 문제가 없습니다. C ++을 사용하면 컴파일러가 자동으로 수행하려는 작업입니다.

자원 관리에 필요한 명시 성이 종종 C ++에서는 간과하기 어렵지만, U ++를 더 이상 사소하게 만들 수 없기 때문에 일반적으로 C에서는 " Foo에 소유 포인터가있는 경우 " 가 더 커 집니다. 작도 / 파괴 단지 그것을 하찮게 작도 / 파괴가 아닌 임의의 멤버 변수를 저장하고 (다시, 일반적으로 매우 도움이 방식으로,하지만 우리는 같이 사용 기능을 유혹하고 있지 않은 경우에 의해 또는 ).memcpyrealloc

내 주요 요점은이 명시 성의 이점을 주장하려고 시도하지 않는 것입니다 (만약 존재한다면 인간 오류의 가능성이 증가함에 따라 거의 항상 무게가 가중됩니다). memcpyand memmoveand qsortand memsetand 같은 기능reallocC ++과 같이 기능과 기능이 풍부한 UDT를 사용하는 언어에서는 사용할 수 없습니다. 그것들이 관계없이 존재하지만, 대다수의 C ++ 개발자들은 전염병과 같은 기능을 피하는 것이 현명하다고 말하지만, C에서는 매우 일상적인 기능입니다. 그들은 타입 시스템이 훨씬 더 기본적이고 아마도 "멍청하다"는 단순한 이유 때문에 C에서 더 적은 문제를 제기한다고 주장한다. X-raying C 유형을 비트 및 바이트로 취급하면 오류가 발생하기 쉽습니다. C ++에서 그렇게하는 것은 언어의 매우 근본적인 기능과 유형 시스템의 권장 사항에 맞서 싸우기 때문에 분명히 잘못되었습니다.

그러나 실제로 C의 언어, 특히 언어 상호 운용성과 관련하여 가장 큰 매력입니다. C #의 FFI와 같은 것을 생성자, 소멸자, 예외, 가상 함수, 함수 / 메소드 오버로드, 연산자 오버로드, 모든 다양한 유형에 이르기까지 C ++의 완전한 유형 시스템 및 언어 기능을 이해하게 만드는 것이 훨씬 더 어려울 것입니다. 상속 등. C에서는 많은 다른 언어가 FFI를 통해 직접 가져 오거나 원하는 형식으로 일부 C API 내보내기 함수를 통해 간접적으로 가져올 수있는 방식으로 API에 비해 다소 표준이 된 비교적 어색한 언어입니다 (예 : Java Native Interface). ). 언어 상호 운용성이 우리의 경우에는 실질적인 요구 사항이기 때문에 C를 사용하는 것 외에는 선택의 여지가없는 경우가 많습니다.

그러나 당신은 알고 있습니다, 나는 실용 주의자입니다 (또는 적어도 나는 노력하고 있습니다). C 가이 가장 악스럽고 오류가 발생하기 쉽고 불쾌한 언어 인 경우 C ++ 애호가 중 일부는 그것을 주장했습니다 (그리고 어떻게 든 C 혐오로 이끌지 않는 것을 제외하고는 C ++ 애호가라고 생각합니다. 반대로, 그것은 그들 자신의 관점과 차이점에서 두 언어를 더 잘 이해하게 만드는 나에게 반대의 영향을 미쳤습니다. C로 작성된 신뢰할 수없는 제품과 라이브러리. 그리고 나는 그것을 찾지 못했습니다. 저는 Linux를 좋아하고 Apache, Lua, zlib를 좋아합니다. OpenGL은 변화하는 하드웨어 요구 사항, Gimp, libpng, Cairo 등에 대한 오랜 유산에 견딜 수 있습니다. 최소한 멋진 언어와 라이브러리를 유능한 손으로 작성하는 것만으로도 언어 문제가 무엇이든 문제가되지 않는 것 같습니다. 이것이 제가 관심있는 전부입니다. 실용적으로 호소하기를 제외하고 언어 전쟁, "이봐, 멋진 것들이 있습니다! 그들이 어떻게 그것을 만들 었는지 배우고 어쩌면 언어의 관용적 특성에 국한되지 않은 멋진 교훈이 있습니다. 사용중인 언어에 관계없이 " :-디


2
memcpy(&f2, f1, sizeof f2);경우도 C에서 "지옥의 일등 혼란"입니다 Foo어떤 소유 포인터가 있거나로, 더 악화입니다 또한 그 처리 할 수있는 도구가 부족하다. C를 쓰는 사람들은 그렇게 많은 일을하지 않습니다
Caleth

@Caleth 포인터를 소유하는 것만으로도 소유 포인터를 명시 적으로 비우는 것이 간단 해 지므로, 예를 들어 한 곳에서만 원래 메모리를 비우는 경우 (예 : 일부 경우에 따라) 디자인). 소멸자가 관여하는 반면, 두 Foo인스턴스는 이제 동적 배열 또는 벡터 또는이 효과에 영향을 미치는 것을 파괴하려고 할 수 있습니다. 필자는 종종 특정 데이터 구조를 작성하여 파괴가 암시 적이 아니라 명시 적이라는 사실에 의지하는 것이 도움이되는 특별한 사례를 발견합니다.
드래곤 에너지

@Caleth Foo소유하는 포인터가 있으면 적절한 복사 / 이동 ctor, dtor, 값 의미론 등을 제공하고 훨씬 풍부하고 안전한 코드를 가질 수 있기 때문에 내 편이 게으름 스럽다 . 그러나 때로는 데이터 구조 또는 할당자를 동일한 비트 및 바이트 수준으로 일반화하려는 경우 C에 도달하고 좁은 사용 사례에서 단순화되는 경향이있는 유형을 가정 할 수 있습니다. 그런 가정에 의해 조금 C에서 만드는 것이 좀 더 자신감을 느낍니다.
Dragon Energy

@Caleth 그러나 내 경우에는 때로는 메모리에서 비트 및 바이트 이상으로 배열하고 액세스하는 것을 보지 못하는 아키텍처의 초석이 있습니다 (일반적으로 이러한 경우에는 POD 이외의 것은 포함되지 않음). 이것들은 내가 여전히 C를 선호하는 몇 가지 특이한 경우입니다. 메모리 할당자를 상상한다면, 정렬 및 풀링에 중점을 둔 비트 및 바이트, 무효 포인터, 이런 종류의 것보다 더 많은 작업이 필요하지 않습니다. 비트와 바이트를 나눠주고, 매우 특별한 경우 C가 C ++보다 장애물이 적다는 것을 알았습니다.
드래곤 에너지

때로는 C에 도달하는 다른 경우는 코드가 추상적이지 않고 프리미티브에 중점을 두어 코드가 실제로 일반화되고 재사용 될 수있는 경우입니다 ( API void filter_image(byte* pixels, int w, int h);예 : API void filter_image(ImageInterface& img);코드를 이미지 인터페이스에 연결하는 것과 같은 간단한 예제 ) 적용 범위 축소). 이러한 경우 C ++에서는 얻을 것이 거의 없기 때문에 때로는 C에서 그러한 함수를 구현하기 때문에 그러한 코드가 향후 변경이 필요할 가능성을 줄입니다.
Dragon Energy
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.