2011-07-01 46 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”。