子类中的方法不会被父类中的虚函数调用
Method in child class doesn't get called by virtual function in parent class
在我的应用程序中,我有几个读取器,它们从.csv文件中读取数据。我现在想通过为那些拥有方法getData(std::string filename)
的读者创建一个父类来构建它们。我想通过在基类中实现一个虚拟方法来实现它。文件名应由构造函数传递。
主
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中的虚拟方法,而不是ChildReader1中的实际方法。我该如何解决?
您可以通过工厂解决问题:
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;
}
在构造基类(父类)期间不会调用虚拟方法。因为派生的还没有准备好。
12.7结构和破坏[Cditor]#4 ISO/IEC N3797
成员函数,包括虚拟函数(10.3),可以在构造或销毁(12.6.2)期间调用。当从构造函数或析构函数直接或间接调用虚拟函数时,包括在类的非静态数据成员的构造或销毁期间,调用所应用的对象是正在构造或销毁的对象(调用它x),调用的函数是构造函数或析构函数类中的最后一个重写器,而不是在更派生的类中重写它。如果虚拟函数调用使用显式类成员访问(5.2.5),并且对象表达式引用x的完整对象或该对象的基类子对象之一,而不是x或其基类子对象之一来,则行为未定义。
正如其他人所提到的,您不能在基类构造函数中的派生类上调用虚拟方法,因为派生类还没有准备好。
一种解决方案是在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);
}
工厂函数创建一个完整的对象,然后可以在返回之前调用虚拟函数。您可以将对象的构造函数设为私有,以强制调用方使用您的工厂函数。
为了避免派生类之间的代码重复,可以引入一个中间CRTP类。
正如其他人所说,您不应该在构造函数中调用虚拟函数。如果你想想正在发生的事情,原因很简单:
调用ChildConstructor->调用ParentConstructor->创建Parent->调用getData->创建Child
在调用getData时,唯一存在的对象是Parent,因此它不可能调用Child的getData。
- C++调用使用重写函数的父类函数
- 使用 Clang LibTooling 扫描C++在模板化父类中调用本地类的源
- 在父类函数中创建子类 - 可能吗?
- 调用父类函数来比较父类和子类
- 从多重继承中的派生类函数调用适当的父类函数
- C++:如何从外部调用父类函数
- 在类函数调用期间丢失私有变量信息
- 从基类函数调用派生类函数
- 禁用或隐藏C++中的某些父类函数
- 使用父类函数作为回调订阅主题
- 使用具有相同名称和属性的父类函数
- 在类中使用typedef定义指向父类函数的函数指针
- C++父类,调用子类中的方法,调用父类方法
- 基类函数调用的替代设计模式
- 从派生类函数调用基函数
- 给父类指针调用子类的方法
- 如何从基类函数调用重写虚函数
- 如何在父类中调用子类
- C++:从非类函数调用类方法
- 调用与父类函数指针同名的函数