代码之家  ›  专栏  ›  技术社区  ›  Whaledawg

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

  •  12
  • Whaledawg  · 技术社区  · 17 年前

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

    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

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

    7 回复  |  直到 17 年前
        1
  •  19
  •   Damir Zekić    17 年前
        2
  •  4
  •   Keith Nicholas    17 年前

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

        3
  •  2
  •   Nick    17 年前

    将在一般情况下工作,但不适用于纯虚拟基类构造函数内的调用。在构造基类时,子类重写不存在,因此不能调用它。只要在构建整个对象后调用它,它就会工作。

        4
  •  2
  •   Adam Pierce    17 年前

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

    有两种解决方案:

    1. 在派生类的构造函数中调用Process()
    2. 定义流程的空白函数体,如下例所示:
    class parent
    {
      public:
        void Read() { //read stuff }
        virtual void Process() { }
        parent() 
        {
            Read();
            Process();
        }
    }
    
        5
  •  2
  •   Marcin Gil    17 年前

    再多走一步,你就可以引入一些函数,比如

    class parent
    {
        public:
            void initialize() {
                read();
                process();
            }
    }
    
        6
  •  1
  •   xtofl Adam Rosenfield    17 年前

    粗略的

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

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

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

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

    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() );
         }
    };
    
        7
  •  0
  •   Loki Astari    17 年前

    在对象完全构造后,需要将其封装到调用虚方法的对象中:

    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;
    }