父 class 中的虚函数未调用子 class 中的方法

Method in child class doesn't get called by virtual function in parent class

在我的应用程序中,我有几个读取器从 .csv 文件中读取数据。我现在想通过为那些共同拥有方法 getData(std::string filename) 的读者创建父 class 来构建它们。我想通过在基 class 中实现一个虚拟方法来实现。文件名应该由构造函数传递。

主要

int main()
{
    std::string filename = "file.csv";
    ChildReader1 reader = new ChildReader1(filename);
}

ChildReader1.h

class ChildReader1: public ParentReader
    {
    public:
        ChildReader1(std::string filename)
            : ParentReader(filename)
        {

        };
        void getData(std::string filename)
        {
             //get the data here
        }
    };

ParentReader.h

class ParentReader
    {
    public:
        ParentReader() {};
        ParentReader(std::string filename)
        {
            getData(filename);
        };
        ~ParentReader() {};

        virtual void getData(std::string filename) {};
    };

目前,filename 被传递给 ParentReader,但是 getData(filename) 在 ParentReader 中打开虚拟方法,而不是在 ChildReader 1 中打开实际方法。我该如何解决?

在构造基(父)过程中不调用虚拟方法class。因为派生还没有准备好。

12.7 构造与破坏[class.cdtor]#4ISO/IECN3797

Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a virtual function is called directly or indirectly from a constructor or from a destructor, including during the construction or destruction of the class’s non-static data members, and the object to which the call applies is the object (call it x) under construction or destruction, the function called is the final overrider in the constructor’s or destructor’s class and not one overriding it in a more-derived class. If the virtual function call uses an explicit class member access (5.2.5) and the object expression refers to the complete object of x or one of that object’s base class subobjects but not x or one of its base class subobjects, the behavior is undefined.

正如其他人所提到的,您不能在基 class 构造函数中的派生 class 上调用虚方法,因为派生 class 尚未准备好。

一个解决方案是在 ChildReader1:

上有一个工厂函数
class ParentReader {
public:
  ParentReader(){};
  void initialize(const std::string& filename){
    getData(filename);
  };
  virtual ~ParentReader(){};
  virtual void getData(const std::string& /*filename*/) {
  };
};

class ChildReader1 : public ParentReader {
private:
  ChildReader1(){}
public:
  void getData(const std::string& /*filename*/) override {
    // get the data here
  }
  static std::unique_ptr<ChildReader1> create(const std::string &filename) {
    auto reader = std::unique_ptr<ChildReader1>(new ChildReader1);
    reader->initialize(filename);
    return reader;
  }
};

int main() {
  std::string filename = "file.csv";
  auto reader = ChildReader1::create(filename);
}

工厂函数创建一个完整的对象,然后可以在返回前调用虚函数。您可以将对象的构造函数设为私有,以强制调用者使用您的工厂函数。

为了避免派生的 classes 之间的代码重复,您可以引入中间 CRTP class.

您可以通过工厂解决您的问题:

class ParentReader
{
public:
    virtual ~ParentReader() = default
    virtual void getData(const std::string& filename) = 0;
};

template <typename T, typename ... Ts>
std::unique_ptr<T> MakeReader(const std::string& filename, Ts&&... args)
{
    static_assert(std::is_base_of<ParentReader, T>::value, "!");
    auto res = std::make_unique<T>(std::forward<Ts>(args)...);
    res->getData(filename);
    return res;
}

正如其他人所说,您不应该在构造函数中调用虚函数。如果您考虑正在发生的事情,原因很简单:

调用 ChildConstructor -> 调用 ParentConstructor -> 创建 Parent -> 调用 getData -> 创建 Child

在调用 getData 时,唯一存在的对象是 Parent,因此它不可能调用 Child 的 getData。