6

以下の段落は、Stroustup の書籍「The C++ Programming Language」(第 3 版) の 420 ページから抜粋したものです。

仮想メンバー (この例では s) へのポインターは一種のオフセットであるため、メモリ内のオブジェクトの位置には依存しません。したがって、同じオブジェクト レイアウトが両方で使用されている限り、異なるアドレス空間間で仮想メンバーへのポインターを安全に渡すことができます。通常の関数へのポインターと同様に、非仮想メンバー関数へのポインターは、アドレス空間間で交換できません。

私はこの段落の最後の文に異議を唱えています。以下のコード スニペットでは、非仮想メンバ関数へのポインタfoo()およびが、1 つの基本オブジェクトと派生オブジェクトfoo1()間で問題なく交換されます。ab

実行できないのは、基本クラスfoo()またはfoo1()派生クラスの関数のオーバーロードです。この場合、コンパイラは以下に示すようなエラーを出力します。

#include <iostream>

class A
{
    int i;
    public:
    A() : i(1) {}
    void foo() { std::cout << i << '\n'; }
    void foo1() { std::cout << 2 * i << '\n'; }
};

class B: public A
{
    int j;
    public:
    B() : A(), j(2) {}
//  void foo() { std::cout << j << '\n'; }
};

int main()
{
    typedef void (A::* PMF)();
    PMF p = &B::foo;    //   error C2374: 'p' redefinition, multiple initialization
                        //   if foo() is overloaded in B.
    PMF q = &B::foo1;
    B b;
    (b.*p)();
    (b.*q)();

    A a;
    (a.*p)();
    (a.*q)();
}
4

2 に答える 2

1

その文は正しいです。(標準) C++ では、プログラムまたはプロセスは、正確に 1 つのアドレス空間を持ちます。したがって、ulidtko が指摘したように、この文は、異なるプロセスのアドレス空間間で仮想メンバー関数と非仮想メンバー関数へのポインターを交換する可能性について言及しています。

クラスの非仮想メンバー関数は、呼び出し先のオブジェクト ( thisポインター)への暗黙的な引数を持つほとんど標準関数です。そのため、ロード時にプロセスのアドレス空間にアドレスが割り当てられます。アドレス空間で正確にどこに到達するかは、プラットフォームと、そのメンバー関数が動的にリンクされたライブラリの一部であるかどうかによって異なります。ポイントは、2 つのプロセスの場合、必ずしも同じアドレスではないということです。そのため、ポインターを渡して別のプロセスでそのような関数を実行すると、潜在的に「マシンが起動する (TM)」ことになります。

仮想メンバー関数は、「実行時にジャンプして this ポインターを渡すメモリ内のアドレス」のように、非仮想メンバー関数とほとんど同じですが、代わりに仮想関数テーブル (vtable) を介して呼び出されます。直接の。したがって、仮想メンバー関数へのポインターは、オブジェクトの仮想関数テーブルへのインデックスにすぎません。その関数を呼び出すと、「オブジェクト ポインターを取得し、ポインターをインクリメントしてオブジェクトの vtable に到達し、そのテーブルの指定されたインデックスのアドレスにジャンプして、オブジェクト自体のアドレスをthisポインターとして渡す」という行に沿って何かを実行します。 '。

免責事項:私は「自分が話していることを本当に知っている」-ここでの快適ゾーンにやや傾いています. したがって、何かを単純化しすぎたり、さらに悪いことに、虚偽の情報を広めている場合は、回答を細断してください;)。

于 2013-02-28T03:33:10.803 に答える
0

ポインタは常に仮想メモリとして存在するので正しいです。アドレスを確認すると、メモリアドレスへの物理ポインタがないことがわかります

仮想メンバー(この例では s)へのポインターは一種のオフセットであるため、メモリ内のオブジェクトの位置には依存しません。したがって、同じオブジェクト レイアウトが両方で使用されている限り、異なるアドレス空間間で仮想メンバーへのポインターを安全に渡すことができます。通常の関数へのポインターと同様に、非仮想メンバー関数へのポインターは、アドレス空間間で交換できません。

于 2013-03-16T20:01:08.987 に答える