在非纯虚函数中使用纯虚函数的 C++ 抽象类

c++ abstract classes using pure virtual functions in non pure virtual functions

本文关键字:函数 C++ 抽象类      更新时间:2023-10-16

我想创建一个抽象类,该类具有由构造函数调用的纯虚函数,该函数不是纯虚拟的。 以下是我的文件class.hpp

#ifndef __CLASS_HPP__
#define __CLASS_HPP__
#include <iostream>
class Parent {
 public:
  Parent(){
    helloWorld(); // forced to say hello when constructor called                    
  };
  virtual void helloWorld() = 0; // no standard hello...                            
};
class Child : public Parent {
 public:
  void helloWorld(){ // childs implementation of helloWorld                         
    std::cout << "Hello, World!n";
  };
};
#endif

在这个例子中,我有一个父类,它有一个纯虚函数helloWorld()。 我希望每个派生类在调用构造函数时都说"你好";因此,为什么helloWorld()在父类构造函数中。 但是,我希望每个派生类都被迫选择如何说"hello",而不是使用默认方法。 这可能吗? 如果我尝试使用 g++ 编译它,我会收到构造函数正在调用纯虚函数的错误。 我main.cpp是:

#include "class.hpp"
int main(){
  Child c;
  return 0;
}

我正在使用g++ main.cpp -o main.out进行编译,结果错误是:

In file included from main.cpp:1:0:
class.hpp: In constructor ‘Parent::Parent()’:  
class.hpp:9:16: warning: pure virtual ‘virtual void Parent::helloWorld()’ called from constructor [enabled by default]

关于如何以合法方式获得类似设置的任何建议?

新问题

DyP 让我注意到构造函数不使用任何重写的函数,所以我希望能够做的事情以我设置它的方式是不可能的。 但是,我仍然想强制任何派生构造函数调用函数helloWorld(),有什么办法可以做到这一点吗?

你正在做的事情是非法的。

为了在C++中定义抽象类,您的类必须至少有一个纯虚函数。在您的情况下

virtual void helloWorld() = 0;

在这种情况下,你是对的。

但是你的纯虚函数

没有任何实现,因为它是一个纯虚函数。所以从同类的康斯坦鲁克托调用纯虚函数是非法的(在类级纯虚函数没有任何实现)

所以

Parent(){
helloWorld(); // forced to say hello when constructor called                    
};

这是非法的。

如果需要,可以在派生类

中实现纯虚函数,然后从派生类的构造函数调用helloWorld()

为什么不简单地将其添加到每个子类的构造函数中?

如果你想避免每次在构造函数中写入它(甚至跳过或继承它),那么你可以使用 CRTP:

class Parent {
 public:
  Parent(){};
  virtual void helloWorld() = 0; // no standard hello...                            
};
template <typename Par>
class ParentCRTP: public Parent {
 public:
  ParentCRTP(){
    Par::doHelloWorld();
  };
  virtual void helloWorld(){
    Par::doHelloWorld();
  }
};
class Child : public ParentCRTP<Child> {
 public:
  static void doHelloWorld(){ // childs implementation of helloWorld                         
    std::cout << "Hello, World!n";
  };
};

此方法不会在子项的 hello 方法中为您提供指向子类的指针 - 此时类实例仅Parent实例,无法获取有效的Child指针。要在构造后强制执行Child的方法,您只能使用两个阶段初始化:首先使用构造函数创建类实例,然后使用单独的方法对其进行初始化。

除此之外,像这样的问题可能是重新思考你的设计的暗示。你不应该强迫你的类以给定的方式初始化自身。