让OOP正确

时间:2011-07-01 06:36:40

标签: c++

好的,这是我的问题。我有以下课程:

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并从Job派生它。但这是我的问题。我还有以下功能,它只能用于SongJob:

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

这里我只是希望它显示该函数仅使用派生对象方法。因此,如果我有另一个从Job派生的对象,我需要将参数更改为Job,但是编译器不会知道thoose函数,我不知道测试每个人是什么类型的对象然后将其转换为所以我可以调用正确的函数。

所以将所有函数放在基类中是可以的,因为那时我没有问题,但是我不知道这是否是正确的OOP,如果一个类处理歌曲而另一个类处理视频,我事情好的oop意味着有2个clases。

如果我没有说清楚,请说出来,我会尝试更好地解释 简而言之,我想使用多态性。

5 个答案:

答案 0 :(得分: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

答案 1 :(得分:3)

在您的基类Job中,您可以将这些方法添加为virtual methods,以便从Job派生的类可能会或可能不会覆盖这些特定方法。

在您的SongJob班级中,您覆盖了这些方法,并且不会在VideoJob

中覆盖它们

在,void process()传递指向基类Job

的指针
void process(Job *s) 

然后根据目标的地址调用适当的方法指向哪个SongJob对象。

答案 2 :(得分: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”的东西,以及各种关于这种愚蠢的“多态”事物的复杂事物;他们是对的。

但这基本上是多功能的一点,在功利主义意义上:它是这样你不必在调用函数之前检查每个类的类型。您只需在基类型上调用函数,最终将调用正确的派生实现。

BTW,在C ++中,virtual ... someFunc(...) = 0;表示中定义的函数类型不能实例化,必须在派生类中实现。它被称为“pure virtual”函数,它定义的类变为“abstract”。

答案 3 :(得分:0)

您的问题来自您在对象上调用进程方法的事实。您应该在Job类上有一个方法Process,并在派生类中重写此方法。

答案 4 :(得分:0)

使用纯虚函数:

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