C ++ STL이 왜 템플릿에 크게 의존하고 있습니까? (* 인터페이스 *가 아님) 형식과 관련이없는 유형을

의무적 인 이름 (표준 템플릿 라이브러리)을 제외하고는 …

C ++은 처음에 OOP 개념을 C에 제시하려고했습니다. 즉, 클래스 및 클래스 계층 구조를 기반으로 특정 엔터티가 수행 할 수있는 작업과 수행 할 수없는 작업을 알 수 있습니다. 다중 상속의 문제와 C ++이 인터페이스 개념을 다소 어색한 방식으로 (자바와 비교하여) 지원한다는 사실로 인해 일부 기능 구성은이 방식으로 설명하기가 더 어렵습니다. 향상).

그런 다음 STL과 함께 템플릿이 작동했습니다. STL은 기존 OOP 개념을 사용하여 대신 템플릿을 사용하여 배수구를 플러시했습니다.

템플릿을 사용하여 템플릿의 형식과 관련이없는 유형을 일반화하기 위해 템플릿을 사용하는 경우 (예 : 컨테이너)가 구분되어야합니다. A가 갖는 vector<int>완벽한 의미가 있습니다.

그러나 많은 다른 경우 (반복자와 알고리즘)에서 템플릿 형식은 개념의 실제 세부 사항이 템플릿의 구현에 의해 완전히 정의되는 “개념”(입력 반복자, 순방향 반복자 등)을 따라야합니다. 템플릿과 함께 사용되는 유형의 클래스가 아닌 함수 / 클래스.

예를 들어, 함수에 다음을 알려줄 수 있습니다.

void MyFunc(ForwardIterator<...> *I);

업데이트 : 원래 질문에서 명확하지 않았으므로 ForwardIterator는 모든 ForwardIterator 유형을 허용하도록 템플릿을 작성하는 것이 좋습니다. 반대로 ForwardIterator를 개념으로 사용하고 있습니다.

Forward Iterator는 그 정의를 살펴보고 구현 또는 문서를 살펴볼 필요가있는 경우에만 기대합니다.

template <typename Type> void MyFunc(Type *I);

템플릿 사용을 선호하는 두 가지 주장 : vtable을 사용하는 대신 사용 된 각 유형에 맞게 템플릿을 컴파일하여 컴파일 된 코드를보다 효율적으로 만들 수 있습니다. 또한 템플릿을 기본 유형과 함께 사용할 수 있습니다.

그러나 STL을 템플릿 화하기 위해 클래식 OOP를 포기하는 더 깊은 이유를 찾고 있습니까? (당신이 그 거리를 읽었다 고 가정 : P)



답변

짧은 대답은 “C ++이 발전했기 때문”입니다. 예, 70 년대 후반에 Stroustrup은 OOP 기능을 갖춘 업그레이드 된 C를 만들려고했지만 오래 전입니다. 1998 년에 언어가 표준화 될 때까지는 더 이상 OOP 언어가 아니 었습니다. 그것은 다중 패러다임 언어였습니다. 확실히 OOP 코드를 약간 지원했지만 튜링 완료 템플릿 언어가 중첩되어 컴파일 타임 메타 프로그래밍이 가능했으며 사람들은 일반 프로그래밍을 발견했습니다. 갑자기 OOP는 그다지 중요하지 않은 것처럼 보였습니다. 템플릿과 일반 프로그래밍을 통해 사용할 수있는 기술을 사용하여 더 단순하고 간결 하며 효율적인 코드를 작성할 수있는시기는 아닙니다 .

OOP는 성배가 아닙니다. 그것은 귀여운 아이디어이며, 발명 당시 70 년대에 절차 적 언어에 비해 상당히 개선되었습니다. 그러나 정직하게 모든 것이 정직하지는 않습니다. 대부분의 경우 어색하고 장황하며 재사용 가능한 코드 나 모듈성을 실제로 홍보하지는 않습니다.

이것이 바로 C ++ 커뮤니티가 오늘날 일반 프로그래밍에 훨씬 더 관심을 갖는 이유이며, 결국 모든 사람들 이 함수형 프로그래밍도 상당히 영리하다는 것을 깨닫기 시작합니다. OOP 자체는 그다지 눈에 띄지 않습니다.

