0

次の C++ 最終試験の準備として、この問題に取り組んでいます。

// What gets printed?
#include <iostream>
using namespace std;
class A {
  public:
    A(int a = 5) : i(a) { cout << "A" << endl; }
    void foo() { cout << "this.i " << i << endl; }
    virtual void print() const { cout << i << " in A" << endl; }
  protected:
    int i;
};
class B : public A {
  public:
    B() : A(1) { cout << "B default" << endl; }
    void foo() { cout << i << " in B" << endl; }
    void print() const { cout << i << " in B" << endl; }
};
int main() {
  A *pa;
  B b;
  pa=&b;
  pa->foo();
  pa->print();
  return 0;
}

そしてその出力は次のとおりです。

A
B default
this.i 1
1 in B

印刷されるのはスーパークラスからのコンストラクターのA呼び出しによるものであり、ポインターを指すようにすると、の基本クラスメソッドにアクセスすることを理解していますが、代わりに値を印刷するにはどうすればよいですか?BA*pa&bfooB::print()A::print()

4

4 に答える 4

1
virtual void print()

function の前にあるvirtualという言葉は、ポリモーフィズムに魔法をかけてくれます。派生クラスが、基本クラスで virtual と宣言された関数を実装すると、派生クラスのインスタンスの基本クラス関数の代わりに呼び出されます。

派生クラス B のインスタンスを作成すると、B には print() というメンバー関数があり、代わりに呼び出されます。

于 2013-06-09T20:17:16.040 に答える
0

の違い

pa->foo();

pa->print();

単純な事実によって引き起こされます。

ポインターの型は、特定のアドレスで見つかったメモリをどのように解釈するか、またその解釈がどのくらいのメモリにまたがるべきかをコンパイラに指示します。

、本からC++ オブジェクト モデルの内部

つまり、コンパイラがこのコード行を変換しようとすると、 paがクラス A のポインタであり、fooがクラス A の関数であるpa->foo()ことしかわかりません。実際には、 paがクラス B のメモリ ブロックを指していることはわかっていますが、その事実を知りませんし、知ることもできません。彼はpaをクラス A のポインターとして解決し、A の関数fooの定義を見つけるだけです。しかし、 の魔法は、C++の仮想関数の実装によるものです。通常の関数の場合、コンパイラはその名前を解析し、その関数の開始アドレスにジャンプします。ただし、仮想関数の場合、コンパイラはまず、ポインターが指すメモリーからvptrポインターを見つけます。pa->print()paおよびvptrを解決して、 print関数の正しい定義を見つけます。今回はコンパイラがメモリからvptrを読み取り、メモリは実際にはクラス B に属しているため、B の print が呼び出されます。
これを説明する別の例を次に示します。

// What gets printed?
#include <iostream>
using namespace std;
class A {
  public:
int b;
    A(int a = 5) : i(a) { 
      b = 42;
  cout << "A" << endl; 
    }
    void foo() { cout << "this.i " << i << endl; }
    virtual void print() const { cout << i << " in A" << endl; }
   protected:
     int i;
 };
 class B : public A {
   public:
 int b;
     B() : A(1) { 
       b = 43;
   cout << "B default" << endl; }
     void foo() { cout << i << " in B" << endl; }
     void print() const { cout << i << " in B" << endl; }
 };
 int main() {
   A *pa;
   B b;
   pa=&b;
   cout << pa->b << endl;
   cout << b.A::b << ", " << b.b << endl;
   //pa->foo();
   //pa->print();
   return 0;
 }

出力は

A
B default
42
42, 43

ちなみに、仮想関数メカニズムはポインターまたは参照でのみ機能します。オブジェクト A の場合、 A の印刷関数であるクラス A のメモリ ブロック内のvptrA.print()に解決する必要があるためです。

于 2013-06-10T08:38:45.207 に答える