C++ 从基类调用派生类函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4869216/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 16:48:41  来源:igfitidea点击:

Calling derived class function from base class

c++inheritancevirtual

提问by cpp help

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

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

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

But when I call doSomething()in the derived class it is using it's own definition of Start()and Stop()- not the derived ones.

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

I don't want to rewrite doSomething()in the derived class because it would be identical to the base one. What am I doing wrong?

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

Sorry if that wasn't clear.
The behaviour of Start() and Stop() in the derived class is different (it's a different machine) - but I want to use the original base class doSomething() because that hasn't changed. It just has to start() and stop() using the new derived class code.

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

回答by Rob Kennedy

The code you've posted should work the way you want. Calling doSomethingon an instance of derivedwill call the overridden startand stopfunctions defined in derived.

您发布的代码应该按照您想要的方式工作。调用doSomething的实例derived将调用 中定义的重写startstop函数derived

There's an exception to that, though. If you call doSomethingin the constructor or destructor of base(whether directly or indirectly), then the versions of startand stopthat get called will be the ones defined in base. That's because in those circumstances, you don't actually have a valid derivedinstance yet. It's either not fully constructed or partially destructed, so the language prevents you from calling methods that would use the partial object.

不过也有例外。如果您调用(直接或间接)doSomething的构造函数或析构函数base,则调用的start和的版本stop将是base. 那是因为在这些情况下,您实际上还没有有效的derived实例。它要么没有完全构建,要么部分被破坏,因此该语言阻止您调用将使用部分对象的方法。

If you're not calling it from a baseconstructor or destructor, then there is more to the problem than what's shown here.

如果您不是从base构造函数或析构函数调用它,那么问题就比这里显示的要多。

回答by Michael Aaron Safyan

Update
Based on your comment below that you are trying to make doSomething() call the Derived class's version of start() and stop(), my updated answer to your question is as follows:

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

There is nothing wrong with the way that you defined Base and Derived. You are probably experiencing what is called "code slicing", where you are calling "doSomething()" on an object whose declared type is "Base", instead of "Base*" or "Base&", which will result in the object being converted to type Base.

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

Bad example:

不好的例子:

 Derived derived;
 Base base = derived;
 base.doSomething();  // This is Base's version of doSomething()

Good example:

好的例子:

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

Side-note: you should use a scoped_ptr, shared_ptr, unique_ptr, or some other smart pointer class instead of using a pointer directly as in my example; however, to not obscure the issue, I have opted to use a raw pointer in this example. For more information about "slicing", see:

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

Original solution
You could do something like this:

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

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() {
            // ...
        }
};

If you do this, then doSomething() will use the internal version of start/stop which isn't overridden. You will find this pattern a lot, when a constructor/destructor needs to share logic with a virtual method.

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

Also, not related to the issue at hand, don't forget that you should always create a virtual destructor whenever you create a class that has virtual methods.

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