我正在嘗試設置一個簡單的例子來解決教科書練習。代碼在IDEone,並在下面重複。C++多態指針不能調用成員函數
該代碼是試圖存儲一系列動物列表的簡化案例,並且能夠從我的封裝隊列中保存的這些動物特定列表之一返回任何通用動物。
我可以添加動物很好,當試圖檢索一隻狗時,我似乎得到一個指向狗的指針,因爲我可以打印它的name
。但是,如果我嘗試調用其成員函數speak()
,代碼崩潰,我無法弄清楚原因。
class Animal {
public:
virtual void speak() = 0;
string name;
};
class Dog: public Animal {
public:
Dog(string n) { this->name=n; }
void speak() { cout<<name<<" says WOOF!"<<endl; }
};
class AnimalQueue {
list<Dog> dogs;
list<Cat> cats; // etc.
public:
void enqueue(Animal* a) {
Dog * d = dynamic_cast<Dog*>(a);
if (d!=nullptr) dogs.push_back(*d);
else // check for other animals, etc.
}
Dog* dequeueDog() {
Dog * d = &(dogs.front());
dogs.pop_front();
return d;
}
Animal dequeueAny() {
// Should return a random animal from any list
}
};
int main() {
// Set up
AnimalQueue q;
Dog * d;
d = new Dog("Rex");
q.enqueue(d);
// Retrieve Rex
d = q.dequeueDog();
cout<<d->name<<endl; // Prints "Rex"
d->speak(); // Crashes?!
return 0;
}
編輯:對不起,削減我的代碼,我消除了問題,這是我應該能夠任何子類的Animal
添加到我的列表的精髓,並有一個名爲特殊功能dequeueAny()
應該能夠從任何列表中隨機返回Animal
。該代碼已經被編輯成包括這個(以及我之前省略的nullptr
檢查時enqueue
ING。
什麼是處理這個最好的方法是什麼?難道是在參考傳遞給現有的Animal
對象?將這項工作?即可以,我有:
void dequeueAny(Animal * a) {
// for example, let's return a Dog
Dog d = dogs.front();
dogs.pop_front();
*a = d;
}
誠然,像dequeueDog()
也許應該返回Dog
按值
爲什麼沒有動物有一個構造函數的名字這狗電話?如果'enqueue'只能合理地處理狗,爲什麼不用參數'Dog *'?你的代碼也會泄漏內存。 – 2015-03-18 20:53:46
@NeilKirk:在這種情況下,應該將它重命名爲enqueueDog(),以匹配'dequeueDog()'。 – 2015-03-18 20:59:51
如果不是'Dog'的'Animal'傳遞給'enqueue()','dynamic_cast'將返回一個NULL指針,這個指針將被存儲在列表中,但是你不會檢查那個地方。 'dequeueDog()'在彈出之前也不檢查列表是否爲空。 – 2015-03-18 21:00:23