以下の段落は、Stroustup の書籍「The C++ Programming Language」(第 3 版) の 420 ページから抜粋したものです。
仮想メンバー (この例では s) へのポインターは一種のオフセットであるため、メモリ内のオブジェクトの位置には依存しません。したがって、同じオブジェクト レイアウトが両方で使用されている限り、異なるアドレス空間間で仮想メンバーへのポインターを安全に渡すことができます。通常の関数へのポインターと同様に、非仮想メンバー関数へのポインターは、アドレス空間間で交換できません。
私はこの段落の最後の文に異議を唱えています。以下のコード スニペットでは、非仮想メンバ関数へのポインタfoo()
およびが、1 つの基本オブジェクトと派生オブジェクトfoo1()
間で問題なく交換されます。a
b
実行できないのは、基本クラス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)();
}