빠른 질문 : 디자인 관점에서 볼 때, 왜 C ++에는 마더 오브 올베이스 클래스가 없는데, 보통 object
다른 언어로는 무엇입니까?
typedef
. 보다 일반적인 클래스 계층 구조에서는 object
또는을 사용할 수 있습니다 iterator
.
빠른 질문 : 디자인 관점에서 볼 때, 왜 C ++에는 마더 오브 올베이스 클래스가 없는데, 보통 object
다른 언어로는 무엇입니까?
typedef
. 보다 일반적인 클래스 계층 구조에서는 object
또는을 사용할 수 있습니다 iterator
.
답변:
최종 판결은 Stroustrup의 FAQ 에서 찾을 수 있습니다. 요컨대 의미 론적 의미를 전달하지 않습니다. 비용이 발생합니다. 템플릿은 컨테이너에 더 유용합니다.
C ++에 유니버설 클래스 Object가없는 이유는 무엇입니까?
우리는 하나가 필요하지 않습니다. 제네릭 프로그래밍은 대부분의 경우 정적으로 형식이 안전한 대안을 제공합니다. 다른 경우는 다중 상속을 사용하여 처리됩니다.
유용한 유니버설 클래스는 없습니다. 진정한 유니버설은 그 자체의 의미를 가지고 있지 않습니다.
"범용"클래스는 유형과 인터페이스에 대한 엉성한 사고를 장려하고 과도한 런타임 검사로 이어집니다.
범용 기본 클래스를 사용하는 것은 비용을 의미합니다. 객체는 다형성이되도록 힙 할당되어야합니다. 이는 메모리 및 액세스 비용을 의미합니다. 힙 개체는 자연스럽게 복사 의미 체계를 지원하지 않습니다. 힙 개체는 리소스 관리를 복잡하게하는 단순 범위 동작을 지원하지 않습니다. 범용 기본 클래스는 dynamic_cast 및 기타 런타임 검사 사용을 권장합니다.
Objects must be heap-allocated to be polymorphic
-이 진술은 일반적으로 옳지 않다고 생각합니다. 스택에 다형성 클래스의 인스턴스를 확실히 만들고 기본 클래스 중 하나에 대한 포인터로 전달하여 다형성 동작을 생성 할 수 있습니다.
Foo
참조 대에 Bar
때 Bar
하지 상속 않는 Foo
, 결정 론적 예외가 발생합니다. C ++에서 포인터 -Foo를 포인터-바로 캐스트하려고 시도하면 로봇을 제 시간에 돌려서 Sarah Connor를 죽일 수 있습니다.
우선 왜베이스 클래스를 원하는지 생각해 봅시다. 몇 가지 다른 이유를 생각할 수 있습니다.
이것이 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 ++에는 기본 클래스가 없습니다. 왜냐하면 템플릿을 통한 매개 변수 다형성을 가지므로 그럴 필요가 없기 때문입니다.
object
System.Object
int
System.Int32
std::shared_ptr
대신 사용해야합니다.
C ++ 변수의 지배적 인 패러다임은 참조에 의한 전달이 아니라 값에 의한 전달입니다. 모든 것이 루트에서 파생되도록 강제 Object
하면 값으로 전달하는 것은 사실 오류가됩니다.
(값으로 Object를 매개 변수로 받아들이 기 때문에 정의에 따라 슬라이스하고 영혼을 제거합니다).
이것은 반갑지 않습니다. C ++를 사용하면 값 또는 참조 의미론을 원하는지 여부를 생각하여 선택할 수 있습니다. 이것은 성능 컴퓨팅에서 중요한 부분입니다.
Object
상대적으로 적을 것입니다.
문제는 C ++에 이러한 유형이 있다는 것입니다! 입니다 void
. :-) void *
기본 유형에 대한 포인터, 가상 테이블이없는 클래스 및 가상 테이블이있는 클래스를 포함하여 모든 포인터를으로 안전하게 캐스트 할 수 있습니다 .
모든 범주의 객체와 호환되어야하므로 void
가상 메서드를 포함 할 수 없습니다. 가상 함수와 RTTI가 없으면 유형에 대한 유용한 정보를 얻을 수 없지만 void
(모든 유형과 일치하므로 모든 유형에 맞는 것만 알 수 있음), 가상 함수와 RTTI는 단순한 유형을 매우 비효율적으로 만들고 C ++가 존재하지 않도록합니다. 직접 메모리 액세스 등의 저수준 프로그래밍에 적합한 언어
그래서 그런 유형이 있습니다. 언어의 저수준 특성으로 인해 매우 최소한의 (사실 빈) 인터페이스를 제공합니다. :-)
void
.
void
컴파일되지 않고이 오류가 발생 합니다. Java에서는 유형의 변수를 가질 수 있으며 Object
작동합니다. 이것이 void
"실제"유형과 의 차이점 입니다. void
모든 것에 대한 기본 유형 이 사실 일 수 있지만 생성자, 메서드 또는 필드를 제공하지 않으므로 존재 여부를 알 수있는 방법이 없습니다. 이 주장은 증명되거나 반증 될 수 없습니다.
void
유형 이라는 것을 인정합니다 (그리고 약간 영리한 사용을? :
발견했습니다 ). 하나는 "완료 할 수없는 불완전한 유형"이고 다른 하나는 void&
유형 이 없습니다 .
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 ++ 언어의 많은 구석과 마찬가지로 대답은 "위원회 구성원이 생각하지 않은 것"일 것입니다.
ReturnType fallback(ArgTypes...)
이 일할 지라도 그것은 나쁜 디자인 일 것입니다. template <class T, auto fallback> class Hook; template <class ReturnType, class ... ArgTypes> class Hook<ReturnType (ArgTypes...), ReturnType(*fallback)(ArgTypes...)> ...
원하는 것을 수행하고 템플릿 매개 변수 Hook
가 일관된 종류
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 ++ 컴파일러를 사용할 수 없습니다).