가상의 “OOP 인증”STL의 종속성 그래프를 그려보십시오. 서로에 대해 얼마나 많은 수업을 알아야합니까? 많은 의존성 이있을 것 입니다. vector가져 iterator오거나 iostream끌어 들이지 않고 헤더 만 포함 할 수 있습니까? STL은 이것을 쉽게 만듭니다. 벡터는 자신이 정의한 반복자 유형에 대해 알고 있습니다. STL 알고리즘은 아무것도 모른다 . 모두 반복자를 매개 변수로 허용하더라도 반복자 헤더를 포함 할 필요조차 없습니다. 그렇다면 어느 것이 더 모듈 식입니까?

Java가 정의한대로 STL이 OOP의 규칙을 따르지 않을 수 있지만 OOP 의 목표 를 달성하지 못 합니까? 재사용 성, 낮은 커플 링, 모듈화 및 캡슐화를 달성하지 못합니까?

OOP 인증 버전보다 이러한 목표를 더 잘 달성하지 못 합니까?

STL이 언어로 채택 된 이유는 STL을 초래 한 몇 가지 일이 발생했습니다.

먼저 템플릿이 C ++에 추가되었습니다. 제네릭이 .NET에 추가 된 것과 같은 이유로 추가되었습니다. 타입 안전성을 버리지 않고 “T 타입 컨테이너”와 같은 것을 작성할 수있는 것이 좋은 생각이었습니다. 물론 그들이 구현 한 구현은 훨씬 더 복잡하고 강력했습니다.

그런 다음 사람들은 추가 한 템플릿 메커니즘이 예상보다 훨씬 강력하다는 것을 알게되었습니다. 그리고 누군가는보다 일반적인 라이브러리를 작성하기 위해 템플릿을 사용하여 실험을 시작했습니다. 함수형 프로그래밍에서 영감을 얻은 것과 C ++의 모든 새로운 기능을 사용한 것입니다.

그는 그것을 C ++ 언어위원회에 제출했는데, 그는 너무 이상하고 다르게 보였기 때문에 익숙해지기까지 꽤 오랜 시간이 걸렸지 만 궁극적 으로는 그렇지 않은 다른 전통적인 OOP보다 더 잘 작동 한다는 것을 깨달았습니다 . 그래서 그들은 몇 가지를 조정하여 표준 라이브러리에 적용했습니다.

그것은 이데올로기적인 선택이 아니라 “우리가 OOP가되고 싶은지 아닌지”의 정치적 선택이 아니라 매우 실용적인 선택이었습니다. 그들은 도서관을 평가하고 잘 작동하는 것을 보았습니다.

어쨌든 STL을 선호한다고 언급 한 두 가지 이유는 모두 필수적입니다.

C ++ 표준 라이브러리 효율적이어야합니다. 예를 들어, 동등한 수동 롤링 C 코드보다 효율성이 떨어지면 사람들은이 코드를 사용하지 않을 것입니다. 이는 생산성을 낮추고 버그 가능성을 높이며 전반적으로 나쁜 생각입니다.

STL 프리미티브 유형과 함께 작동해야합니다. 프리미티브 유형은 C에있는 모든 것이기 때문에 두 언어의 주요 부분이기 때문입니다. STL이 기본 배열에서 작동하지 않으면 쓸모없습니다 .

귀하의 질문에는 OOP가 “최고”라고 강력하게 가정합니다. 왜 그런지 궁금합니다. 당신은 왜 그들이 “고전 OOP를 폐지”했는지 묻습니다. 나는 그들이 왜 붙어 있어야하는지 궁금합니다. 어떤 장점이 있었습니까?


답변

내가 생각하고 불평하는 것에 대한 가장 직접적인 대답은 이것입니다. C ++이 OOP 언어라는 가정은 잘못된 가정입니다.

C ++는 다중 패러다임 언어입니다. OOP 원칙을 사용하여 프로그래밍 할 수 있고, 절차 적으로 프로그래밍 할 수 있으며, 일반적으로 (템플릿) 프로그래밍 할 수 있으며 C ++ 11 (이전의 C ++ 0x)을 사용하여 일부 기능을 프로그래밍 할 수도 있습니다.

