2012-12-05 80 views
0

我正在嘗試一個基本的東西,有兩個類和一個免費函數。首先,我有兩個類:免費函數和繼承

struct BASE{ 
    BASE(int a = 0):a_(a){}; 
    virtual ~BASE(){}; 
    virtual void foo(){std::cout << "BASE " << std::endl;} 
    int a_; 
}; 

struct DERIVED: public BASE{ 
    DERIVED():BASE(){}; 
    void foo(){std::cout << "DERIVED " << std::endl;} 
}; 

然後我填了一個std ::向量(或升壓:: ptr_vector)

std::vector<BASE* > vec;  
vec.push_back(new BASE(2)); 
vec.push_back(new DERIVED); 

如果我把我的函數foo,沒有PB虛擬的東西效果很好, 但如果我創建了兩個免費的功能:

void foo(BASE* a, DERIVED* b){ 
    std::cout << " mix base/derived " << std::endl; 
} 

void foo(BASE* a, BASE* b){ 
    std::cout << " full base " << std::endl; 
} 

,如果我做

foo(vec[0], vec[1]); //failed 

我會得到的消息

full base 

那麼它是符合邏輯的,因爲我有BASE *的載體,但它無論如何存在 去我的免費功能良好的通話?我需要繼承,所以我不能真正地分開這兩個類,因爲我必須填寫這個容器

此外,在最後我的向量將被隨機填充,所以我無法預先知道如何正確轉換。

回答

2

獲得解決方法最簡單(最快)的方法是向唯一標識派生類(使用int,enum值或typeid)引入一個更多虛函數。所以稍後你可以調用它並且知道你在BASE*後面得到了什麼確切的派生類(或者可能是基礎),並且可以執行dynamic_cast。如果你想實現Double Dispatch(或某種)...

但通常情況下,如果您需要dynamic_cast這意味着您設計錯誤(OOP模型的域名)...

+0

如果您使用手動RTTI(枚舉等),你不需要'dynamic_cast','static_cast '足夠了 – 2012-12-05 13:46:57

+0

不完全正確!考慮多重繼承(romb類) – zaufi

+0

嗯,我正在矩陣之間進行線性代數。目前我有一個密集的矩陣類。當你乘以矩陣C = A * B時,你稱之爲blas GEMM求解器。但是如果你的矩陣之一是一個單位矩陣,你應該返回A或B並且什麼也不要。目前,ID矩陣是基於一個矩陣類,它不是最優的,我分配無用的內存,並且不需要調用DGEMM。我的矩陣填滿了矢量,操作是隨機執行的。我試圖在這個例子中簡化最大值。同意我應該避免使用dynamic_cast –

0

正如你事先並不知道你的vec[i]是什麼,所以不是編譯器。函數重載解析是一個編譯時過程,而多態 - 運行時。

因此它調用void foo(BASE* a, BASE* b)版本。

換句話說,除非您使用dynamic_cast來嘗試投射到每個可能的派生類,否則您想要做的事情是不可能的。如果對象類型錯誤,它將返回0

但是,很多人會認爲使用dynamic_cast表示設計不好。而且它也很貴。

+0

是的,演員是邪惡的,像空指針^ _^ –

0

你需要爲動態調度,這樣的事情:

void foo(BASE *a, BASE *b) { 
    if (DERIVED *bb = dynamic_cast<DERIVED*>(b)) { 
    foo(a, bb); 
    } else { 
    std::cout << " full base " << std::endl; 
    } 
} 

如果你不想使用dynamic_cast,你可以虛函數添加到BASE這將返回某種形式的類標識符(例如enum),請在每個派生類中重寫此操作,然後根據此函數的返回值(以及static_cast)分叉該呼叫。

+0

我應該避免動態演員,我會嘗試枚舉 –