2013-10-18 115 views
0

我有一個抽象基類和模板派生類。派生對象可以由派生對象的前一個實例構造,比如說一個整數。到目前爲止,我們有C++:我怎樣才能避免static_cast?

struct base { 
    /* ...pure virtual functions here... */ 

    virtual ~base() = default; 
    /* NO DATA */ 
}; 

template <class D> 
struct derived : base { 
    derived() = default; 

    derived(int x, const derived& previous) { 
    /* to construct I need access to previous.data_ */ 
    } 

    /* ...overriden virtual functions here... */ 

    ~derived() = default; 

    D data_; 
}; 

請注意,派生類的構造函數需要訪問previous派生對象的data_成員。現在我想創建一個函數,它將通過輸入一個整數和前一個實例derived<D>構造類型爲derived<D>的對象,並返回指向base的指針。問題是,既然 用戶將base類指針來工作,該功能應該 是這樣的:

template <class D> 
std::shared_ptr<base> getNext(int x, std::shared_ptr<base> current) { 
    return std::make_shared<derived<D>>(x, *current); /* ERROR */ 
} 

這一點,因爲你可能已經猜到,創建一個編譯錯誤,說是沒有已知的轉換從basederived<D>。我知道我可以使用的一件事是static_cast<derived<D>&>(*current),因爲底層對象的類型始終爲derived<D>,但理想情況下,我希望儘可能避免任何強制轉換。 任何想法如何克服這個問題>?提前致謝!

+0

爲什麼不使用複製構造函數? –

+0

@John Smith:派生的構造函數並不是簡單地複製前一個對象。它意味着使用在前一個對象中找到的數據來構建它自己的數據。 – linuxfever

+0

@HeywoodFloyd:我認爲這不重要。問題由getNext的輸入參數創建,而不是其返回類型。 – linuxfever

回答

0

當你有工作多態類,並發現自己需要轉換爲派生類型,這通常是設計中出現問題的線索。畢竟,如果你仍然需要去派生類,爲什麼要有virtual函數呢?我並不是說沒有例外 - 但我會說他們很少。

在這種情況下,你(想你)需要強制轉換才能克隆該對象。相反,我會在基類上提供一個clone方法(這裏叫做getNext)。作出這樣的virtual,在派生類中重寫它,並調用來代替:

struct base { 
public: 
    virtual std::shared_ptr<base> getNext(int x) = 0; 
}; 

template <typename D> 
struct derived : public base 
{ 
public: 
    std::shared_ptr<base> getNext(int x) 
    { 
    std::shared_ptr <derived> clone = std::make_shared <derived<d>> (x, *this); 
    return std::static_pointer_cast <base> (clone); 
    } 
}; 
+0

非常感謝,我接受了你的回答。 – linuxfever

+0

@linuxfever:祝你好運。 –

0

不管怎樣,您都不想使用static_cast;你會想要使用dynamic_pointer_cast(並檢查結果以確保它可以轉換爲您的派生類型)。

如果接口有您需要填寫您的Data對象的所有信息,你可以創建一個轉換構造函數,可以讓你避免做演員:

template<typename T> 
class MyDerived : public Base 
{ 
public: 
    // other functions 
    MyDerived(std::shared_ptr<Base> p) 
    { 
     // initialize _data 
    } 

private: 
    Data _data; 
}; 
1

你可以在基類,它告訴哪種類型的派生類是使用虛擬訪問函數。然後,您可以安全地使用static cast來投射基類。

class Animal { 
    virtual bool isDog() { return false; } 
    virtual bool isCat() { return false; } 
}; 

class Dog : public Animal { 
    virtual bool isDog() { return true; } 
}; 

class Cat : public Animal { 
    virtual bool isCat() { return true; } 
}; 

我可以再投的基類安全這樣的:

Dog A; 
Cat B; 

Animal *unknown_animal = &A; 

if (unknown_animal->isDog()) { 
    Dog *dog = static_cast<Dog*>(unknown_animal); 
} 
else if (unknown_animal->isCat()) { 
    Cat *cat = static_cast<Cat*>(unknown_animal); 
} 

的存取功能也是有用的,如果你只需要知道派生類型,但不需要訪問它