Пример двойной отправки C ++ - PullRequest
0 голосов
/ 24 января 2019

Я получил этот код в качестве примера использования двойной диспетчеризации, но я не совсем понимаю одну часть кода. создание «абстрактного класса» принтера, почему мне нужно добавить:

virtual void print(PDFDoc *d)=0;
virtual void print(DocDoc *d)=0; 

Насколько я понимаю, во время выполнения p.print(docA); отправит меня на virtual void print(Document *d) myPrinter, затем d->printMe(this) отправит меня на printMe из PDFDoc, а затем вызовет во время выполнения на virtual void print(PDFDoc *d) моего принтера

Так зачем определять

virtual void print(PDFDoc *d)=0;
virtual void print(DocDoc *d)=0; 

нужен для абстрактного класса?

class Document{
public:
      //this is the accept function
      virtual void printMe(Printer *p)=0;
};

    class Printer{
    public:
    virtual void print(Document *d)=0;

     //the visitors
     virtual void print(PDFDoc *d)=0;
     virtual void print(DocDoc *d)=0;
     };

 class PDFDoc : public virtual Document{
 public:
     virtual void printMe(Printer *p){
         std::cout << "PDFDoc accepting a print call" << std::endl;
         p->print(this);
     }
 };

class DocDoc : public virtual Document{
public:
    virtual void printMe(Printer *p){
        std::cout << "DocDoc accepting a print call" << std::endl;
        p->print(this);
    }
};


class MyPrinter : public virtual Printer{
public:
    virtual void print(Document *d){
        std::cout << "dispatching function <print> called" << std::endl;
        d->printMe(this);
    }
    virtual void print(PDFDoc *d){
        std::cout << "printing a PDF doc" << std::endl;
    }
    virtual void print(DocDoc *d){
        std::cout << "printing a Doc doc" << std::endl;
    }
};

int main(){
    MyPrinter p;
    Document *docA = new PDFDoc();
    Document *docB = new DocDoc(); 
    p.print(docA);
    p.print(docB);
    delete docA;
    delete docB;
    return 0;
}

1 Ответ

0 голосов
/ 24 января 2019

Поскольку аргумент printMe() является указателем на абстрактный базовый класс, Printer:

virtual void printMe(Printer *p){

А целью шаблона проектирования "двойная диспетчеризация" является реализация print()передача соответствующего производного Document класса в качестве параметра.

Без перегрузок для производных Document классов единственный метод в базовом классе - это тот, который принимает абстрактный Document базовый класс:

     p->print(this);

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

Последовательность событий:

  1. Виртуальный базовый класс Printer вызывается с параметром, являющимся классом виртуального документа Document.

  2. Реальные реализации принтера используют для фактического классаон получен из Document.

  3. Итак, вызывается чисто виртуальный метод Document printMe() из print(), который принимает указатель Document в качестве параметра.

  4. толькоy параметр, который printMe() принимает, является виртуальным указателем базового класса Printer.

  5. Итак, что бы ни вызывал printMe(), он может вызывать только методы, определенные в виртуальном Printerбазовый класс.

  6. Следовательно, если фактическая реализация принтера должна использовать производный класс Document, эти методы должны быть виртуальными методами в базовом классе Printer.

  7. Эти виртуальные методы не обязательно должны быть print() перегрузками.Они могут быть чем угодно.Некоторым было бы более понятно назвать их как-то иначе, например, printPDF() и printDoc ().Если бы вы переписали их как таковые, возможно, было бы более понятно, что происходит.

...