2011-07-01 85 views
2

好的,這是我的問題。我有以下類:正確獲取OOP

class Job { 
    bool isComplete() {} 
    void setComplete() {} 
    //other functions 
}; 

class SongJob: public Job { 
    vector<Job> v; 
    string getArtist() {} 
    void setArtist() {} 
    void addTrack() {} 
    string getTrack() {} 
    // other functions 
}; 
// This were already implemeted 

現在我想實現一個VideoJob並從作業派生它。但這是我的問題。我也有以下功能巫婆它設置爲只與SongJob工作:

void process(SongJob s) 
{ 
// not the real functions 
    s.setArtist(); 
    .............. 
    s.getArtist(); 
    ............. 
    s.getArtist(); 
    ............... 
    s.setArtist() 
} 

在這裏,我只是希望它表明該函數只使用派生類對象的方法。因此,如果我有另一個派生於Job的對象,我需要將參數更改爲Job,但是編譯器不會知道什麼是Thoose函數,我不知道要測試每個人是什麼類型的對象,然後將它投射出來,所以我可以調用正確的功能。

因此,將所有函數放在基類中是可以的,因爲那樣我就沒有問題了,但我不知道這是否正確OOP,如果一個類處理歌曲,另一個類處理視頻,我好的oop意味着有2個clases。

如果我沒有說清楚,請說出來,我會嘗試更好地解釋。
換句話說,我想用polymorfism。

回答

4

這是完全正常把所有的類SongJobVideoJob有共同到一個共同的基類的東西。但是,一旦你想添加一個與藝術家無關的Job的子類,這會造成問題。

有些事情需要注意您發佈的代碼。首先,你的班級Job顯然不是abstract base class。這意味着你可以有隻是工作的工作。不是SongJob而不是VideoJob。如果你想清楚,不能有一個簡單的Job,使基類摘要:

class Job { 
    virtual bool isComplete() = 0; 
    virtual void setComplete() = 0; 
    //other functions 
}; 

現在,你不能創建的Job實例:

Job job; // compiler-error 
std::vector<Job> jobs; // compiler-error 

注意功能現在是虛擬的,這意味着子類可以覆蓋它們。 = 0和最後意味着子類必須提供這些函數的實現(它們是pure virtual member functions)。

其次,您的班級SongJob有一個成員std::vector<Job>。這幾乎肯定不是你想要的。如果你添加一個SongJob到這個向量,它將成爲一個正常的Job。這種效應被稱爲slicing。爲了防止它,你必須使它成爲std::vector<Job*>

這裏還有很多話要說,但那會很快。我建議你得到一個好的book

+0

所以如果SonjJob有一個容器來存儲歌曲和VideoJob一個來存儲視頻,這些容器我應該把它們也放在基類中?我認爲派生類不會有任何數據:) – Kobe

+0

我知道關於oop細節,我的問題是我需要在C++和java中做這個,所以我需要用兩種語言來思考:)但是你的解釋是非常好。謝謝 – Kobe

+2

@vBx:不,你可以將這些容器放入類中。他們是不同的,因爲一個商店*只有*視頻,而其他商店*只*歌曲。這不是一個共同點,而是一個區別,所以它不屬於基類。 –

0

您的問題來自您在對象上調用流程方法的事實。你應該有一個Job類的方法Process,並在你的派生類中重寫這個方法。

+0

好的,這就是我所做的,但後來我需要使用typeid,因爲一個deirved對象有hasNewTrack(),另一個派生對象hasnewClip(),所以基類對象沒有任何這個,所以我得到錯誤 – Kobe

+0

Job.Process可以被做成純虛擬的(沒有實現)。然後SongJob.Process將調用hasNewTrack,但它不會調用hasNewClip和VideoJob.Process將調用hasNewClip,但它不會調用hasNewTrack。 – Dan

0

使用純虛函數:

class Job 
{ 
virtual string getArtist() =0; 
}; 
3

在您的基類Job中,您可以將這些方法添加爲virtual methods,以便派生自Job的類可以覆蓋或不覆蓋這些特定的方法。

在你SongJob類重寫的方法和不覆蓋它們在VideoJob

在,void process()將指針傳遞給基類Job

void process(Job *s) 

然後,它會調用取決於ADRESS適當的方法的對象是指向哪個將是一個SongJob對象。

+0

嗯,這聽起來是對的 – Kobe

2

在C++中,你必須做兩件事情讓多態性的工作:

  • 訪問態函數通過引用(&)或指針(*)的基本類型
  • 定義態函數如在基類型

所以virtual,改變這些從:

class Job { 
    bool isComplete() {} 
    void setComplete() {} 
}; 

void process(SongJob s) 
{ 
    // ... 
} 

要:

class Job { 
    public: // You forgot this... 
    virtual bool isComplete() { } 
    virtual void setComplete() { } 
}; 

void process(Job& s) 
{ 
    // ... 
} 

如果你不能確定你需要的內部process在你的基類(如果所有你想要的成員函數並不適用於所有的派生類)的所有功能,那麼你需要把process成一個成員函數上Job,並使其虛擬:

class Job { 
    public: 
    virtual bool isComplete() { } 
    virtual void setComplete() { } 
    virtual void process() = 0; 
}; 

// ... 

int main(int argc, char* argv[]) 
{ 
    SongJob sj; 
    Job& jobByRef = sj; 
    Job* jobByPointer = new SongJob(); 

    // These call the derived implementation of process, on SongJob 
    jobByRef.process(); 
    jobByPointer->process(); 

    delete jobByPointer; 
    jobByPointer = new VideoJob(); 

    // This calls the derived implementation of process, on VideoJob 
    jobByPointer->process(); 

    return 0; 
} 

,當然還有,你就會有process兩種不同的實現。每種類型一個。人們會告訴你各種各樣的「is-a」vs「has-a」的東西,以及關於這個愚蠢的「多態」事物的各種複雜的事情;他們是正確的。

但是這基本上是多功能性的一點,在功利意義上說:它是這樣的,所以你不必在每次調用函數之前檢查它的類型。你可以在基類型上調用函數,並且最終調用正確派生的實現。

順便說一句,在C++中,virtual ... someFunc(...) = 0;意味着函數在定義的類型不能被實例化,並且必須在派生類來實現。它被稱爲「pure virtual」函數,它定義的類變爲「abstract」。