C++类继承在派生类中分离方法

C++ Class Inheritance separate methods in derived class

本文关键字:分离 方法 继承 C++ 派生      更新时间:2023-10-16

我得到了三个类MachineLearningMachineLearningSVMMachineLearningAdaboost

MachineLearning是基类,MachineLearningSVMMachineLearningAdaboost从中派生

class MachineLearning;      //Base class
class MachineLearningSVM : public MachineLearning;   
class MachineLearningAdaboost : public MachineLearning;
class `MachineLearning` {
   public:
      virtual void Train();
}
class MachineLearningSVM : public MachineLearning {
   public:
       void Train(std::vector<Feature> features);
}
class MachineLearningAdaboost : public MachineLearning {
   public:
       void Train(std::vector<Feature> features, std::vector<Label> labels);
}

我的问题是,我想告诉所有派生类,它们应该保留一个函数Train(),但每个派生类的方法定义中都应该有不同的参数。如上所述,Adaboost需要(例如)额外的标签进行培训。

考虑以下内容:

 int main(){
     MachineLearning* ml;
     switch(type){
         case SVM:
             ml = new MachineLearningSVM();
             break;
         case Adaboost:
             ml = new MachineLearningAdaboost();
             break;
     }
     ml->Train(std::vector<Feature>);
 }

C++在编译时不知道该调用哪个Train函数,因为不清楚它是SVM还是Adaboost类型。

我该如何实现此场景?我想避免使用模板。

您从根本上误解了多态性和继承的概念。派生类必须与基类具有is-a关系:MachineLearningSVMMachineLearning,特别是在基类中声明的virtual函数(但在派生类中定义或重写)将可从指向基类的指针调用。

在您的示例中,这毫无意义:

MachineLearning*ptr = get_machine_learning(); // can be either derived class
ptr->Train();           // we don't know which derived class so what do you
                        // want to pass as arguments???

你可以定义一个更灵活的接口,但你仍然有同样的问题(例外情况很明显):

struct MachineLearning
{
  void Train(std::vector<Feature> const&features)
  {
    if(need_labels()) throw std::runtime_error("need labels to train");
    train(features);
  }
  void Train(std::vector<Feature> const&features,
             std::vector<Label> const&labels)
  {
    if(!need_labels()) std::cerr<<"WARNING: ignoring labels for trainingn";
    train(features,labels);
  }
  virtual~MachineLearning() {}
protected:
  virtual void train(std::vector<Feature> const&) = 0;
  virtual void train(std::vector<Feature> const&,
                     std::vector<Label> const&) = 0;
  virtual bool need_labels() const = 0;
};
struct MachineLearningSVM : MachineLearning
{
protected:
  bool need_labels() const { return false; }
  void train(std::vector<Feature> const&features) override;
  void train(std::vector<Feature> const&features,
             std::vector<Label> const&) override
  { train(features); }
};
struct MachineLearningAdaboost : public MachineLearning
{
protected:
  bool need_labels() const { return true; }
  void train(std::vector<Feature> const&) override
  { throw std::runtime_error("need labels for training"); }
  void train(std::vector<Feature> const&features,
             std::vector<Label> const&labels) override;
};

这些错误和警告是糟糕代码设计的标志。。。

这里的问题是,在C++中,函数签名是使用其名称和传递给它的参数类型创建的。基类不包含带有签名的函数

void Train(std::vector<Feature> features);

因此编译器开始大喊大叫。从技术上讲,你可以通过声明虚拟函数来修复你的代码,但它不会真正起作用,因为你的设计中存在问题,正如前面的响应中提到的那样。