2013-04-03 22 views
19
#include <iostream> 
#include <stdio.h> 
using namespace std; 

// Base class 
class Shape 
{ 
    public: 
     void setWidth(int w) 
     { 
     width = w; 
     } 
     void setHeight(int h) 
     { 
     height = h; 
     } 
     Shape() 
     { 
    printf("creating shape \n"); 
     } 
     Shape(int h,int w) 
     { 
    height = h; 
     width = w; 
     printf("creatig shape with attributes\n"); 
     } 
    protected: 
     int width; 
     int height; 
}; 

// Derived class 
class Rectangle: public Shape 
{ 
    public: 
     int getArea() 
     { 
     return (width * height); 
     } 
     Rectangle() 
     { 
    printf("creating rectangle \n"); 
     } 
     Rectangle(int h,int w) 
     { 
    printf("creating rectangle with attributes \n"); 
    height = h; 
     width = w; 
     } 
}; 

int main(void) 
{ 
    Rectangle Rect; 

    Rect.setWidth(5); 
    Rect.setHeight(7); 

    Rectangle *square = new Rectangle(5,5); 
    // Print the area of the object. 
    cout << "Total area: " << Rect.getArea() << endl; 

    return 0; 
} 

プログラムの出力は、それが常にcalled.Isデフォルトの基底クラスのコンストラクタですC++呼び出して、基本クラスのコンストラクタ

creating shape 
creating rectangle 
creating shape 
creating rectangle with attributes 
Total area: 35 

以下に示します。そこには理由がありますか?そしてこれが、Pythonのような言語が、C++のような暗黙の呼び出しではなく、基本クラスのコンストラクタの明示的な呼び出しを主張する理由ですか?

+2

継承階層のすべてのコンストラクターが、[ベース] - > [派生]の順に呼び出されます。デストラクタは逆の順序で呼び出されます。 –

+0

私の質問は、 "それは常に呼び出される基本クラスのデフォルトのコンストラクタですか?" – liv2hak

+0

@ liv2hakしかし、私には、Rectangle(int h、int w)コンストラクタが2番目のRectangle initで呼び出されたようです... – Kupto

答えて

47

これは簡単な答えです。「これがC++標準で規定されているためです」。あなたはいつものように、デフォルトと異なるのコンストラクタを指定することができます

注:お電話するかを指定していない場合にのみ、基本クラスのデフォルトコンストラクタが呼び出される

class Shape { 

    Shape() {...} //default constructor 
    Shape(int h, int w) {....} //some custom constructor 


}; 

class Rectangle : public Shape { 
    Rectangle(int h, int w) : Shape(h, w) {...} //you can specify which base class constructor to call 

} 

4

オブジェクトが構築されるとき、それは常に最初の基本クラスのサブオブジェクトを構成するため、基本クラスのコンストラクタが最初に呼び出され、次に派生クラスのコンストラクタが呼び出されます。その理由は、派生クラスオブジェクトには、基本クラスから継承されたサブオブジェクトが含まれているからです。ベースクラスのサブオブジェクトを初期化するには、常にベースクラスのコンストラクタを呼び出す必要があります。通常は、派生クラスのメンバ初期化リストで基本クラスのコンストラクタを呼び出します。基本クラスのコンストラクタを明示的に呼び出さないと、コンパイルによって基本クラスのデフォルトコンストラクタが呼び出され、基本クラスの下位オブジェクトが初期化されます。しかし、デフォルトのコンストラクタでの暗黙の呼び出しは、常に必要ではありません(たとえば、基本クラスが引数なしで呼び出すことのできないコンストラクタを定義している場合など)。

オブジェクトがスコープ外にある場合、オブジェクトは最初に派生クラスのデストラクタを呼び出し、次にベースクラスのデストラクタを呼び出します。

+0

"これはいつもうまくいかないでしょうか? – liv2hak

+1

@ liv2hak基本クラスが引数なしで呼び出すことができるコンストラクタを定義している場合、この場合、コンパイラはデフォルトのコンストラクタを生成しないため、コンパイラは基本クラスのサブオブジェクトを初期化できません。エラーが発生する。それは常に動作しません。 – taocp

11

派生クラスで別のコンストラクタを明示的に呼び出さない限り、デフォルトのクラスコンストラクタが呼び出されます。言語はこれを指定します。

Rectangle(int h,int w): 
    Shape(h,w) 
    {...} 

他の基本クラスのコンストラクタを呼び出します。

0

あなたのサブクラスがスーパークラスからプロパティを継承するとき、それらは魔法のように表示されません。それでもオブジェクトを構築する必要があります。したがって、基本コンストラクタを呼び出します。クラスがスーパークラスのコンストラクタが重要な値に初期化する変数を継承するとします。これを行わなければ、変数が初期化されていないため、コードが失敗する可能性があります。

1

コンパイラでは、コンパイラは常に、オブジェクト階層内の関数が正常に呼び出されるようにします。これらの関数はコンストラクタとデストラクタであり、オブジェクト階層は継承ツリーです。

このルールによれば、継承階層の各オブジェクトのコンストラクタとデストラクタは、実装していなくてもコンパイラがそれを呼び出すことができます。この操作を実行するには、コンパイラは未定義コンストラクタとデストラクタを合成し、デフォルトのコンストラクタとデストラクタとして名前を付けます。次に、コンパイラは基本クラスのデフォルトコンストラクタを呼び出し、派生クラスのコンストラクタを呼び出します。

あなたの場合、基本クラスのコンストラクタを呼び出さず、コンパイラがそれをしなかった場合、あなたの例のRectangleである派生クラスは完了しないため、コンパイラはそれをベースクラスのデフォルトコンストラクタを呼び出して行いますおそらく派生クラスで基本クラスのメンバー関数を使用するため、災害の可能性があります。だから安全のためにコンパイラは常にすべてのコンストラクタ呼び出しが必要です。

0

なぜ基本クラスのデフォルトのコンストラクタが呼び出されますか?常にそうであるとは限りません。派生クラスのコンストラクタから基本クラスの任意のコンストラクタ(シグネチャが異なる)を呼び出すことができます。あなたの場合、デフォルトのコンストラクタはパラメータを持たないので、デフォルトのコンストラクタが呼び出されます。

派生クラスを作成すると、コンストラクターが呼び出される順序は、常に階層内のベース - >派生です。

class A {..} 
class B : A {...} 
class C : B {...} 
C c; 

cが作成されると、Aのコンストラクタが最初に呼び出され、およびBのため、その後のコンストラクタを、派生ときにC.

のコンストラクタは、その順序を保証するために:私たちは持っている場合クラス 'コンストラクタが呼び出されると、コンストラクタが基本クラス'コンストラクタを呼び出してから、派生クラス 'コンストラクタが他の処理を実行できるようになります。このため、プログラマは、派生クラスのコンストラクタの唯一の初期化リストで、対応するパラメータを使用して、基本クラスのコンストラクタを手動で呼び出すことができます。たとえば、次のコードでは、Derivedのデフォルトのコンストラクタは、デフォルトコンストラクタの代わりにBaseのコンストラクタであるBase :: Base(int i)を呼び出します。派生クラスの初期化リストで呼び出され、そのようなコンストラクタがない場合

Derived() : Base(5) 
{  
} 

は、パラメータのないコンストラクタコンストラクタは、その後、プログラムは、基本クラスを想定しています。そのため、パラメータのないコンストラクタ(つまり、デフォルトのコンストラクタ)が呼び出されるのはそのためです。