仮想コンストラクターの必要性はありますか? もしそうなら、誰でもシナリオを投稿できますか?
9 に答える
C++ で仮想デストラクタについて話している場合 (仮想コンストラクタのようなものはありません)、子クラスをポリモーフィックに使用している場合は、常にそれらを使用する必要があります。
class A
{
~A();
}
class B : public A
{
~B();
}
A* pB = new B();
delete pB; // NOTE: WILL NOT CALL B's destructor
class A
{
virtual ~A();
}
class B : public A
{
virtual ~B();
}
A* pB = new B();
delete pB; // NOTE: WILL CALL B's destructor
編集:なぜこれに反対票を投じたのかわかりません(コメントを残していただけると助かります...)が、こちらも読んでください
http://blogs.msdn.com/oldnewthing/archive/2004/05/07/127826.aspx
いつものように: C++ FAQ lite: virtual functionsを調べてください。
「仮想コンストラクタ」だけでなく、デストラクタ・関数についても解説!
もちろん、そもそもC++が必要な場合は...
たとえば、複数の環境用の GUI を作成する場合など、さまざまなシナリオがあります。コントロール (「ウィジェット」) のクラスがあり、実際には各環境に独自のウィジェット セットがあるとします。したがって、これらのウィジェットの作成を環境ごとにサブクラス化することは論理的です。これを行う方法 (役に立たないことが指摘されているように、コンストラクターは実際にはほとんどの言語で仮想化できないため) は、抽象ファクトリを使用することであり、上記の例は実際にこの設計パターンを説明するために使用される標準的な例です。
Delphi は、仮想コンストラクタをサポートする言語の 1 つです。
通常、これらはメタ タイプを作成するクラス ファクトリ タイプのシナリオで使用されます。つまり、タイプを説明するタイプです。次に、そのメタ タイプを使用して、子孫クラスの具体的な例を構築します。
コードは次のようになります....
type
MyMetaTypeRef = class of MyBaseClass;
var
theRef : MyMetaTypeRef;
inst : MyBaseClass;
begin
theRef := GetTheMetaTypeFromAFactory();
inst := theRef.Create(); // Use polymorphic behaviour to create the class
どの言語で?たとえば C++ では、コンストラクターを仮想にすることはできません。
コンストラクターは、定義により仮想にすることはできません。コンストラクター呼び出しの時点ではまだオブジェクトが作成されていないため、多態性は意味がありません。
C++ では、コンストラクターが静的関数であるため、コンストラクターを仮想にする理由はありません。つまり、それらは静的にバインドされているため、呼び出すには、呼び出しているコンストラクター関数を特定する必要があります。不確実性はなく、仮想的なものは何もありません。
これはまた、何があっても、オブジェクトがどのクラスになるかを知る必要があることを意味します。ただし、できることは次のようなものです。
Superclass *object = NULL;
if (condition) {
object = new Subclass1();
}
else {
object = new Subclass2();
}
object.setMeUp(args);
...仮想関数があり、構築後に呼び出します。これは Objective-C の標準的なパターンで、まずクラスの「alloc」メソッドを呼び出してインスタンスを取得してから、用途に合わせた初期化子を呼び出します。
ただし、Abstract Factory パターンについて言及した人は、おそらく C++ と Java の方が正しいでしょう。
C ++では、すべてのコンストラクターは暗黙的に仮想化されます(少し余分に追加されます)。つまり、基本クラスのコンストラクターは、派生クラスのコンストラクターの前に呼び出されます。だから、それは彼らが一種の仮想のようです。仮想メソッドでは、派生クラスが同じシグニチャのメソッドを実装している場合、派生クラスのメソッドのみが呼び出されるためです。
ただし、コンストラクターでは、両方のメソッドが呼び出されます(以下の例を参照)。
これがなぜそうなのかについてのより完全な説明については、ScottMeyersによるEffectiveC ++、Third Editionのアイテム9を参照してください(構築中または破棄中に仮想関数を呼び出さないでください)。アイテムのタイトルは質問に関して誤解を招く可能性がありますが、説明を読めば、それは完全に理にかなっています。
#include <iostream>
#include <vector>
class Animal {
public:
Animal(){
std::cout << "Animal Constructor Invoked." << std::endl;
}
virtual void eat() {
std::cout << "I eat like a generic animal.\n";
}
//always make destructors virtual in base classes
virtual ~Animal() {
}
};
class Wolf : public Animal {
public:
Wolf(){
std::cout << "Wolf Constructor Invoked." << std::endl;
}
void eat() {
std::cout << "I eat like a wolf!" << std::endl;
}
};
int main() {
Wolf wolf;
std::cout << "-------------" << std::endl;
wolf.eat();
}
出力:
Animal Constructor Invoked.
Wolf Constructor Invoked.
-------------
I eat like a wolf!
仮想コンストラクターはC++では意味がありません。これは、C++ではコンストラクターに戻り値がないためです。他のいくつかのプログラミング言語では、これは当てはまりません。これらの言語では、コンストラクターを直接呼び出すことができ、コンストラクターには戻り値があります。これにより、特定のタイプのデザインパターンを実装するのに役立ちます。ただし、C ++では、これは当てはまりません。