C ++의 설계자들은이 점을 이점으로보고 있으므로, 일반 프로그래밍이 문제를 더 잘 해결하고보다 일반적으로 더 한 단계 뒤 떨어질 때 C ++을 순전히 OOP 언어처럼 작동하도록 제한 합니다.


답변

내 이해는 Stroustrup은 원래 “OOP 스타일”컨테이너 디자인을 선호했으며 실제로 다른 방법으로는 보지 못했다는 것입니다. Alexander Stepanov는 STL을 책임지는 사람이며 그의 목표에는 “객체 지향”을 포함하지 않았습니다 .

이것이 기본 요점입니다. 알고리즘은 대수 구조에 정의되어 있습니다. 규칙적인 공리에 복잡성 요구 사항을 추가하여 구조 개념을 확장해야한다는 것을 깨달으려면 몇 년이 더 걸렸습니다. … 반복자 이론은 반지 또는 Banach 공간 이론이 수학의 중심이기 때문에 컴퓨터 과학의 중심이라고 생각합니다. 알고리즘을 볼 때마다 알고리즘이 정의 된 구조를 찾으려고 노력합니다. 그래서 내가하고 싶었던 것은 알고리즘을 일반적으로 설명하는 것이 었습니다. 그게 내가 좋아하는 일입니다. 한 달 동안 잘 알려진 알고리즘을 사용하여 일반적인 표현을 찾으려고 노력할 수 있습니다. …

적어도 저에게 STL은 프로그래밍이 가능한 유일한 방법을 나타냅니다. 실제로 C ++ 프로그래밍과는 상당히 다르며 여전히 대부분의 교과서에 제시되어 있습니다. 그러나 C ++로 프로그래밍하지 않고 소프트웨어를 처리하는 올바른 방법을 찾으려고했습니다. …

나는 많은 잘못된 시작을했다. 예를 들어, 그 메커니즘이 근본적으로 결함이 있고 사용되어서는 안되는 이유를 이해하기 전에 상속과 가상에 대한 용도를 찾기 위해 수년을 보냈습니다. 나는 아무도 모든 중간 단계를 볼 수 없다는 것을 매우 기쁘게 생각합니다. 대부분은 매우 어리 석었습니다.

(그는 인터뷰와 관련하여 객체 지향 디자인 (일명 객체 지향 디자인이 근본적으로 결함이있어서 사용해서는 안 됨) 인 상속과 가상을 설명합니다.)

Stepanov가 자신의 라이브러리를 Stroustrup에 제출하면 Stroustrup과 다른 사람들은 ISO C ++ 표준 (동일한 인터뷰)으로 가져 오기 위해 철저한 노력을 기울였습니다.

Bjarne Stroustrup의 지원은 매우 중요했습니다. Bjarne은 표준에서 STL을 정말로 원했고 Bjarne이 무언가를 원한다면 그것을 얻습니다. … 그는 내가 다른 사람에게는 절대로하지 않을 STL을 변경하도록 강요했습니다 … 그는 내가 아는 가장 독창적 인 사람입니다. 그는 일을 끝냅니다. 그는 STL이 무엇인지 이해하는 데 시간이 걸렸지 만, 그렇게했을 때 그는 그것을 통과 할 준비가되었습니다. 그는 또한 10여 년 동안 플락과 과대 광고가 끝나지 않았으며 유연성, 효율성, 과부하 및 형식 안전성의 조합을 추구하는 하나 이상의 프로그래밍 방법이 유효하다는 견해를 견지함으로써 STL에 기여했습니다. STL을 가능하게 한 템플릿. 나는 Bjarne이 우리 세대의 저명한 언어 디자이너라고 분명히 말하고 싶습니다.


답변

답은 STL의 저자 인 Stepanov 와의 인터뷰 에서 찾을 수 있습니다 .

예. STL은 객체 지향이 아닙니다. 저는 객체 지향성이 인공 지능만큼이나 허위라고 생각합니다. 나는이 OO 사람들로부터 오는 흥미로운 코드 조각을 아직 보지 못했습니다.


답변

데이터 구조 및 알고리즘 라이브러리에 대한 순수한 OOP 설계가 더 좋은 이유는 무엇입니까?! OOP가 모든 것에 대한 해결책은 아닙니다.

