3

なぜこれが起こるのですか?

uがc++で抽象クラスを作成する場合例:クラスBがクラスAから継承された後、クラスA(純粋仮想関数を持つ)

そして、クラスAにA() というコンストラクターがある場合、クラスBのオブジェクト を 作成したとすると、コンパイラーは最初に基本クラス、つまりクラスAを初期化し、次にクラスBを初期化します。

まず、オブジェクトがないとクラスのコンストラクターにアクセスできません。次に、抽象クラスのオブジェクトを作成できない場合に、抽象クラスのコンストラクターを初期化する方法を説明します。

4

5 に答える 5

8

クイックアンサー:コンストラクターは特別です。

Aのコンストラクターがまだ実行されている場合、構築されているオブジェクトはまだ実際にはタイプAではありません。まだ構築中です。コンストラクターが終了すると、Aになります。

派生したBについても同じです。Aのコンストラクターが最初に実行されます。これでAになります。次に、Bのコンストラクターが実行を開始します。この間、オブジェクトは実際にはAのままです。Bのコンストラクターが終了したときにのみ、オブジェクトはBになります。

これは、コンストラクターから純粋仮想関数を呼び出そうとすることで確認できます。関数がAで定義されていて、Bのコンストラクターがそれを呼び出す場合、オブジェクトはまだタイプBではないため、Bのオーバーライドを実行する代わりにランタイムエラーが発生します。

純粋仮想関数のため、コンパイラはAを構築するコードを生成することを許可しません。ただし、Bを作成するプロセスの一部としてAを作成するコードが生成されます。これには魔法は含まれていません。Aを作成できないという規則は、物理学ではなく、言語規則によって課せられます。言語は、Bのオブジェクトを構築するという特別な状況下でそのルールを解除します。

于 2008-12-13T09:53:25.470 に答える
4

class A抽象的ですが、class Bそうではありません。を構築するにclass Bは、のすべての純粋仮想メンバー関数を実装する必要がありclass Aます。

class A
{
public:
    A() {}
    virtual ~A() {}
    virtual void foo() = 0; // pure virtual
    int i;
};


class B : public A
{
public:
    B() {}
    virtual ~B() {}
    virtual void foo() {}
    int j;
};

Aクラスのレイアウトは次のようになります。

+ --------- + + --------- +
| vftable | -> | 〜A()| -> A ::〜A()のアドレス
+ --------- + + --------- +
| 私| | foo()| -> NULL、純粋な仮想
+ --------- + + --------- +

Bクラスのレイアウトは次のようになります。

+ --------- + + --------- +
| vftable | -> | 〜B()| -> B ::〜B()のアドレス
+ --------- + + --------- +
| 私| | foo()| -> B :: foo()のアドレス
+ --------- + + --------- +
| j |
+ --------- +
于 2008-12-13T09:52:15.533 に答える
1
struct A {
  A(int x) {..}
  virtual void do() = 0;
};

struct B : public A {
   B() : A(13) {}      // <--- there you see how we give params to A c'tor
   virtual void do() {..}
};
于 2008-12-13T10:17:04.253 に答える
0
 And if class A has constructor called A() suppose i created an
 Object of class B then the compiler initializes the base class
 first i.e.class A and then initialize the class B
 Then.......?

実際には、あなたはそれを間違った方法で持っています:

クラス B のオブジェクトを作成すると、B のコンストラクターが呼び出されます。
B コンストラクターが A コンストラクターを呼び出す方法を指定しない場合、コンパイラーは初期化子リストの最初のアクションとして、A の既定のコンストラクターへの呼び出しを自動的に挿入します。

デフォルトのコンストラクターを使用したくない場合は、初期化子リストの最初の要素として、適切な A コンストラクターへの呼び出しを明示的に配置する必要があります。

Aの建設が完了すると、Bの建設が継続されます。

First thing is we can not access a constructor of any class without an Object
then how it is initialize the constructor of abstract class if we can not create
an object of abstract class .

上記の言葉は、A と B を別のものと考えているかのように言います。クラス B のオブジェクトは、クラス A のオブジェクトでもあります。オブジェクト全体が有効です。オブジェクト全体はクラス B ですが、これには (同じオブジェクトの一部として) クラス A からのすべての情報が含まれています。

于 2008-12-13T17:18:14.163 に答える
0

classAを直接インスタンス化できないからといって、 class をインスタンス化できないわけではありませんAAコンパイラはそれAが抽象的であることを認識し、直接インスタンス化しようとするコードを拒否するため、インスタンス化は許可されていませんA。次のようなコードは禁止されています。

A a;
new A();

クラスを抽象化するのは、純粋な仮想メソッドがあることです。ただし、そのようなクラスのインスタンス化を本質的に妨げるものは何もありません。C++ 標準では、許可されていないと単純に述べています。コンパイラは、抽象クラスをインスタンス化するための命令を完全に生成できます。非抽象クラスの場合と同じように、適切な量のメモリを予約してからコンストラクターを呼び出すだけです。

をインスタンス化するBと、クラスのすべてのメモリが一度に割り当てられます。すべてのバイトがそこにあるので、基本的にそこにはAインスタンスがあり、コンストラクターによって初期化される準備ができています。(ただし、メモリは、コンストラクターの実行が完了するAまで正式Aは型のオブジェクトと見なされないことに注意してください。)Aコンストラクターが実行され、次にBコンストラクターが実行されます。

于 2008-12-13T17:46:29.007 に答える