2013-11-25 48 views
0

我有一個類,並且有幾種方法可以遍歷它。例如,您可以迭代查看其中的所有ABC。該課程沒有虛擬功能。通過將父類轉換爲子引用來提供類的迭代「視圖」

我希望這些有一個很好的界面。我想知道下面是否給出了未定義或不明確的行爲,或者是否可以做。

我想使這一類的三個子類:

// can look at this in three ways 
struct myClass { 
    void myFunc(); 
}; 

struct A_view : public myClass { 
    A_iterator begin(); 
}; 

struct B_view : public myClass { 
    B_iterator begin(); 
}; 


struct C_view : public myClass { 
    C_iterator begin(); 
}; 

然後

A_view& get_C_view(const myClass& c) { 
    return *reinterpret_cast<B_view*>(&c); 
} 

B_view& get_B_view(const myClass& c) { 
    return *reinterpret_cast<B_view*>(&c); 
} 

C_view& get_C_view(const myClass& c) { 
    return *static_cast<C_view*>(&c); 
} 

我希望能夠做到這樣使用它

myClass inst; 

for (auto& c : get_C_view(inst)) 
    //stuff 

for (auto& b : get_B_view(inst)) 
    //stuff 

auto& bview = get_b_view(inst); 

std::transform(bview.begin(), bview.end(), bview.begin(), [](auto& x, auto& y) { /* smthing */ }); 

bview.myFunc(); 

或任何與<algorithm>算法。如您所見,您還可以使用視圖上父類中定義的函數。

所以,我將一個實例強制轉換爲從其派生的類型的引用,該類型僅添加函數,而不是數據,但實際上並不是這些類型之一。

可以嗎? 「OK」我的意思是

  1. 這是明確的,未定義的或未指定的行爲?
  2. 如果沒有明確定義,這是否會導致實踐中的問題?
  3. 藥草薩特會皺眉嗎?
+0

爲什麼不只有'A_begin','A_end'等方法?或者,如果您爲每種類型設置單獨的類,請將「A_view」設置爲朋友類,而不是派生類。 –

+0

@TaylorBrandstetter因爲我的實際情況太多了。而且那些不能用於需要'begin' /'end'方法的東西,比如基於範圍的。 – Jay

+0

如果您只是簡單地將'A_view'作爲獨立類而不是派生類(如下面的答案),那麼您應該能夠以完全相同的方式使用它,並且編寫幾乎相同數量的代碼行。如果「c_begin()」的等價物是私有的,你只需要把它變成朋友。 –

回答

3

繼承是不是在這種情況下,出於多種原因,使用正確的工具,第一個是,你可以不投對象的類型,這是沒有,但更普遍比因爲繼承是第二高的耦合在語言中的關係,應該謹慎使用(即在需要時,而不僅僅是因爲)。

可以創建用於保存關於你型薄膜包裝類型和它們的開始/結束的功能映射到在你的組件的相應的觀點:

struct C_view { 
    MyClass &obj; 
    C_view(MyClass& obj) : obj(obj) {} 
    C_iterator begin() { 
    return obj.c_begin(); 
    } 
    C_iterator end() { 
    return obj.c_end(); 
    } 
}; 

然後用戶代碼變爲:

for (auto &c : C_view(inst)) { 
    ... 
} 
+0

但是,然後你必須有一個更加笨拙的方式來訪問被包裝的東西上的函數。所以,在你的回答開始時,這是不確定的還是未說明的或......? – Jay

+1

@Jay:所以你寧願有未定義的行爲,而不是輸入更多?這是一種選擇,但你的同事可能不同意你的方法。 –

+0

你從未說過它是未定義的,那是我的問題。 – Jay