C ++双调度示例

时间:2019-01-24 01:45:19

标签: c++ visitor-pattern double-dispatch

我获得了此代码作为使用双重调度的示例,但是我并不真正理解代码的一部分。创建“抽象类”打印机,为什么需要添加:

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

据我了解,在运行时p.print(docA);会将我发送到myPrinter的virtual void print(Document *d),然后d->printMe(this)会将我发送到PDFDoc的printMe,然后它将在运行时调用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 :(得分:2)

因为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指针作为参数。

    < / li>
  4. printMe()唯一的参数是虚拟的Printer基类指针。

  5. 因此,无论printMe()调用什么,它都只能调用虚拟Printer基类中定义的方法。

  6. 因此,如果实际的打印机实现需要使用派生的Document类,则这些方法必须是Printer基类中的虚拟方法。

  7. 这些虚拟方法实际上不必是print()重载。他们可以是任何东西。对于某些人来说,更清楚地命名它们是不同的,例如printPDF()printDoc()。如果您这样重写它们,可能会更清楚发生了什么。