从基类调用派生类函数

cpp*_*elp 15 c++ virtual inheritance

class base
{
  public:
  virtual void start();
  virtual void stop();

  void doSomething() { start(); .... stop(); }
}

class derived : public base
{
  public:
   void start();
   void stop();
}
Run Code Online (Sandbox Code Playgroud)

但是当我调用doSomething()派生类时,它使用它自己的定义Start()Stop()不是派生类.

我不想doSomething()在派生类中重写,因为它与基类相同.我究竟做错了什么?

对不起,如果不清楚.
派生类中Start()和Stop()的行为是不同的(它是一个不同的机器) - 但我想使用原始基类doSomething(),因为它没有改变.它只需要使用新的派生类代码start()和stop().

Rob*_*edy 25

您发布的代码应该按照您想要的方式工作.调用doSomething一个实例derived将调用被覆盖的start和被stop定义的函数derived.

但是有一个例外.如果你doSomething在构造函数或析构函数中调用base(无论是直接还是间接),那么被调用的startstop将被定义的版本base.那是因为在那种情况下,你实际上还没有有效的derived实例.它不是完全构造的或部分破坏的,因此该语言阻止您调用将使用部分对象的方法.

如果你没有从base构造函数或析构函数中调用它,那么问题就比这里显示的更多了.


Mic*_*yan 7

更新
根据您在下面的评论,您试图让doSomething()调用Derived类的start()和stop()版本,我对您的问题的更新答案如下:

您定义Base和Derived的方式没有任何问题.您可能正在经历所谓的"代码切片",您在声明类型为"Base"的对象上调用"doSomething()",而不是"Base*"或"Base&",这将导致对象成为转换为Base类型.

不好的例子:

 Derived derived;
 Base base = derived;
 base.doSomething();  // This is Base's version of doSomething()
Run Code Online (Sandbox Code Playgroud)

好例子:

 Base* base = new Derived;  // NOTE: declared type is "Base*"
 base->doSomething();  // This will call Derived version
 delete base;
Run Code Online (Sandbox Code Playgroud)

注意:你应该使用scoped_ptr,shared_ptr,unique_ptr或其他一些智能指针类,而不是像我的例子那样直接使用指针; 但是,为了不掩盖这个问题,我选择在这个例子中使用原始指针.有关"切片"的更多信息,请参阅:

原始解决方案
您可以执行以下操作:

class Base {
    public:
        Base() {}
        virtual ~Base() {}

        virtual void start() {
           startInternal();
        }

        virtual void stop() {
            stopInternal();
        }

        void doSomething() {
            startInternal();
            // ...
            stopInternal();
        }
    private:
        void startInternal() {
          // ...
        } 
        void stopInternal() {
          // ...
        }
};

class Derived : public Base {
    public:
        Derived() {}
        virtual ~Derived() {}
        virtual void start() {
            // ...
        }
        virtual void stop() {
            // ...
        }
};
Run Code Online (Sandbox Code Playgroud)

如果你这样做,那么doSomething()将使用未被覆盖的内部版本的start/stop.当构造函数/析构函数需要与虚方法共享逻辑时,您会发现很多这种模式.

此外,与手头的问题无关,不要忘记每当创建具有虚方法的类时,都应始终创建虚拟析构函数.