2013-03-23 114 views
1

我有一個接口,我們稱其爲Creature,他具有虛擬函數,使其成爲抽象類。將C++接口實例化爲子類

我有這個接口的子類,如DogCatPig

由於無法將變量thing聲明爲抽象類型Creature,編譯器似乎不喜歡以下行。

Creature thing = Dog(); 

我知道我不能實例化接口等,但是這僅僅是一個Dog被聲明爲Creature

我需要有對所有的孩子一個申報工作的一些方法(即能夠把Dog()Cat(),或Pig()其中Dog()是線以上)。

這可以在c + +中完成,或者我濫用繼承和接口完全?

回答

8

對象類型本身在C++中不是多態的。您給出的行聲明瞭一個Creature對象,然後嘗試用Dog對象初始化它。如果Creature不是抽象的,這會導致分片 - thing不會是Dog,它只會是Creature。由於它是抽象的,因此無論如何你都不能有一個對象Creature

您需要爲多態行爲使用指針或引用。考慮到例如:

Creature* thing = new Dog(); 

現在可以提領thing並把它作爲一個Creature,即使它的動態類型Dog。但是,通常不推薦使用像這樣的原始指針,因爲您必須在某個時刻手動確保對象爲deleted。所有權可能會變得混亂。最好的辦法是把它放在一個智能指針,如:

std::unique_ptr<Creature> thing(new Dog()); // or std::make_unique when we have it 

在這裏,我已經證明std::unique_ptr,但智能指針的選擇將取決於所有權語義該對象。一個常見的選擇是std::shared_ptr

若要引用表現多態:

Dog dog; 
Creature& thing = dog; 
// Can now use dog as a Creature 
+0

有趣!我對最後提到的引用有點好奇。如果'Creature'有一個名爲'talk()'和'Dog'的虛擬方法覆蓋它,會調用'thing'的樹皮調用'Creature's或'Dog's? – 2013-03-23 20:57:28

+0

@CoreyMaddieBesmer它會調用'Dog',因爲當通過指針或引用調用虛擬成員函數時,會查找對象的* dynamic *類型。 「東西」的動態類型是「狗」。 – 2013-03-23 21:01:07

1

在C++中,你必須認識到不同的價值和參考語義之間,其中,在interpretet的語言,你往往只是處理引用語義(除了一些奇怪的具有價值語義但除點之外的普通舊數據對象的情況)。

在C++中,所有對象都是值,例如一個對象永遠不可能是null,這意味着聲明指定了存儲需求。 考慮對狗以下

struct creature { 
}; 

struct dog : public creature { 
    float cuteness; 
}; 

的存儲需求比生物的不同,即使您允許的轉換,這將導致切片。 例如,將fido樹皮或保持沉默? 的#include

class creature { 
public: 
    virtual void speak() { 
     std::cout << "..." << std::endl; 
    } 
}; 

class dog : public creature { 
public: 
    virtual void speak() { 
     std::cout << "woof!" << std::endl; 
    } 
}; 

int main(int argc, const char *argv[]) { 
    creature fido; 
    fido = dog(); 

    fido.speak(); 
    return 0; 
} 

但是如果你只需有一個指針或參考對象是另一回事。 通過指針。

creature* fido = new dog(); 
fido->speak(); 
delete fido; 

作爲參考。

dog fido; 
creature& c = fido; 

c.speak(); 

超出此問題的範圍,但可以選擇一個智能指針。

std::unique_ptr<creature> fido(new dog);