2012-07-11 135 views
3

可能重複:
Conversion between Derived** to Base**我不能從指針指向派生類的指針和指向基類的指針嗎?

我收到回C++經過幾年大多的Python,和我打起來反對強類型的牆。我認爲我有基本的多態性和基類派生類指針之間的類型轉換(例如Can a pointer of a derived class be type cast to the pointer of its base class?),但是這裏有一個stumper:爲什麼我不能指派一個指向派生類的指針指向p- to-p到它的基類?

欲瞭解更多的上下文(也許提示做這個更少pythonishly),這是我試圖做的簡化版本。我想要一個指向對象的指針列表(從單個類派生)和一個標識它們的字符串(即一個map<string, obj*>)。然後一組組件將通過識別字符串和位置的列表來存儲指向相應對象的指針(即map<string, obj**>)。然後,我應該能夠通過其字符串ID找到適當的對象,然後填寫適當的指針供組件隨後使用。 簡化代碼做,這是

#include <map> 
#include <string> 
using namespace std; 

class base 
{ 
}; 

class derived: public base 
{ 

}; 

typedef map<string, base**> BasePtrDict; 
typedef map<string, base*> BaseDict; 


int main(int argc, char* argv[]) 
{ 
    base b1, b2; 
    derived d; 
    derived* d_ptr; 

    BaseDict base_dict; 
    base_dict["b1"] = &b1; 
    base_dict.insert(make_pair("b2",&b2)); // alternate syntax 
    base_dict["d"]= &d; 

    BasePtrDict ptr_dict; 
    ptr_dict["d"] = &d_ptr; 

    for (auto b = ptr_dict.begin(); b != ptr_dict.end(); b++) 
     *(b->second) = base_dict[b->first]; 

    return 0; 
} 

這在ptr_dict["d"] = &d_ptr;運行到一個編譯錯誤。爲什麼?在C++範例中,我該怎麼做?我真的需要做到醜陋(不安全?)reinterpret_cast<base>()無處不在嗎?

+0

謝謝所有有用的參考和示例。現在肯定有意義,我不得不考慮如何在保持強大的打字ala C++的同時優雅地做到這一點。 – Bismark 2012-07-12 09:00:57

回答

0

直接投derived*base*是好的,但這不是你想要的。您正在嘗試執行derived**base**,這不是隱式轉換。除此之外,我可以問爲什麼?我甚至會繼續問你是否真的需要指針,但雙指針?

3

您正在失去必要的信息,以便能夠將base *投射到derived *

考慮derived繼承自多個基類的情況,因此需要調整指針值。然後derived *pd = static_cast<derived *>(pb)爲指針到基地pb將自動應用指針調整。

但是derived *pd; base **ppb = &pd; *ppb = *pb將無法​​應用指針調整,因此這是不合法的。

你應該做的是:

base *b_ptr; 
... // existing code 
derived *d_ptr = static_cast<derived *>(b_ptr); 
1

爲了做一個孩子到基轉換的類型都需要進行相關。對於derived**base**這意味着derived*base*的孩子,這顯然不是真實的,因爲它們是正交指針類型(碰巧指向相關類)。

你應該能夠用static_cast,而不是reinterpret_cast雖然解決了這個:

ptr_dict["d"] = &static_cast<base*&>(d_ptr); 
+1

不是'dynamic_cast'? – 2012-07-11 14:38:56

0

這將是更簡單的更換

derived* d_ptr; 

base* d_ptr; 

和使用隨時可能需要應用d_ptr的確切類型,但當然是th面向對象原則認爲這種情況應該是非常罕見的。

2

考慮它是否被允許治療derived**base**什麼會被啓用:

class base 
{ 
}; 

class derived: public base 
{ 
public: 
    int boom; 
} 


void light_the_fuse(base** pb) 
{ 
    *pb = new base; 
} 


int main() 
{ 
    derived* pd = NULL; 

    light_the_fuse(&pd); 

    pd->boom = 42; // uh oh, `pd` points to a `class base`... 

    return 0; 
} 
0

這幾乎類似Why do I need a reinterpret_cast to convert Fred ** const to void ** const?

指向兩個不同的對象類型基本上是不兼容的。但是,也有例外

  • Derived*Base* ...派生和基礎是相關的,因此,轉換允許(值映射爲Base*後,指針實際上是指向Base類型的對象
  • T*void* - 允許(見上面的鏈接)

但沒有理由D**應該被允許轉換爲B**,因爲B*D*基本上是不同的類型。

0

您不能也不應該將Derived**指定給Base**,因爲它不安全。如果演員被允許,則允許Derived*指向不是Dervied類型的類型。考慮以下幾點:

class Base {}; 
class Derived: public Base {}; 
class Other: public Base {}; 

... 

Derived derived; 
Derived* derived_p = &derived; // derived_p points to derived. 
Derived** derived_pp = &derived_p; // derived_p points to derived. 
            // derived_pp points to derived_p. 
Base** base_pp = derived_pp;  // derived_p points to derived. 
            // base_pp points to derived_p. 

Other other; 
Other* other_p = &other;   // other_p points to other. 

*bpp = op;       // base_pp points to derived_p. 
            // derived_p points to other. 

如果上面的代碼是有效的,它將使Derived* derived = new Other()

不幸的是,我不完全確定試圖完成什麼,所以我不能提供替代解決方案。