从基类调用派生类函数

时间:2011-02-01 23:33:14

标签: c++ inheritance virtual

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

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

class derived : public base
{
  public:
   void start();
   void stop();
}

但是当我在派生类中调用doSomething()时,它正在使用它自己对Start()Stop()的定义 - 而不是派生类。

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

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

3 个答案:

答案 0 :(得分:23)

您发布的代码应该按照您想要的方式运行。在doSomething的实例上调用derived会调用start中定义的被覆盖的stopderived个函数。

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

如果您没有从base构造函数或析构函数中调用它,那么问题就会出现问题,而不是此处显示的内容。

答案 1 :(得分: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()

很好的例子:

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

旁注:您应该使用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() {
            // ...
        }
};

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

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

答案 2 :(得分:1)

只需在基类中将启动和停止函数声明为纯虚函数即可。

virtual void stop() = 0;
virtual void start() = 0;