C ++에 기본 클래스가없는 이유는 무엇입니까? 때, 왜 C ++에는

빠른 질문 : 디자인 관점에서 볼 때, 왜 C ++에는 마더 오브 올베이스 클래스가 없는데, 보통 object다른 언어로는 무엇입니까?



답변

최종 판결은 Stroustrup의 FAQ 에서 찾을 수 있습니다. 요컨대 의미 론적 의미를 전달하지 않습니다. 비용이 발생합니다. 템플릿은 컨테이너에 더 유용합니다.

C ++에 유니버설 클래스 Object가없는 이유는 무엇입니까?

  • 우리는 하나가 필요하지 않습니다. 제네릭 프로그래밍은 대부분의 경우 정적으로 형식이 안전한 대안을 제공합니다. 다른 경우는 다중 상속을 사용하여 처리됩니다.

  • 유용한 유니버설 클래스는 없습니다. 진정한 유니버설은 그 자체의 의미를 가지고 있지 않습니다.

  • “범용”클래스는 유형과 인터페이스에 대한 엉성한 사고를 장려하고 과도한 런타임 검사로 이어집니다.

  • 범용 기본 클래스를 사용하는 것은 비용을 의미합니다. 객체는 다형성이되도록 힙 할당되어야합니다. 이는 메모리 및 액세스 비용을 의미합니다. 힙 개체는 자연스럽게 복사 의미 체계를 지원하지 않습니다. 힙 개체는 리소스 관리를 복잡하게하는 단순 범위 동작을 지원하지 않습니다. 범용 기본 클래스는 dynamic_cast 및 기타 런타임 검사 사용을 권장합니다.


답변

우선 왜베이스 클래스를 원하는지 생각해 봅시다. 몇 가지 다른 이유를 생각할 수 있습니다.

  1. 모든 유형의 개체에서 작동하는 일반 작업 또는 컬렉션을 지원합니다.
  2. 모든 개체에 공통적 인 다양한 절차를 포함합니다 (예 : 메모리 관리).
  3. 모든 것이 객체입니다 (프리미티브가 아닙니다!). Objective-C와 같은 일부 언어에는이 기능이 없기 때문에 상황이 매우 복잡해집니다.

이것이 Smalltalk, Ruby 및 Objective-C 브랜드의 언어가 기본 클래스를 갖는 두 가지 좋은 이유입니다 (기술적으로 Objective-C에는 실제로 기본 클래스가 없지만 모든 의도와 목적에 따라 그렇습니다).

# 1의 경우, C ++에 템플릿을 포함하여 모든 개체를 단일 인터페이스로 통합하는 기본 클래스가 필요하지 않습니다. 예를 들면 :

void somethingGeneric(Base);

Derived object;
somethingGeneric(object);

파라 메트릭 다형성을 통해 유형 무결성을 완전히 유지할 수 있다면 불필요합니다!

template <class T>
void somethingGeneric(T);

Derived object;
somethingGeneric(object);

# 2의 경우 Objective-C에서는 메모리 관리 절차가 클래스 구현의 일부이고 기본 클래스에서 상속되는 반면 C ++의 메모리 관리는 상속이 아닌 구성을 사용하여 수행됩니다. 예를 들어 모든 유형의 객체에 대한 참조 계산을 수행하는 스마트 포인터 래퍼를 정의 할 수 있습니다.

template <class T>
struct refcounted
{
  refcounted(T* object) : _object(object), _count(0) {}

  T* operator->() { return _object; }
  operator T*() { return _object; }

  void retain() { ++_count; }

  void release()
  {
    if (--_count == 0) { delete _object; }
  }

  private:
    T* _object;
    int _count;
};

그런 다음 개체 자체에서 메서드를 호출하는 대신 래퍼에서 메서드를 호출합니다. 이것은보다 일반적인 프로그래밍을 허용 할뿐만 아니라 관심사를 분리 할 수도 있습니다 (이상적으로는 객체가 다른 상황에서 메모리를 관리하는 방법보다 수행해야하는 작업에 더 관심을 가져야하기 때문에).

마지막으로, C ++와 같은 기본 객체와 실제 객체를 모두 포함하는 언어에서는 기본 클래스 ( 모든 값에 대한 일관된 인터페이스)를 갖는 이점 이 손실됩니다. 그러면 해당 인터페이스를 준수 할 수없는 특정 값이 있기 때문입니다. 이런 상황에서 프리미티브를 사용하기 위해서는 그것들을 객체로 들어 올려야합니다 (컴파일러가 자동으로하지 않는다면). 이것은 많은 합병증을 만듭니다.

