Как вызвать функцию производного класса из базового класса? - PullRequest
1 голос
/ 12 января 2020

Я новичок ie в C ++, и я программировал этот код ниже.

Это DOCUMENT.h : работает хорошо, и поэтому я не опубликовал его реализацию (документ. cpp):

#pragma once
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
class Document {
private: 
    int id;
    char *titre;

public:
    Document();
    Document(int id, char *titre);
    ~Document();
    Document(const Document &doc);
    Document operator+( Document doc);
    Document operator=(const Document &doc);
    void setId(int id);
    int getId();

    void setTitre(char *titre);
    char *getTitre();
};

class Livre :public Document {
private:
    float price;

public:
    Livre();
    Livre(int id , char *titre,float price);
    ~Livre();
    Livre( Livre &doc);
    Livre operator+(Livre doc);
    Livre operator=( Livre &doc);

    void setPrice(float price);
    virtual float getPrice();
};

class Article :public Document {
private:
    char *date;

public:
    Article();
    Article(int id, char *titre , char *date);
    ~Article();
    Article(Article &doc);
    Article  operator+( Article &doc);
    Article operator=( Article &doc);
    void setDate(char* date);
    char *getDate();
};

MANAGER.H :

#include "Document.h"

class Manager {
private:
    Document **doc ;

public:
    int count = 0;

    Manager();
    ~Manager();

    int  ajouter(Document *d);
    void afficher();

};

MANAGER. CPP:

#include "stdafx.h"
#include "Manager.h"

Manager::Manager() {}
Manager::~Manager() {}

int  Manager::ajouter(Document *d) {
    if (count == 0) {
        doc = (Document**)malloc( sizeof(Document));
        doc[count] = new Document();

        doc[0] = d;
    }
    else {
        doc = (Document**)realloc(doc, count * sizeof(Document));
        doc[count] = new Document();
        doc[count] = d;
    }
    count++;

    return 0;
}

void Manager::afficher() {
    for (int i = 0; i < count; i++) {
        printf("\nid : %d  \n", doc[i]->getId());
        printf("titre : %s  \n", doc[i]->getTitre());
        printf("Price : %f  \n", doc[i]->getPrice());
    }

}

Моя проблема в функции afficher(). Я хочу позвонить getprice() оттуда, но getprice() не является членом класса Document: он является членом Livre класса (который является потомком Document). Есть ли способ позвонить getprice()?

1 Ответ

0 голосов
/ 12 января 2020

Решение вашей проблемы

В идеале 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.

Последнее замечание. Всякий раз, когда у вас есть одна виртуальная функция в классе, вы должны также сделать виртуальный деструктор.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...