Yahoo Answers is shutting down on May 4th, 2021 (Eastern Time) and beginning April 20th, 2021 (Eastern Time) the Yahoo Answers website will be in read-only mode. There will be no changes to other Yahoo properties or services, or your Yahoo account. You can find more information about the Yahoo Answers shutdown and how to download your data on this help page.

? asked in 電腦與網際網路程式設計 · 2 decades ago

何謂double dispatching

我們在作剪刀 石頭 布的時候有用到

可是不大了解他的涵義耶

2 Answers

Rating
  • 2 decades ago
    Favorite Answer

    你是要問如何實作 C++ 裡的 double dispatching 吧!

    double dispatching 是一種概念,也可以說是一種小技巧。它主要是要解決以下這種類型的問題:

    一個 superclass Printer,二個 subclass InkjetPrinter 和 PostscriptPrinter。

    另外有一個 superclass Figure,二個 subclass Circle 和 Rectangle

    利用這些 class 的宣告,希望執行下列的動作。

    // 可能傳回 InkjetPrinter 和 PostscriptPrinter 的物件

    Printer *p = getPrinter();

    // 可能傳回 Circle 和 Rectangle 的物件

    Figure *f = getFigure();

    // 希望能呼叫個別 Circle 或 Rectangle 的 method,然後透過不同的

    // Printer subclass 去列出東西來

    f->printOn(p);

    要讓以上這些程式片段達到我們的目的是需要一些技巧的。因為在 C++ 裡,呼叫者的型別 (在本例中是 f) 是動態決定的。所以如果 getFigure() 傳回的是 Circle 這種 class 的 object ,那麼執行 f->PrinterOn(p),就會執行到 Circle 裡定義的 PrinterOn()。所以呼叫者這部份沒有問題。

    但是,C++裡參數型別是在編譯時期(compile time)就決定好的。在編譯時期,編譯器只知道 p 的型別是 Printer。而不知道是 InkjetPrinter 還是 PostscriptPrinter。

    為了達到我們的目的,在寫作上就要像以下這樣

    class InkjetPrinter : public Printer {

    public:

    void printCircle(const Circle *circle) {

    // ... rasterizing logic for inkjet printing of circles here ...

    cout << "Inkjet printer prints a circle." << endl;

    }

    void printRectangle(const Rectangle *rectangle) {

    // ... rasterizing logic for inkjet printing of rectangles here ...

    cout << "Inkjet printer prints a rectangle." << endl;

    }

    };

    class PostscriptPrinter : public Printer {

    public:

    void printCircle(const Circle *circle) {

    // ... postscript preprocessing logic for circles here ...

    cout << "PostScript printer prints a cirlce." << endl;

    }

    void printRectangle(const Rectangle *rectangle) {

    // ... postscript preprocessing logic for rectangles here ...

    cout << "PostScript printer prints a rectangle." << endl;

    }

    };

    class Circle : public Figure {

    public:

    void printOn(Printer* printer) {

    printer->printCircle(this); // <-- 此處為關鍵技巧

    }

    };

    class Rectangle : public Figure {

    public:

    void printOn(Printer* printer) {

    printer->printRectangle(this); // <-- 此處為關鍵技巧

    }

    };

    請留意註解中有寫"此處為關鍵技巧"那兩行。

    既然「呼叫者」的型別是動態決定的。那我們將參數再當成呼叫者去執行它的成員函式,就可以解決參數型別的限制。所以你可以看到上面的例子裡將 printer 當成呼叫者,再去執行它的成員函式。但是它的參數還是要是 Figure 這種型別才行啊,那會不會又遇到前面參數型別不法動態決定的問題。這個函式因為是 Circle 或 Rectangle 的成員函式,所以可以用 this 來代表目前動態的型別為何。

    以上的方法中,f->printOn(p) 就是 first dispatching。而將傳入的參數當 caller ,printer->printRectangle(this) 或 printer->printCircle(this),就是所謂的 second dispatching。因此這種作法就叫 double dispatching

  • Anonymous
    2 decades ago

    多次改變原理

    它不是組合的因為你不能只有單項記錄

    它是每次把為第二份、三份...等類型也記錄下來

    操作的項目是相等的或與組合性(數量實際 操作的總數量)

    Source(s): 學的
Still have questions? Get your answers by asking now.