2013-03-29 146 views
0

我在程序中遇到了設計問題,因爲我需要偶爾訪問所有存儲在基類指針向量中的子類的屬性&。我的代碼看起來是這樣的:訪問C++子類的屬性/功能

class B1; 
class B2; 
class Base { 
    private: 
    int id, a, b; 

    public: 
    virtual int getA() { return a; } 
    virtual int getB() { return b; } 
    virtual B1 *getB1() { return NULL; } //seems like a bad idea 
    virtual B2 *getB2() { return NULL; } //to have these two functions 
    Base(int newId) { id = newId; } 
}; 

class B1 : public Base { 
    private: 
    int x; 

    public: 
    int getX() { return x; } 
    B1 *getB1() { return this; } 
}; 

class B2 : public Base { 
    private: 
    int y; 

    public: 
    int getY() { return y; } 
    B2 *getB2() { return this; } 
}; 

class Thing { 
    private: 
    std::vector<Base*> bases; 

    void addBase(Base *base) { bases.push_back(base); } 
    void doB1Stuff(); 
    void doB2Stuff(); 
    void setAandB(int ID, int newA, int newB); //set a and b of one of the elements in bases vector based upon the id given 
}; 

的問題是,如果我需要訪問X或Y的東西,像下面這樣:

void Thing::doB1Stuff() { 
    for(std::vector<Base*>::iterator it = bases.begin(); it != bases.end(); ++it) { 
    if (it->getB1()) { 
     //do stuff with b1 
    } 
    } 
} 

上面的代碼應該工作,但如果它似乎壞主意,因爲人們很容易忘記檢查,如果指針爲空使用這樣的B1/B2屬性之前:

void Thing::doB2Stuff() { 
    for(std::vector<Base*>::iterator it = bases.begin(); it != bases.end(); ++it) { 
    std::cout << it->getY(); //I believe this will crash the program if a NULL pointer is returned 
    } 
} 

我的問題因此是:什麼是訪問的子類屬性的好辦法嗎?我正在考慮爲Thing中的B1和B2使用兩個單獨的向量,但這似乎並不是一個好主意,因爲我需要能夠輕鬆設置a和b。有什麼想法嗎?

+0

如果您的類在上下文中表現出根本性不同,則不應將它們混合在數組中。也許你想使用模板呢? – Dave

+1

您的確切問題已通過'dynamic_cast'解決。 (或更好的設計) –

回答

0

您可以檢查您正在訪問的項目是否是您正在尋找的正確的子類別類型,但要執行此操作,您需要包含運行時類型信息(rtti)。

然後,如果它是某種類型而不是null,則可以將其轉換爲該類型並調用正確的函數。

你也可以使用dynamic _cast,雖然爲了這個工作你需要再次rtti,它基本上與檢查自己,然後靜態鑄造相同。

1

你有什麼是完美的罰款:只要你不存儲NULL S IN指針bases載體,就沒有必要爲空,檢查值從迭代器返回。不幸的是,一個指針向量是你的多態對象容器的唯一選擇。您可以創建一個共享指針向量來簡化處理刪除操作,但基本想法將保持不變。

+0

+1最後一句中的'subst(「can」,「should」)'= P – WhozCraig

0

你說得對,這不是接近問題的好方法,你可以使用dynamic_cast有一個安全的方式來確定要使用哪個對象,但是這是不好的代碼的氣味給我。

我會做什麼,而不是訪問子屬性是創建一個虛擬函數,返回您想要在基類中的值。

例子:

class Base { 
    private: 
    int id, a, b; 

    public: 
    virtual int getA() { return a; } 
    virtual int getB() { return b; } 
    virtual int getSubValue() = 0; // 
    Base(int newId) { id = newId; } 
}; 

class B1 : public Base { 
    private: 
    int x; 

    public: 
    int getSubValue() { return x; } 
}; 

class B2 : public Base { 
    private: 
    int y; 

    public: 
    int getSubValue() { return y; } 
}; 

然後,你可以調用它 - > getSubValue()來獲得您所請求的子值。

這是我的觀點,有很多方法可以解決這個問題,但這是我建議根據您提供的信息提出的建議。