2015-07-10 46 views
1

我觀看了一個視頻,可以在 https://www.youtube.com/watch?v=4F72VULWFvc找到,我真的很喜歡這個案例的一些概念。但我用鏈表的工作,需要選擇性的方法執行,例如:繼承,選擇性執行方法

#include <stdio.h> 
class A { 
public: 
    A() : next(0) { 
     if (head == 0) { 
      head = this; 
     } else { 
      A* step = head; 
      while (step->next != 0) { 
       step = step->next; 
      } 
      step->next = this; 
     } 
    } 
    virtual ~A() { 
     if (head == this) { 
      head = 0; 
     } else { 
      A* step = head; 
      while (step->next != this) { 
       step = step->next; 
      } 
      step->next = next; 
     } 
    } 
    virtual void foo() { 
     // Do nothing... 
    } 
    static A* head; 
    A* next; 
}; 

class B : public A { 
public: 
    B() {} 
    virtual ~B() {} 
    virtual void foo() { 
     printf("function foo\n"); 
    } 
}; 

A* A::head = 0; 

int main() { 
    A a_cls; 
    B b_cls; 

    A* step = A::head; 

    while (step != 0) { 
     step->foo(); 
     step = step->next; 
    } 

    return 0; 
} 

實例的所有對象後,B類的對象的方法foo()需要執行。爲了實現這一點,虛擬方法foo()被添加到類A,具有空主體virtual void foo() {},並且在類B中,代碼被添加到方法foo()正文。

它的工作原理,但我不喜歡它,在主函數中,它看起來像你在每個節點上做的事情,但你不是,它幾乎感覺像一個NULL指針。有沒有另一個創造性的解決方案呢?

注意:我正在使用C++ 03。

回答

1

退房dynamic_cast,以此來檢查特定的派生類型和來電fooB類(或B派生類)的對象:

int main() { 
    A a_cls; 
    B b_cls; 

    A* step = A::head; 
    B* step_b = 0; 

    while (step != 0) { 
     step_b = dynamic_cast<B *>(step); 
     if (step_b != 0) { 
      step_b->foo(); 
     } 
     step = step->next; 
    } 

    return 0; 
} 

這樣一來,就沒有必要定義在A上爲空的foo方法。試試ideone

+0

致OP:請理解這是脆弱的代碼。只要將'C'類型引入'A'的子類型,就需要另一個'if'子句。這正是使用多態的原因。 –

+0

我想我需要了解更多OP的意圖,以瞭解我是否同意這一說法。如果C源自B,則不需要額外的if語句。如果我們想爲C調用一個不同於B的方法,那麼不管我們需要一個if語句。 –

0

它的工作原理,但我不喜歡它,在main功能,它看起來像你在每個節點上做一些事情,但你不是,它幾乎感覺就像一個NULL指針。有沒有另一個創造性的解決方案呢?

確保您的基類是純粹的抽象類。這樣,每次致電step->foo();很可能會有所作爲。

下面是一個異構列表的裸骨的例子。 List::Node是一個抽象基類。 List::Node::print()是一個僅在具體類中實現的虛擬成員函數。 List能夠使用通用算法步進通過Node,而不需要明確知道它包含的Node的種類。

#include <iostream> 
#include <string> 

class List 
{ 
    public: 

     class Node 
     { 
     public: 
      Node() : next(nullptr) {} 
      virtual ~Node() {} 
      virtual void print() = 0; 
      Node* next; 
     }; 

     List() : head(nullptr), tail(nullptr) {} 

     ~List() 
     { 
     Node* node = head; 
     Node* next = nullptr; 
     for (; node != nullptr; node = next) 
     { 
      next = node->next; 
      delete node; 
     } 
     } 

     void addNode(Node* node) 
     { 
     if (head == 0) 
     { 
      head = tail = node; 
      return; 
     } 

     if (head == tail) 
     { 
      head->next = node; 
     } 

     tail->next = node; 
     tail = node; 
     } 

     void print() 
     { 
     Node* node = head; 
     for (; node != nullptr; node = node->next) 
     { 
      node->print(); 
      std::cout << std::endl; 
     } 
     } 

     Node* head; 
     Node* tail; 
}; 

class NodeA : public List::Node 
{ 
    public: 
     NodeA(int d) : data(d) {} 
     virtual ~NodeA() {} 
     virtual void print() 
     { 
     std::cout << "In NodeA::print(), Data: " << data; 
     } 
    private: 
     int data; 
}; 


class NodeB : public List::Node 
{ 
    public: 
     NodeB(double d) : data(d) {} 
     virtual ~NodeB() {} 
     virtual void print() 
     { 
     std::cout << "In NodeB::print(), Data: " << data; 
     } 
    private: 
     double data; 
}; 


class NodeC : public List::Node 
{ 
    public: 
     NodeC(std::string const& d) : data(d) {} 
     virtual ~NodeC() {} 
     virtual void print() 
     { 
     std::cout << "In NodeC::print(), Data: " << data; 
     } 
    private: 
     std::string data; 
}; 

int main() 
{ 
    List list; 

    list.addNode(new NodeA(10)); 
    list.addNode(new NodeB(23.45)); 
    list.addNode(new NodeC("abcd")); 

    list.print(); 

    return 0; 
} 
+0

咦?這有什麼用?你仍然需要在每個類中定義每個虛擬函數。除非我錯過了一些東西。 – user1135541

+0

@ user1135541,不正確。你需要爲每個具體的類定義它們。如果你將你的類分成List和ListNode,並使ListNode成爲一個純虛擬類,那麼它會更有意義。 –

+0

我喜歡這個主意,但我認爲答案應該多一些,以回答OP的評論。它與意圖有關:A類的真正目的是什麼?僅僅是建立一個其他對象的列表?如果是這樣,它可能應該是抽象的。 –

0

它的工作原理,但我不喜歡它,在主函數,它看起來像你 在每個節點做一些事情,但你不是

其實你正在做在每個節點處有。你所做的是決定什麼都不做。決定通常不是免費的,你還沒有告訴我們足夠的應用程序來證明它可以通過決定可以有效地自由(在編譯時產生)的方式進行重組。

如果不做任何事的決定不是免費的,那麼實施該決策作爲虛擬職能的調用的成本幾乎與決策可能相同。

+0

該類的用戶必須知道該類的內容,才能知道正在發生什麼,所以邏輯分散了,該函數只是一個「填充」函數。所以這是我不喜歡的可讀性。 – user1135541

0

雖然奧斯汀的解決方案非常好,但另一種方法(我通常更喜歡)在這種情況下是使用接口類和上傳。

class FooFighter { public: virtual void foo() = 0; }; 

class A { ... }; 

class B1 : public A { ... }; 

class B2 : public A, public FooFighter { ... }; 

... 

int main() { 
    std::vector<A *> v; 

    // fill up v 

    for (int i = 0; i < v.size(); ++i) { 
    FooFighter * ff = dynamic_cast<FooFighter *>(v[i]); 
    if (ff) ff.foo(); 
    } 
    return 0; 

}

這可以讓你保持一類是否具有獨立foo的層次結構的其餘部分。特別是,通過檢查任何類型的類層次結構,您總是知道該類型是否實現了foo,因爲它必須從FooFighter繼承。當你使用向下轉換的方法時,你可以讓A的多個孩子以不同的方式實現foo。這種方法也非常適用於IDE,可以讓您輕鬆檢查和遍歷代碼中的類型層次結構。