簡単な質問:設計の観点から、C ++には基本クラスの母がないのはobject
なぜですか?通常、他の言語には何がありますか?
typedef
。より一般的なクラス階層では、object
またはを使用できますiterator
。
簡単な質問:設計の観点から、C ++には基本クラスの母がないのはobject
なぜですか?通常、他の言語には何がありますか?
typedef
。より一般的なクラス階層では、object
またはを使用できますiterator
。
回答:
決定的な判決はStroustrupのFAQにあります。要するに、それは意味的な意味を伝えません。費用がかかります。テンプレートはコンテナに役立ちます。
C ++にユニバーサルクラスのオブジェクトがないのはなぜですか?
必要はありません。ジェネリックプログラミングは、ほとんどの場合、静的に型安全な代替手段を提供します。その他の場合は、多重継承を使用して処理されます。
有用なユニバーサルクラスはありません。真にユニバーサルなクラスには、独自のセマンティクスはありません。
「ユニバーサル」クラスは、タイプとインターフェースについてのずさんな考えを促し、過剰な実行時チェックにつながります。
ユニバーサル基本クラスを使用すると、コストが発生します。多態性を持たせるには、オブジェクトをヒープに割り当てる必要があります。これは、メモリとアクセスのコストを意味します。ヒープオブジェクトは、コピーセマンティクスを自然にサポートしていません。ヒープオブジェクトは、単純なスコープ動作(リソース管理を複雑にする)をサポートしていません。ユニバーサル基本クラスは、dynamic_castおよびその他のランタイムチェックの使用を推奨します。
Objects must be heap-allocated to be polymorphic
-この記述は一般的に正しいとは思いません。スタック上にポリモーフィッククラスのインスタンスを作成し、それをその基本クラスの1つへのポインターとして渡すことで、ポリモーフィックな動作を実現できます。
Foo
をreference-to- Bar
whenにキャストしようとBar
するとFoo
、継承されない場合、決定論的に例外がスローされます。C ++では、FooへのポインターをBarへのポインターにキャストしようとすると、ロボットが時間内に戻ってサラ・コナーを殺す可能性があります。
まず、そもそもなぜ基本クラスが必要なのかを考えてみましょう。私はいくつかの異なる理由を考えることができます:
これらは、Smalltalk、Ruby、Objective-Cブランドの言語に基本クラスがある2つの理由です(技術的には、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
、値で渡すと事実上エラーになります。
(パラメーターとして値によってオブジェクトを受け入れるため、定義上、オブジェクトをスライスしてその魂を取り除きます)。
これは歓迎されません。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 ++は当初「Cwithclasses」と呼ばれていました。これは、C#のような他のより現代的なものとは異なり、C言語の進歩です。また、C ++を言語としてではなく、言語の基盤として見ることができます(はい、ScottMeyersの著書EffectiveC ++を覚えています)。
C自体は、Cプログラミング言語とそのプリプロセッサの混合言語です。
C ++は別のミックスを追加します。
クラス/オブジェクトアプローチ
テンプレート
STL
私は個人的に、CからC ++に直接来るものが好きではありません。一例は列挙型機能です。C#を使用して開発者が使用できるようにする方法は、はるかに優れています。列挙型を独自のスコープに制限し、Countプロパティを持ち、簡単に反復できます。
C ++はCとの下位互換性を望んでいたため、設計者はC言語全体をC ++に入力できるようにすることを非常に寛容でした(微妙な違いはいくつかありますが、Cコンパイラを使用して実行できることは覚えていません。 C ++コンパイラを使用できませんでした)。