为什么我需要在子类中重新声明`virtual`方法? [C ++ / Polymorphism]

时间:2017-10-26 11:01:15

标签: c++ polymorphism

有人可以解释,如果我们有一个带有virtual成员函数的抽象类, 为什么 我们需要在子类中再次声明它?例如,请参见下面的示例

抽象类

.h文件

#ifndef ALGORITHM_H
#define ALGORITHM_H

#include <vector>
#include "Event.h"

using std::vector;

class Algorithm{
protected:
  vector<Event>* dataset;
public:
  Algorithm(vector<Event>& dataset);
  virtual ~Algorithm();

  virtual void run() = 0;
};

#endif

.cpp文件

#include "../include/Algorithm.h"

Algorithm::Algorithm(vector<Event>& dataset):dataset(&dataset){}
Algorithm::~Algorithm(){}

鉴于声明纯虚函数run,通过扩展此类,我的期望是 需要实现。但是,它仍然需要在类中声明扩展此抽象类。

子类

.h文件

#ifndef SELECT_ALGORITHM_RANDOM_H
#define SELECT_ALGORITHM_RANDOM_H

#include "Algorithm.h"

class SelectAlgorithmRandom : public Algorithm{
public:
  SelectAlgorithmRandom(vector<Event>& dataset);
  ~SelectAlgorithmRandom();

  void run(); // <-- why do I need this here, and doesn't it defy the purpose of me declaring virtual `run` function in `Algorithm`? 
};

#endif

.cpp文件

#include "../include/SelectAlgorithmRandom.h"

SelectAlgorithmRandom::SelectAlgorithmRandom(vector<Event>& dataset):Algorithm(dataset){}
SelectAlgorithmRandom::~SelectAlgorithmRandom(){}

void SelectAlgorithmRandom::run(){
  //  TODO
}

3 个答案:

答案 0 :(得分:6)

您必须添加声明,因为C ++标准要求在类定义本身中声明类的每个成员:

[class.mem]/1

  

类定义中的成员规范声明了该类的完整成员集;没有成员可以添加到其他地方。

成员指的是功能和数据。 Algorithm中存在纯虚函数的事实并不自动意味着SelectAlgorithmRandom也将定义它。可以通过继承层次结构的多个层来保持类的抽象。

要定义run函数,必须在类定义中明确指定该intent。

顺便说一句,在现代C ++中,最好将该函数声明为意味着作为覆盖:

void run() override;

这样编译器会根据基类版本的定义对其进行检查,以确保您真正覆盖基类中的某些内容,而不是添加重载或某些不相关的函数。

答案 1 :(得分:1)

简而言之,如果你想实现polymorphism使用虚方法和指向基类的指针。

class A{
    public:
        virtual void F(){std::cout << "Base A::Foo()" << std::endl;}
};

class B : public A{
    public:
       void F(){std::cout << "B::Foo()" << std::endl;}
};

现在主要:

int main(){

    A* ptrA = new B;
    ptrA->Foo();

    return 0;
}

正如您在上面所看到的,根据Foo指向的对象类型调用方法ptrA

  • 方法重写需要在派生类中重新声明虚方法。

答案 2 :(得分:1)

您必须在std::memset (&st_arr[0], 0, sizeof(st_arr)); 声明中声明run()函数,以表明您确实打算为该类定义它。

如果没有,SelectAlgorithmRandom也将是一个抽象类,并且该函数可以在另一个派生类中定义。也许有几个级别了。