26
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.

Arun
  • 19,750
  • 10
  • 51
  • 60
cpp help
  • 279
  • 1
  • 3
  • 5
  • 3
    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? – Ed S. Feb 01 '11 at 23:35
  • 4
    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. – Rob Kennedy Feb 01 '11 at 23:36
  • 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. – David Rodríguez - dribeas Feb 01 '11 at 23:37
  • 1
    @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 Feb 01 '11 at 23:38
  • @RobKennedy: It doesn't have to be runable if there is a compile error he cannot solve. – the_drow Feb 01 '11 at 23:38
  • 1
    @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. – Rob Kennedy Feb 01 '11 at 23:41
  • @RobKennedy: My comment was just a general clarification for the OP. – the_drow Feb 01 '11 at 23:42
  • 2
    @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. – sbi Feb 01 '11 at 23:50

2 Answers2

42

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.

Olivia Stork
  • 4,660
  • 5
  • 27
  • 40
Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
15

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.

Community
  • 1
  • 1
Michael Aaron Safyan
  • 93,612
  • 16
  • 138
  • 200
  • @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 Feb 01 '11 at 23:47
  • 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. – Michael Aaron Safyan Feb 01 '11 at 23:47
  • 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. – cpp help Feb 01 '11 at 23:48
  • @RageD, it is strictly a matter of style. I am now accustomed to using the Google C++ style (see: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Inheritance), 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 Feb 01 '11 at 23:49
  • @cpp help, sorry, your question didn't make this clear. Will update shortly. – Michael Aaron Safyan Feb 01 '11 at 23:50
  • Looking at the updated answer, I don't see how this can work. Derived doesn't have a doSomething() method. – iheanyi Jun 19 '14 at 20:26