从基类调用派生类函数

发布于 2024-10-15 12:51:03 字数 507 浏览 3 评论 0原文

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() 因为它没有改变。它只需使用新的派生类代码启动()和停止()。

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.

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?

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

ㄟ。诗瑗 2024-10-22 12:51:03

您发布的代码应该按照您想要的方式工作。在 衍生 实例上调用 doSomething 将调用 衍生< 中定义的重写 startstop 函数/代码>。

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

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

The code you've posted should work the way you want. Calling doSomething on an instance of derived will call the overridden start and stop functions defined in derived.

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

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

泪之魂 2024-10-22 12:51:03

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

您定义 Base 和 的方式没有任何问题衍生的。您可能正在经历所谓的“代码切片”,即您在声明类型为“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 的内部版本。当构造函数/析构函数需要与虚拟方法共享逻辑时,您会经常发现这种模式。

另外,与当前的问题无关,不要忘记,每当您创建具有虚拟方法的类时,您都应该创建一个虚拟析构函数。

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:

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.

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:

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.

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文