Решение вашей проблемы
В идеале Manager::afficher()
не должно знать детали Document
. Если это необходимо отнести к новой функции Document::afficher()
, и пусть каждый тип документа решает, какая информация должна быть распечатана и что доступно. Это принцип полиморфизма:
void Manager::afficher() {
for (int i = 0; i < count; i++) {
doc[i]->afficher();
}
}
Если вы все же хотите нарушить закон деметры , вы можете сохранить свой подход. Но вы можете использовать только те элементы, которые доступны для всех документов. Если вы точно не знаете, что это Ливре. В этом случае вы можете использовать Dynami c Casting:
void Manager::afficher() {
for (int i = 0; i < count; i++) {
printf("\nid : %d \n", doc[i]->getId());
printf("titre : %s \n", doc[i]->getTitre());
Livre *l = dynamic_cast<Livre*>(doc[i]); // attempt to see it's a Livre
if (l) { // If it's a Livre l is not null
printf("Price : %f \n", doc[i]->getPrice());
}
else printf ("Price : unknown\n");
}
}
Не связано, но в вашем коде много проблем, о которых вы еще не знаете
Прежде всего, C ++ не C, поэтому malloc()
не следует использовать, если вы не уверены в том, что делаете (т.е. если вы знаете правила, когда использовать размещение-новое или нет).
Более того, ваше управление указателями указателей в Manager
приведет вас непосредственно к катастрофе: вы выделите один Document
, вы можете в конечном итоге обработать это как массив одного документа, но с помощью мастера приведения dry, вы делаете это указателем на указатель. Ой!
Вам нужно изменить способ управления своей коллекцией документов:
doc = (Document**)malloc( sizeof(Document)); //!!!!! NOOO
Поскольку вы хотите использовать полиморфизм с различными видами специализированных документов, вы можете сделать свой класс похожим на:
class Manager {
private:
vector<shared_ptr<Document>> doc ; // safer way
public:
Manager();
~Manager();
int ajouter(shared_ptr<Document> d);
void afficher();
};
shared_ptr<>
используются как указатели, но управляют памятью самостоятельно. vector
является автоадаптивным: вам просто нужно push_back()
элемент, и он при необходимости изменит свой размер. После этого вы можете индексировать элементы как в массиве. Кроме того, в счетах для вас с vector::size()
;
int Manager::ajouter(shared_ptr<Document> d) {
doc.push_back(d);
}
int Manager::compter() { // you need to add this in your class definition
return doc.size(); // always up-to date count !
}
Как добавить новые документы в вашу библиотеку?
auto d1 = make_shared<Document>();
...
manager.ajouter(d1);
auto d2 = male_shared<Livre>();
...
manager.ajouter(d2);
Чтобы это работало гладко, вам также следует заменить char*
на string
, чтобы избежать проблем с управлением памятью и получить мощность строк C ++.
Динамическое приведение c, которое я упомянул в своем решении, работает несколько иначе с общими указателями: вы должны использовать dynamic_pointer_cast
вместо dynamic_cast
.
Последнее замечание. Всякий раз, когда у вас есть одна виртуальная функция в классе, вы должны также сделать виртуальный деструктор.