IMHO, STL은 내가 본 것 중 가장 우아한 라이브러리입니다 🙂

당신의 질문에

런타임 다형성이 필요하지 않습니다. STL이 실제로 정적 다형성을 사용하여 라이브러리를 구현하는 것이 유리합니다. 즉, 효율성을 의미합니다. 일반적인 정렬 또는 거리 또는 모든 컨테이너에 적용되는 알고리즘을 작성하십시오! Sort in Java는 n 레벨을 통해 동적으로 실행되는 함수를 호출합니다!

Pure OOP 언어의 불쾌한 가정을 숨기려면 Boxing 및 Unboxing과 같은 어리석은 것이 필요합니다.

STL에서 볼 수있는 유일한 문제는 일반적으로 템플릿은 끔찍한 오류 메시지입니다. C ++ 0X에서 Concepts를 사용하여 해결할 수 있습니다.

STL과 Java의 컬렉션을 비교하는 것은 Taj Mahal을 내 집과 비교하는 것과 같습니다. 🙂


답변

템플릿 형식은 개념의 실제 세부 사항이 형식의 클래스가 아닌 템플릿 함수 / 클래스의 구현에 의해 완전히 정의되는 “개념”(Input Iterator, Forward Iterator 등)을 따라야합니다. OOP를 다소 사용하지 않는 템플릿과 함께 사용됩니다.

템플릿의 개념 사용을 오해하고 있다고 생각합니다. 예를 들어 Forward Iterator는 매우 잘 정의 된 개념입니다. 클래스가 Forward Iterator가되기 위해 유효한 표현식과 계산 복잡도를 포함한 의미를 찾으려면 표준 또는 http://www.sgi.com/tech/stl/ForwardIterator.html참조하십시오. (입력, 출력 및 사소한 반복기에 대한 링크를 따라 가야합니다).

이 문서는 완벽하게 훌륭한 인터페이스이며 “개념의 실제 세부 사항”이 바로 정의되어 있습니다. 그것들은 Forward Iterators의 구현에 의해 정의되지 않으며 Forward Iterators를 사용하는 알고리즘에 의해 정의되지도 않습니다.

STL과 Java 간 인터페이스 처리 방식의 차이점은 세 가지입니다.

1) STL은 객체를 사용하여 유효한 표현식을 정의하는 반면 Java는 객체에서 호출 해야하는 메소드를 정의합니다. 물론 유효한 식은 메서드 (멤버 함수) 호출 일 수 있지만 반드시 그럴 필요는 없습니다.

2) Java 인터페이스는 런타임 객체이지만 STL 개념은 RTTI에서도 런타임에 표시되지 않습니다.

3) STL 개념에 필요한 유효한 표현식을 유효하게 만들지 않으면 유형으로 일부 템플리트를 인스턴스화 할 때 지정되지 않은 컴파일 오류가 발생합니다. Java 인터페이스의 필수 메소드를 구현하지 못하면 특정 컴파일 오류가 발생합니다.

이 세 번째 부분은 일종의 (컴파일 타임) “덕 타이핑”을 좋아하는 경우입니다. 인터페이스는 암시적일 수 있습니다. Java에서 인터페이스는 다소 명시 적입니다. 클래스 “is”Iterable 을 구현 한다고 말하는 경우에만 Iterable입니다. 컴파일러는 메소드의 시그니처가 모두 존재하고 올바른지 확인할 수 있지만 시맨틱은 여전히 ​​암시 적입니다 (즉, 문서화되어 있는지 아닌지, 더 많은 코드 (단위 테스트)만이 구현이 올바른지 여부를 알려줄 수 있음).

