12

我想要一个纯虚拟父类来调用函数的子实现,如下所示:

class parent
{
  public:
    void Read() { //read stuff }
    virtual void Process() = 0;
    parent() 
    {
        Read();
        Process();
    }
}
class child : public parent
{
  public:
    virtual void Process() { //process stuff }
    child() : parent() { }
}

int main()
{
   child c;
}

这应该可以,但我得到一个未链接的错误:/ 这是使用 VC++ 2k3

或者它不应该工作,我错了吗?

4

7 回答 7

19

下一篇文章的标题说明了一切:在构造或破坏期间不要调用虚函数

于 2008-10-24T00:03:47.907 回答
4

或者,创建一个用于创建对象的工厂方法并将构造函数设为私有,然后工厂方法可以在构造后初始化对象。

于 2008-10-24T00:22:10.897 回答
2

通常可以工作,但不适用于纯虚拟基类的构造函数中的调用。在构造基类时,子类覆盖不存在,因此您不能调用它。只要您在构建整个对象后调用它,它就应该可以工作。

于 2008-10-24T00:01:18.787 回答
2

这是因为您的调用在构造函数中。在构造函数完成之前,派生类将无效,因此您的编译器对此进行了正确的测试。

有两种解决方案:

  1. 在派生类的构造函数中调用 Process()
  2. 为 Process 定义一个空白函数体,如下例所示:
class parent
{
  public:
    void Read() { //read stuff }
    virtual void Process() { }
    parent() 
    {
        Read();
        Process();
    }
}
于 2008-10-24T00:02:58.673 回答
2

再走一步,您就可以引入某种功能,例如

class parent
{
    public:
        void initialize() {
            read();
            process();
        }
}
于 2008-10-24T09:27:39.593 回答
1

表面问题是您调用了一个未知的虚函数(对象是从父级到子级构造的,因此 vtables 也是如此)。你的编译器警告过你。

据我所知,基本问题是您尝试通过继承重用功能。这几乎总是一个坏主意。一个设计问题,可以这么说:)

本质上,您尝试实例化模板方法模式,以将什么何时分开:首先读取一些数据(以某种方式),然后处理它(以某种方式)。

这可能会更好地使用聚合:将 Processing 函数赋予 Template 方法以在正确的时间调用。也许你甚至可以对 Read 功能做同样的事情。

聚合可以通过两种方式完成:

  1. 使用虚函数(即运行时绑定)
  2. 使用模板(即编译时绑定)

示例 1:运行时绑定

class Data {};
class IReader    { public: virtual Data read()            = 0; };
class IProcessor { public: virtual void process( Data& d) = 0; };

class ReadNProcess {
public:
    ReadNProcess( IReader& reader, IProcessor processor ){
       processor.process( reader.read() );
    }
};

示例 2:编译时绑定

template< typename Reader, typename Writer > // definitely could use concepts here :)
class ReadNProcess {
public:
     ReadNProcess( Reader& r, Processor& p ) {
         p.process( r.read() );
     }
};
于 2008-10-24T09:48:59.317 回答
0

您需要在对象完全构造后调用虚拟方法的对象内部:

class parent
{
  public:
    void Read() { /*read stuff*/ }
    virtual void Process() = 0;
    parent()
    {
        Read();
    }
};

class child: public parent
{
  public:
    virtual void Process() { /*process stuff*/ }
    child() : parent() { }
};

template<typename T>
class Processor
{
    public:
        Processor()
            :processorObj() // Pass on any args here
        {
            processorObj.Process();
        }
    private:
        T   processorObj;

};




int main()
{
   Processor<child> c;
}
于 2008-10-24T00:28:11.507 回答