Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Inheritance : Calling virtual method when it has been overridden

I am trying to build a service object which can run (i.e. execute it's run() function) in a separate thread. This is the service object

#include <boost/noncopyable.hpp>
#include <atomic>
#include <thread>
#include <iostream>

class service : public boost::noncopyable {
 public:
  service() : stop_(false), started_(false) { }

  virtual ~service() {
    stop();
    if (thread_.joinable()) {
      thread_.join();
    }
  }

  virtual void stop() { stop_ = true; }

  virtual void start() {
    if (started_.load() == false) {
      started_ = true;
      thread_ = std::thread([&] () {
        run();
      });
    }
  }

 protected:
  virtual void run() = 0;

  std::atomic<bool> stop_;

  std::atomic<bool> started_;

  std::thread thread_;
};

I am the creating a test class which inherits from this abstract class and is called in the main() function

class test : public service {
 public:
  test() : service() {
    std::cout<< "CTOR" << std::endl;
    start();
  }

  ~test() {
    std::cout<< "DTOR" << std::endl;
  }

 protected:
  void run() override {
    std::cout << "HELLO WORLD" <<std::endl;
  }
};


int main() {
  test test1;
  return 0;
}

Now when I execute this, why do I get an error saying pure virtual function called? The run() function is clearly overridden in the test class. Whats worse is that it runs correctly sometimes?

$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception

$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception

$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception

$ ./a.out
CTOR
DTOR
HELLO WORLD

$ ./a.out
CTOR
DTOR
pure virtual method called
terminate called without an active exception

What could be going wrong here?

like image 294
ssb Avatar asked Jul 17 '15 23:07

ssb


People also ask

Can a virtual method be overridden?

A virtual method can be created in the base class by using the “virtual” keyword and the same method can be overridden in the derived class by using the “override” keyword.

Is it mandatory to override virtual method?

It is not mandatory for the derived class to override (or re-define the virtual function), in that case, the base class version of the function is used.

What happens if we don't use virtual function in inheritance?

If you don't use virtual functions, you don't understand OOP yet. Because the virtual function is intimately bound with the concept of type, and type is at the core of object-oriented programming, there is no analog to the virtual function in a traditional procedural language.

Can a private virtual method be overridden in derived class?

A private virtual function can be overridden by derived classes, but can only be called from within the base class.


1 Answers

Follow along, step by step:

1) You construct the object.

2) You execute the following piece of code:

if (started_.load() == false) {
  started_ = true;
  thread_ = std::thread([&] () {
    run();
  });
}

The parent thread immediately returns to main() where it immediately exits and destroys your object.

Here's your bug:

  • You are not guaranteed that the thread started in start() is going to reach the call to run(), above, before the parent thread terminates the process. Both the child thread, and the parent thread runs concurrently.

So, every once in a while, the parent thread will destroy the object before the child thread gets in gear, and calls run().

At this point, the object whose run() method gets invoked, is already destroyed.

Undefined behavior.

The assertion you're hitting, every once in a while, is one possible result of this undefined behavior.

like image 105
Sam Varshavchik Avatar answered Sep 21 '22 15:09

Sam Varshavchik