Calling derived class function from base class

57,160

Solution 1

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.

Solution 2

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.

Share:
57,160

Related videos on Youtube

cpp help
Author by

cpp help

Updated on June 27, 2020

Comments

  • cpp help
    cpp help almost 4 years
    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.

    • Ed S.
      Ed S. over 13 years
      Of course it uses its own definition; that's polymorphism at work. Your question isn't very clear, why wouldn't you want to call the overriden implementation?
    • Rob Kennedy
      Rob Kennedy over 13 years
      Welcome to Stack Overflow. Please consider spending a little more time preparing your question so that it accurately demonstrates the issue you wish to discuss. That means posting a short, compilable and runnable example. When it's ready, copy and paste from your code editor into your browser; don't try to compose new code in your browser because you'll make mistakes, and it won't be clear to readers whether those mistakes are really part of your test case.
    • David Rodríguez - dribeas
      David Rodríguez - dribeas over 13 years
      Check that the signatures of start and stop match exactly in both classes, and that they are declared virtual at least in the base class. With the code as you posted, if you call doSomething() on a derived object you should be getting derived::start(); ...; derived::stop(); calls.
    • the_drow
      the_drow over 13 years
      @EdSwangren: I believe he wants to extend behavior. In that case in the implementation of start() and stop() in the derived class call base::start(); and base::stop(); respectively and handle the specifics for derived. Either that or make start and stop pure virtual and encapsulate the common behavior in protected functions.
    • the_drow
      the_drow over 13 years
      @RobKennedy: It doesn't have to be runable if there is a compile error he cannot solve.
    • Rob Kennedy
      Rob Kennedy over 13 years
      @The_drow, it's clearly not a compiler error if the problem is that it's using the wrong implementation of a function. That wouldn't be possible to know at compile time, so the actual code must be runnable. But in general, you're right — the requirement to post runnable code is waived if the problem is that it won't compile.
    • the_drow
      the_drow over 13 years
      @RobKennedy: My comment was just a general clarification for the OP.
    • sbi
      sbi over 13 years
      @cpp: Are you sure this sentence says what you wanted it to say: "But when I call doSomething() in the derived class it is using it's own definition of Start() and Stop() - not the derived ones." [emphasize mine]? Because if it does, I don't even understand what your problem is.
  • Michael Aaron Safyan
    Michael Aaron Safyan over 13 years
    @Marton, regardless of whether start() and stop() are declared virtual in Derived they will be virtual (a method that is declared virtual in a base class with an identical signature is automatically virtual in the derived class). As a matter of style, I prefer to redeclare them as virtual to make it clear that they are virtual without having to look up the documentation of the base class.
  • Michael Aaron Safyan
    Michael Aaron Safyan over 13 years
    NOTE: My comment above was in response to a deleted comment by Marton, which asked whether I intended to make start() and stop() virtual in the derived class, also.
  • cpp help
    cpp help over 13 years
    That's the opposite of what I needed - I need the base class doSomething() to pick up the derived start/stop when doSomething() is called in the derived class.
  • Michael Aaron Safyan
    Michael Aaron Safyan over 13 years
    @RageD, it is strictly a matter of style. I am now accustomed to using the Google C++ style (see: google-styleguide.googlecode.com/svn/trunk/…), where it states "When redefining an inherited virtual function, explicitly declare it virtual in the declaration of the derived class. Rationale: If virtual is omitted, the reader has to check all ancestors of the class in question to determine if the function is virtual or not." I think the rationale given makes sense.
  • Michael Aaron Safyan
    Michael Aaron Safyan over 13 years
    @cpp help, sorry, your question didn't make this clear. Will update shortly.
  • iheanyi
    iheanyi almost 10 years
    Looking at the updated answer, I don't see how this can work. Derived doesn't have a doSomething() method.