0

I put up an simple example to illustrate my question. Here is the base class.

#include <mutex>
#include <atomic>

class Task
{
public:
    Task()
    {
        Empty.store(true);
    }
    std::mutex Access;
    std::atomic<bool> Empty;
    virtual void Work() = 0;
};

This is the derived class.

#include <stdlib.h>

class ExampleTask : public Task
{
public:
    void Work()
    {
        for(int i = 0; i < 16; ++i)
        {
            Data[i] = rand();
        }
    }
private:
    int Data[16];
};

As you can see, this example is about tasks or jobs which will be done asynchronously. Imagine, there is a queue of Tasks to do and a bunch of worker threads, maybe one for each CPU core on the target machine.

The task queue stores the tasks casted to their base class, so that the worker threads can just pick up the next job from the queue and call Work().

std::list<Task*> Queue;

ExampleTask *example = new ExampleTask();
Queue.push_back((Task*)example);

A worker thread would then fetch the first task, remove it from the queue, and work on it.

while(true)
{
    Task *current = Queue.front();
    Queue.erase(Queue.begin());
    current->Work();
}

Would this concept work? Can Data be accessed when current->Work() is called, even if I deal with a pointer to the base class?

danijar
  • 32,406
  • 45
  • 166
  • 297
  • 3
    Yes this works, welcome to polymorphism :) And you don't even need a cast in `Queue.push_back((Task*)example);`. These conversions are implicit. – jrok Aug 07 '13 at 11:38
  • @jrok Does this imply that I could take any class from a third party library, inherit from it and overwrite some functions, cast the instanced object back to the base class, and let the library use it without knowing? – danijar Aug 07 '13 at 11:39
  • 1
    That works as long as you are overwriting virtual methods. – Max Beikirch Aug 07 '13 at 11:40
  • 1
    If the base class is designed for that (has virtual functions that can be overriden), yes. That's the whole the point of [LSP](http://en.wikipedia.org/wiki/Liskov_substitution_principle). – jrok Aug 07 '13 at 11:40
  • But note that you do not need to cast back to anything. – juanchopanza Aug 07 '13 at 11:45
  • Okay, that's basically how interfaces in C++ work, right? :-) – danijar Aug 07 '13 at 11:47
  • 1
    @MaxBeikirch, _overriding_ not overwriting – Jonathan Wakely Aug 07 '13 at 12:06
  • Thanks to you all. @jrok Could you write a short answer so that I can accept it? Because you were the first providing an answer. – danijar Aug 07 '13 at 12:10
  • @jrok Alright, I'll do so, too. – danijar Aug 07 '13 at 12:16

1 Answers1

0

Yes: A reference/pointer to a base class can be implicitly converted to a pointer/reference to a derived class. This is exactly how CRTP and static polymorphism works:

template<typename T>
struct CRTP_base
{
    void execute()
    {
        static_cast<T*>(this)->f(); //The instance is casted to the known derived class, and we use the derived class function f.
    }
};

struct Foo : public CRTP_base<Foo>
{
    void f()
    {
        std::cout << "Wow, compile-time resolved polymorphism!" << std::endl;
    }
};

int main()
{
   Foo my_foo_instance;
   CRTP_base<Foo>& base_reference = my_foo_instance;
   base_reference.execute();
};

This prints:

Wow, compile-time resolved polymorphism!

Here is a running example.

Manu343726
  • 13,969
  • 4
  • 40
  • 75