2013-02-11 162 views
5
class a //my base abstract class 
{ 
public: 
virtual void foo() = 0; 
}; 

class b : public a //my child class with new member object 
{ 
public: 
void foo() 
{} 
int obj; 
}; 

int main() 
{ 
b bee; 
a * ptr = &bee; 
ptr->obj; //ERROR: class a has no member named "obj" 
} 

我的問題是,當我有指向基類(「a」)的指針指向子類(「b」)時,如何訪問「obj」成員「)對象?我知道鑄造應該做到這一點,但我正在尋找更好的解決方案。使用指針指向基類抽象類的子類成員

+0

有些上下文會有所幫助。你爲什麼要那樣做?如果轉換不是選項,則必須在派生類中有一個虛擬函數重寫,該重寫返回一個引用或指向該成員的指針。但是,這通常會破壞封裝。這將我們帶回到爲什麼要通過指向基類的指針訪問派生類成員? – Void 2013-02-11 20:50:59

+0

@虛構你可能是對的,我應該改變設計。 – user1873947 2013-02-11 20:53:01

回答

7

您可以使用dynamic_cast<>運算符將指針轉換爲指向b的指針a。轉換將成功的前提條件對象的運行時類型指向ptrb,並將否則返回一個空指針,所以你必須轉換後檢查結果:

b* p = dynamic_cast<b*>(ptr); 
if (p != nullptr) 
{ 
    // It is safe to dereference p 
    p->foo(); 
} 

如果你能保證由ptr指向的對象的類型是b,但是,在這種情況下(因爲不涉及虛擬繼承),您甚至可以使用static_cast<>,因爲它在編譯時執行,所以開銷較小。

b* p = static_cast<b*>(ptr); 
// You are assuming ptr points to an instance of b. If your assumption is 
// correct, dereferencing p is safe 
p->foo(); 
3

您必須拋棄繼承層次結構。您的情況是爲適合的類型使用dynamic_cast而量身定製的,因爲您可以以類型安全的方式檢查您嘗試投射的對象實際上是否具有預期類型。

+0

我沒有想到dynamic_cast,它應該解決這個問題,因爲它是類型安全的。 – user1873947 2013-02-11 20:48:10

1

在GCC和鏘(在Visual Studio中,我認爲),您也可以使用下面的語法糖

if (Base* x = dynamic_cast<Base*>(x)) { 
    // do something with \c x now that we know its defined  
} 

和C++ 11,使用auto類型推斷,甚至更好

if (auto x = dynamic_cast<Base*>(x)) { 
    // do something with \c x now that we know its defined  
} 

最後,如果我們想限制爲只讀訪問

if (const auto x = dynamic_cast<Base*>(x)) { 
    // read something from \c x now that we know its defined  
} 

請注意,這很好地將x的範圍限制在if子句的內部,如果我們使用ifelse if來執行多個連續的dynamic_cast,這通常會更方便。