따라서 귀하의 질문에 대한 짧은 대답은 C ++에는 기본 클래스가 없습니다. 왜냐하면 템플릿을 통한 매개 변수 다형성을 가지므로 그럴 필요가 없기 때문입니다.


답변

C ++ 변수의 지배적 인 패러다임은 참조에 의한 전달이 아니라 값에 의한 전달입니다. 모든 것이 루트에서 파생되도록 강제 Object하면 값으로 전달하는 것은 사실 오류가됩니다.

(값으로 Object를 매개 변수로 받아들이 기 때문에 정의에 따라 슬라이스하고 영혼을 제거합니다).

이것은 반갑지 않습니다. C ++를 사용하면 값 또는 참조 의미론을 원하는지 여부를 생각하여 선택할 수 있습니다. 이것은 성능 컴퓨팅에서 중요한 부분입니다.


답변

문제는 C ++에 이러한 유형이 있다는 것입니다! 입니다 void. 🙂 void *기본 유형에 대한 포인터, 가상 테이블이없는 클래스 및 가상 테이블이있는 클래스를 포함하여 모든 포인터를으로 안전하게 캐스트 할 수 있습니다 .

모든 범주의 객체와 호환되어야하므로 void가상 메서드를 포함 할 수 없습니다. 가상 함수와 RTTI가 없으면 유형에 대한 유용한 정보를 얻을 수 없지만 void(모든 유형과 일치하므로 모든 유형에 맞는 것만 알 수 있음), 가상 함수와 RTTI는 단순한 유형을 매우 비효율적으로 만들고 C ++가 존재하지 않도록합니다. 직접 메모리 액세스 등의 저수준 프로그래밍에 적합한 언어

그래서 그런 유형이 있습니다. 언어의 저수준 특성으로 인해 매우 최소한의 (사실 빈) 인터페이스를 제공합니다. 🙂


답변

C ++는 강력한 형식의 언어입니다. 그러나 템플릿 전문화의 맥락에서 범용 객체 유형이 없다는 것은 당혹 스럽습니다.

예를 들어, 패턴

template <class T> class Hook;
template <class ReturnType, class ... ArgTypes>
class Hook<ReturnType (ArgTypes...)>
{
   ...
   ReturnType operator () (ArgTypes... args) { ... }
};

다음과 같이 인스턴스화 될 수 있습니다.

Hook<decltype(some_function)> ...;

이제 특정 함수에 대해 동일한 것을 원한다고 가정 해 봅시다. 처럼

template <auto fallback> class Hook;
template <auto fallback, class ReturnType, class ... ArgTypes>
class Hook<ReturnType fallback(ArgTypes...)>
{
   ...
   ReturnType operator () (ArgTypes... args) { ... }
};

전문화 된 인스턴스화

Hook<some_function> ...

그러나 아아, 클래스 T가 전문화 전에 어떤 유형 (클래스이든 auto fallback아니든)을 나타낼 수 있지만, 어떤 것을 의미 할 수있는 동등한 것은 없습니다 (이 컨텍스트에서 가장 명백한 일반 비 유형 유형으로 해당 구문을 사용하고 있습니다). 전문화 전 비 유형 템플릿 인수.

따라서 일반적으로이 패턴은 형식 템플릿 인수에서 형식이 아닌 템플릿 인수로 전송되지 않습니다.

C ++ 언어의 많은 구석과 마찬가지로 대답은 “위원회 구성원이 생각하지 않은 것”일 것입니다.


답변

C ++는 처음에 “C with classes”라고 불 렸습니다. C #과 같은 다른 현대적인 것과는 달리 C 언어의 발전입니다. 그리고 C ++를 언어로 볼 수는 없지만 언어의 기초로 볼 수 있습니다 (예, Scott Meyers의 저서 Effective C ++를 기억하고 있습니다).

C 자체는 언어, C 프로그래밍 언어 및 전 처리기의 혼합입니다.

C ++는 또 다른 조합을 추가합니다.

  • 클래스 / 객체 접근 방식

  • 템플릿

  • STL

저는 개인적으로 C에서 C ++로 직접 오는 것을 좋아하지 않습니다. 한 가지 예는 열거 형 기능입니다. C #을 통해 개발자가 사용할 수있는 방법이 훨씬 더 좋습니다. 자체 범위에서 열거 형을 제한하고 Count 속성이 있으며 쉽게 반복 할 수 있습니다.

C ++가 C와 역 호환되기를 원했기 때문에 디자이너는 C 언어가 전체적으로 C ++에 들어가도록 허용하는 것이 매우 관대했습니다 (미묘한 차이가 있지만 C 컴파일러를 사용하여 수행 할 수있는 작업은 C ++ 컴파일러를 사용할 수 없습니다).