12/11/2009

Invoke pure virtual function

沒錯 你沒看錯
這篇的標題是呼叫純虛擬函式
一個沒有實作的純虛擬函式是有可能被呼叫起來的
class A {
public:
    virtual void f(void) = 0;
};
class B : public A {
    virtual void f(void) {}
};
在系統開發中 這是一個很常出現的程式片斷
在多型體系中
A* a = new B;
a->f();
因為vtable的存在 程式會為f找尋合適的function pointer並呼叫
這例子中從vtable中會找到class B中的f()
這並沒有甚麼問題
那麼如果vtable中沒有class B的資訊時會怎麼樣 那就會找到class A的f()
就會呼叫純虛擬函式了

這會發生嗎?
會的
class A;
class A {
public:
    virtual ~A() { m_pA->Close(); }
    virtual void Close(void) = 0;
    A* m_pA;
};
class B : public A {
    virtual void Close(void) {}
};
像這樣的程式
一般人會想說把所有的CloseXXX, DeleteXXX, DestoryXXX寫在解構子
解構子被呼叫的順序是從下而上
所以B的解構子先呼叫 把vtable清掉
A的解構子再呼叫 這時vtable中只有class A 所以就呼叫一個純虛擬函式了

當然 Effective C++裡提到 不應該在解構子呼叫虛擬函式 會有類似的問題出現
而在多執行緒中 也可能發生
class B : public A {
    virtual void f(void) {}
    void ThreadProc() {
        while(1)
            f();
    }
};

void main() {
    A* a = new B();

    while(1) {
        if (...)
            a->Create();
        if (exception == true)
            break;
    }
    delete a;
}
我們把class B改為一個thread 它會不斷的呼叫f()
當一個執行緒因為例外發生或其他原因 使物件的解構子被呼叫
呼叫到一半的時候 另一個執行緒呼叫該物件的虛擬函式
剛好解構到vtable只剩下Base class時 就會呼叫純虛擬函式了

1 則留言:

Unknown 提到...

The kid's stomach is delicate to heat range changes. If they capture cool, it is simple to let intestinal tract contract so that appear withdrawal leading to convulsions. Moreover, around the belly button and the whole stomach is weak, which is easier to appear abdominal pain and diarrhoea because of catching cool. http://www.fitwowgold.com
Buy WOW Gold
RS Gold