C++ C++;调用子虚函数的父类

C++ C++;调用子虚函数的父类,c++,inheritance,virtual,C++,Inheritance,Virtual,我希望纯虚拟父类调用函数的子实现,如下所示: class parent { public: void Read() { //read stuff } virtual void Process() = 0; parent() { Read(); Process(); } } class child : public parent { public: virtual void Process() { //pro

我希望纯虚拟父类调用函数的子实现,如下所示:

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


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

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

这是因为您的调用在构造函数中。在构造函数完成之前,派生类将无效,因此编译器会就此向您发出警告

有两种解决方案:

  • 在派生类的构造函数中调用Process()
  • 定义流程的空白函数体,如下例所示:

  • 以下文章的标题说明了这一切:。

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

    您需要在对象完全构建后封装在调用虚方法的对象中:

    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;
    }
    
    类父类
    {
    公众:
    void Read(){/*读取内容*/}
    虚空进程()=0;
    父项()
    {
    Read();
    }
    };
    类子:公共父类
    {
    公众:
    虚空进程(){/*进程文件*/}
    子():父(){}
    };
    模板
    类处理器
    {
    公众:
    处理器()
    :processorObj()//在此处传递任何参数
    {
    processorObj.Process();
    }
    私人:
    T处理器bj;
    };
    int main()
    {
    处理器c;
    }
    
    再多做一步,您就可以引入一些函数,如

    class parent
    {
        public:
            void initialize() {
                read();
                process();
            }
    }
    

    肤浅的问题在于调用了一个未知的虚拟函数(对象是从父对象到子对象构造的,因此vtables也是如此)。你的编译器警告过你这一点

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

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

    这可能会更好地处理聚合:为模板方法提供处理函数,以便在正确的时间调用。也许您甚至可以对读取功能执行相同的操作

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

  • 使用虚拟函数(即运行时绑定)
  • 使用模板(即编译时绑定)
  • 示例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() );
        }
    };
    
    template< typename Reader, typename Writer > // definitely could use concepts here :)
    class ReadNProcess {
    public:
         ReadNProcess( Reader& r, Processor& p ) {
             p.process( r.read() );
         }
    };
    
    示例2:编译时绑定

    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() );
        }
    };
    
    template< typename Reader, typename Writer > // definitely could use concepts here :)
    class ReadNProcess {
    public:
         ReadNProcess( Reader& r, Processor& p ) {
             p.process( r.read() );
         }
    };
    
    template//这里绝对可以使用概念:)
    类ReadNProcess{
    公众:
    读写过程(读写器&r、处理器&p){
    p、 进程(r.read());
    }
    };
    
    这是危险的,在父函数中定义一个空函数体并在其构造函数中调用它将导致只执行Process()的父函数部分(即nothing)。他可能希望调用作为一个虚函数来解决,这在结构上是不可能的:空白函数将被调用。这不是可行的解决方案。正确,但有点短。你至少应该复制这样的结论:“要记住的事情:在构造或销毁期间不要调用虚拟函数,因为这样的调用永远不会到达比当前正在执行的构造函数或析构函数派生得更多的类。”不过,我真的认为,在通过继承混合功能之前,你应该三思。这个问题显示了表面下的设计流程。