2011-11-06 14 views
4

假設我有兩個繼承具有純虛函數的基類的類。這兩個類都實現了它自己的那個函數版本,但不添加額外的成員變量,因此它們具有相同的大小。現在有時候,在程序執行過程中,我想將一個類轉換爲另一個類而不復制其所有數據。所以基本上我想讓它使用其他類的虛擬表。有沒有一種便攜的方式來做到這一點?在運行時動態更改虛擬指針

回答

4

可移植的方法是實現你自己的類系統,它實際上具有可被複制的虛擬指針。

標準C++中沒有這樣的虛擬指針。

+0

能否請您就如何做到這一點的例子嗎? – CODError

3

有沒有一種便攜的方式來做到這一點?

絕對不是。關於如何實現虛擬功能的具體細節並未由規範定義,因此不存在假裝一個虛擬類別是另一種虛擬類別的方式。

4

沒有。就語言而言,不存在虛擬表格之類的東西,更不用說關於它的外觀/包含/存儲位置的規則。

某種形式的作文可能更適合您的任務。

3

正如其他答案所說,實際上改變vtable是絕對不可移植的。

不過,也有一些變通辦法,可以讓你完成類似的語義沒有實際改變類類型:

這種簡單的解決辦法是用描述當前實施的枚舉「滾你自己的」遺產:

class MyClass 
{ 
    public: 
    enum DerivedType { A, B }; 

    private: 
    DerivedType myType; 

    public: 
    void myVirtualFunction() 
    { 
     if (myType == A) 
      myAFunction(); 
     else 
      myBFunction(); 
    } 
} 

您也可以使用函數指針作爲公共成員變量,該變量設置爲指示類類型的函數。然後你可以設置功能指針到另一個類的功能來「改變它的類型」

既然你提到你想避免複製數據,你可以保留你的不同的類,但有引用計數指針給你所有的成員變量,以便您可以快速創建彼此相反類型的新對象。

4

挪威安徒生諮詢公司(現埃森哲)的一位年輕同事曾經向我提出過​​一個嚴重的問題。他們在Visual Basic中開發的應用程序花了很長時間來加載。他懷疑這可能是因爲他們把每個類放在它自己的DLL中?

由於擔心最壞情況,我進一步詢問。是的,他們也有任何崩潰等問題

他懷疑,否則莫名其妙的崩潰可能會連接到他們的巧妙方案改變對象的類型在運行時,通過替換vtable指針?

我建議也許他們不應該做這些事情。他懷疑地看着我,冒險說他們沒有時間再次從零開始做事。事實上,他們已經在擴展它,並且存在各種各樣的問題,比如他們的項目負責人堅持他們在客戶現場工作,而不是參加強制性會議。對我而言,這聽起來像蘑菇管理(讓他們在黑暗中,當一個人頭彈出來,切開它):這些東西經常一起。

無論如何,我給你的建議是:不要。

或許可以改爲實現快速移動操作,從移動數據b

或者,您可能會發現,這些都是不成熟的優化

乾杯&心連心,

+0

我同意100%。好像開發已經夠難了!當一些承包商決定增加一些額外的數據成員到'他們'的子類時會發生什麼?我認爲繼承等的一個原因就是爲了避免這類旅行。 –

0

即使這個問題是舊的,我想彈出一個辦法做到這一點。 (對可移植性不太確定)

從我所瞭解的你有一個類BC繼承自某個類A並且它們之間只存在一個虛函數。 (如果BC是不相關的,以及我在這裏的方法工作。)

class A { 
public: 
    virtual std::string hello() = 0; 
}; 

class B : public A { 
public: 
    virtual std::string hello() { return "B"; } 
}; 

class C : public A { 
public: 
    virtual std::string hello() { return "C"; } 
}; 

然後你想利用BC然後調用hello,並得到"B"


所以,有一種方法來創建boost::any的淡化版本,只要它符合:)

struct parent {}; 

template< typename T > 
struct child : public parent { 
    child(T const& t): item(t){} 
    mutable T item; 
}; 

template< typename T > 
T& as(parent const & p) { return static_cast< child<T> const& >(p).item; } 

會投什麼東西然後一切都混合在一起:

B b; 
parent* p = new child<B>(b); 
std::cout << as<C>(*p).hello() << std::endl; 
// ==== OUTPUT ==== 
// B 

可以看到代碼在行動here


再向前邁進一步,我們可以創建一個從一種類型到另一種轉換無需提供有關他們之間發生的事情一個蚊蚋的追尾功能。

template< typename TO, typename FROM > 
TO& convert(FROM const& from) { 
    parent* p = new child<FROM>(from); 
    return as<TO>(p); 
}; 

這可以運行here

(意識到我錯過了這些示例代碼鏈接的繼承,但看完這個問題後,我認爲這是實際需要的。所以,看到沒有繼承測試去here


一些其他代碼,我開始玩,我認爲可能會幫助一些以及...

#include <iostream> 
#include <string> 

class B { 
public: 
    virtual char hello() {return 'B';} 
}; 

class C { 
public: 
    virtual int hello() {return 65;} 
}; 

struct parent {}; 

template< typename T > 
struct child : public parent { 
    child(T const& t): item(t){} 
    mutable T item; 
}; 

template< typename T > 
T& as(parent const & p) { return static_cast< child<T> const& >(p).item; } 

template< typename TO, typename FROM > 
TO& convert(FROM const& from) { 
    parent* p = new child<FROM>(from); 
    return as<TO>(*p); 
}; 

int main() 
{ 
    B b; 
    std::cout << convert< C, B >(b).hello() << std::endl; 
    C c; 
    std::cout << convert< B, C >(c).hello() << std::endl; 
} 
// ==== OUTPUT ==== 
// 66 
// A 

想出如何使這一切的轉換函數中:

template< typename TO, typename FROM > 
TO& convert(FROM const& from) { 
    struct parent {}; 

    struct child : public parent { 
     child(FROM const& t): item(t){} 
     mutable FROM item; 
    }; 

    struct sibling : public parent { 
     sibling(TO const& t): item(t){} 
     mutable TO item; 
    }; 

    parent* p = new child(from); 
    return static_cast< sibling const& >(*p).item; 
};