C++ 双重分派示例

C++ double dispatch example

我得到这段代码作为使用双重分派的示例,但我并不真正理解其中的一部分代码。创建 "abstract class" 打印机,为什么我需要添加:

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?

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;
}

因为printMe()的参数是指向抽象基class的指针,Printer:

virtual void printMe(Printer *p){

而 "double-dispatch" 设计模式的目的是实现 print() 传递适当的派生 Document class 作为参数。

没有派生 Document classes 的重载,基 class 中唯一的方法是采用抽象 Document 基 class:

     p->print(this);

在没有额外重载的情况下,这只是调用以虚拟 Document 基础 class 作为参数的相同虚拟方法。

事件的顺序是:

  1. 虚拟基础 class Printer 被调用,参数是虚拟文档 class Document.

  2. 实际打印机实现使用派生自文档的实际 class。

  3. 因此,Document 的纯虚拟 printMe() 方法被调用,来自 print(),它将 Document 指针作为参数。

  4. printMe()接受的唯一参数是虚拟Printer基class指针。

  5. 所以,无论printMe()调用什么,都只能调用virtual Printer base中定义的方法class.

  6. 因此,如果实际的打印机实现需要使用派生的Documentclass,那些方法必须是Printer基[=]中的虚方法75=].

  7. 那些虚拟方法并不一定要 print() 重载。它们可以是任何东西。对某些人来说,将它们命名为不同的名称可能更清楚,例如 printPDF()printDoc()。如果您要重写它们,那么可能会更清楚发生了什么。