以下のコードでわかるように、抽象基本クラス "HostWindow" と、そこから派生するクラス "Chrome" があります。すべての機能は Chrome で実装されています。問題は、仮想の場合、Chrome で関数を呼び出せないことです。
class HostWindow : public Noncopyable {
public:
virtual ~HostWindow() { }
// Pure virtual functions:
virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false) = 0;
virtual void scrollbarsModeDidChange() const = 0;
}
class Chrome : public HostWindow {
// HostWindow functions:
virtual void repaint(const IntRect&, bool contentChanged, bool immediate = false, bool repaintContentOnly = false);
virtual void scrollbarsModeDidChange() const;
void focus() const;
}
たとえば、Chrome のインスタンスがあり、いくつかの関数を呼び出すとします。
WebCore::Chrome *chrome = new Chrome();
chrome->repaint(IntRect(), true); // Null pointer error
chrome->focus(); // returns void (works)
仮想関数を呼び出すたびに発生するヌル ポインター エラーは次のとおりです。
プログラムは信号 EXC_BAD_ACCESS を受信しました。メモリにアクセスできませんでした。理由: アドレス: 0x00000008 の KERN_PROTECTION_FAILURE
何が起こっているのか分かりますか?
更新: 多くの人が指摘したように、このコードは実際に実行されます。残念ながら、コードは WebCore (WebKit) の奥深くにあるため、これ以上完全な例を提供することはできません。しかし、私は問題を絞り込みました。Chrome インスタンスを手動で作成すると、仮想関数の呼び出しが機能します。したがって、問題はこの特定のクロム インスタンスにあり、適切にインスタンス化できません。これで、Chrome インスタンスは別のクラスのコンストラクターでインスタンス化されます。さらに調べてみます…
更新 2: 問題のあるインスタンスの vtable を調べると、それが null であることがわかります。GDB から:
p *(void **)chrome
$52 = (void *) 0x0
通常のインスタンスには正しい vtable があります。では、なぜ vtable が nil なのかを解明する必要があります。どうしてそうなったのだろうか? 他のクラスのコンストラクターでインスタンス化されているためでしょうか。
更新 3: 別のクラスのコンストラクター内でのインスタンス化であるという問題について、私は正しいようです。
したがって、インスタンス化前は次のようになります。
Page::Page(ChromeClient* chromeClient, ...)
: m_chrome(new Chrome(this, chromeClient))
m_chrome は無効なインスタンスであり、vtable はありません。インスタンス化を変更したので、変数が初めて必要になったときに発生します (これには、後で使用するために ChromeClient を保存する必要があります)。
Page::Page(ChromeClient* chromeClient, ...)
: m_chrome(0)
, m_chrome_client(chromeClient)
Chrome* Page::chrome() const {
if(!m_chrome) {
m_chrome = new Chrome(this, m_chrome_client);
}
return m_chrome;
}
これで、Page::chrome() インスタンスが適切な vtable を備えた正しいインスタンスになりました。かなり奇妙です!
更新 4: 最後の更新、約束します :)。わかりましたので、正確に特定しました。Page コンストラクターの本体でインスタンス化すると、vtable を使用して正しいインスタンスを取得できます。Page コンストラクターのヘッドでインスタンス化すると、vtable がありません。コンストラクターの頭で実行できる変数設定の種類に制限はありますか? それは別の Stackoverflow の質問だと思います。
とても役に立ってくれてありがとう。