C ++에서는 파이썬과 마찬가지로 의미론과 구문이 모두 암시 적이지만 C ++ (및 강력한 타이핑 전처리기를 사용하는 경우 Python)에서는 컴파일러의 도움을받습니다. 프로그래머가 구현 클래스에 의해 Java와 같은 명시 적 인터페이스 선언을 요구하는 경우 표준 접근 방식은 유형 특성을 사용하는 것입니다 (다중 상속으로 인해 너무 자세한 정보를 방지 할 수 있음). Java와 비교하여 부족한 것은 내 유형으로 인스턴스화 할 수있는 단일 템플릿이며 필요한 모든 표현식이 내 유형에 유효한 경우에만 컴파일됩니다. 이것은 내가 사용하기 전에 필요한 모든 비트를 구현했는지 여부를 알려줍니다. 그것은 편리하지만 OOP의 핵심은 아닙니다 (그리고 여전히 의미를 테스트하지는 않습니다.

STL은 귀하의 취향에 따라 충분히 OO 일 수도 있고 아닐 수도 있지만, 인터페이스와 구현을 확실히 분리합니다. 인터페이스를 통해 리플렉션을 수행 할 수있는 Java 기능이 부족하며 인터페이스 요구 사항 위반을 다르게보고합니다.

당신은 함수를 말할 수 있습니다 … 구현을 보거나 문서를 볼 필요가있는 정의를보고 만 순방향 반복자를 기대합니다 …

개인적으로 암시 적 유형은 적절하게 사용될 때 강점이라고 생각합니다. 알고리즘은 템플릿 매개 변수로 수행하는 작업을 말하고 구현자는 이러한 작업이 작동하는지 확인합니다. “인터페이스”가 수행해야하는 작업의 공통 분모입니다. 또한 STL을 사용 std::copy하면 헤더 파일에서 순방향 선언을 찾는 데 사용하지 않을 것 입니다. 프로그래머 함수 서명 만이 아니라 문서를 기반으로 함수가 수행하는 작업을 수행 해야 합니다. C ++, Python 또는 Java에서 마찬가지입니다. 어떤 언어로 입력하면 얻을 수있는 작업에 제한이 있으며 입력을 사용하여 수행하지 않는 작업 (의미 검사)은 오류가됩니다.

즉, STL 알고리즘은 일반적으로 필요한 개념을 명확하게하는 방식으로 템플릿 매개 변수의 이름을 지정합니다. 그러나 이것은 문서의 첫 번째 줄에 유용한 추가 정보를 제공하고 앞으로 선언을 더 유익하게 만들지 않습니다. 매개 변수 유형으로 캡슐화 할 수있는 것보다 알아야 할 것이 많으므로 문서를 읽어야합니다. (예를 들어, 입력 범위와 출력 반복자를 취하는 알고리즘에서, 출력 반복기가 입력 범위의 크기와 그 값에 따라 특정 수의 출력에 대해 충분한 “공간”을 필요로 할 가능성이 있습니다. 입력을 강력하게 입력하십시오. )

명시 적으로 선언 된 인터페이스에 대한 Bjarne은 다음과 같습니다. http://www.artima.com/cppsource/cpp0xP.html

제네릭에서 인수는 제네릭의 정의에 지정된 인터페이스 (인터페이스에 해당하는 C ++)에서 파생 된 클래스 여야합니다. 즉, 모든 일반 인수 유형은 계층 구조에 맞아야합니다. 따라서 설계에 불필요한 제약이 가해지면 개발자 측에 대한 합리적인 예측이 필요합니다. 예를 들어 제네릭을 작성하고 클래스를 정의하면 사용자가 지정한 인터페이스에 대해 알고 클래스에서 클래스를 파생시키지 않으면 클래스를 제네릭의 인수로 사용할 수 없습니다. 딱딱하다.

다른 방법으로 살펴보면, 오리 타이핑을 사용하면 인터페이스가 존재하는지 몰라도 인터페이스를 구현할 수 있습니다. 또는 누군가 클래스에서 구현하도록 인터페이스를 의도적으로 작성하여 문서를 참조하여 아직하지 않은 것을 요청하지 않는지 확인하십시오. 융통성이 있습니다.


답변

“OOP는 메시징, 로컬 보관 및 상태 프로세스의 보호 및 숨기기, 모든 사물의 극단적 인 바인딩 만 의미합니다. 스몰 토크와 LISP에서 수행 될 수 있습니다. 이것이 가능한 다른 시스템도있을 수 있지만 나는 그것들을 모른다. ” -스몰 토크 제작자 Alan Kay.

C ++, Java 및 대부분의 다른 언어는 모두 고전적인 OOP와는 거리가 멀다. 그러나 이데올로기를 주장하는 것은 굉장히 생산적이지 않다. C ++은 어떤 의미에서나 순수하지 않으므로 당시에는 실용적으로 보이는 기능을 구현합니다.