2

I recently finished a bit of a program that I was hoping would work the way I expected it to, and as it turns out, it did! Here is the situation:

I have a Handler class which is the base class:

class Handler
{
public:
    Handler();
    virtual ~Handler();
    virtual void handle(SOCKET socket);

protected:
    virtual void doWork(SOCKET socket);


private:
    std::thread * handlerThread;
    static void processData(SOCKET socket);
};

I have a PrintHandler which is a subclass of Handler:

class PrintHandler : public Handler
{
public:
    PrintHandler();
    ~PrintHandler();

protected:
    virtual void doWork(SOCKET socket);
};

Here are the definitions of doWork in the base class Handler and the subclass PrintHandler:

void Handler::doWork(SOCKET socket)
{
    std::cerr << "If you see this, you didn't override the doWork function" << std::endl;
}

void PrintHandler::doWork(SOCKET socket)
{
    std::cerr << "This is in the base class" << std::endl;
}

When I create a pointer to a PrintHandler and cast it to a pointer to a Handler and call the handle method on that object via method pointer:

void Handler::handle(SOCKET socket)
{
    handlerThread = new std::thread(&Handler::doWork, this, socket);
}

the doWorkexecutes as the subclass method that overrode the base class method. When I override a method in the manner that I did, does it replace the base class method in memory? Is there anyway to call the original base class doWork method? Does calling it with a method pointer change which method gets called?

In this thread it gives you a means to do it from the sub class. How would I call the original base class method from the base class and what does the actual structure of the object look like in memory?

I understand this is probably a lot to answer, so if you could maybe provide your knowledge on the questions in the first paragraph and suggest some reading for the questions in the second, I think that would be most appropriate.

Thank you!

Community
  • 1
  • 1
Matt Vaughan
  • 1,135
  • 2
  • 13
  • 19

2 Answers2

2

When I override a method in the manner that I did, does it replace the base class method in memory?

No, both functions still exist. Overriding affects which version is chosen when called on a particular object; the base version is still needed for objects of that type, or other derived classes that don't override it.

Is there anyway to call the original base class doWork method?

Yes, you can call it non-virtually:

Handler::doWork();

Does calling it with a method pointer change which method gets called?

No, virtual dispatch chooses the same override whether you call the function directly, or via a pointer-to-member-funcion. It only depends on the dynamic type of the object it's called on.

what does the actual structure of the object look like in memory?

That's up to the implementation. Typically, the object contains a pointer (known as a vptr or virtual pointer) to some class-specific metadata, which contains a table of pointers to the virtual functions (known as a vtable). When you (virtually) call a virtual function, it looks in that table to find which function to call. A pointer to a virtual function will specify which table entry to use, rather than which function to call, so that virtual dispatch still works on any type that overrides that function.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • You say calling `Handler::doWork();` is non virtual, but in my code `handlerThread = new std::thread(&Handler::doWork, this, socket);` calls the derived `doWork()`. Aren't those two calls the same thing, but on just uses a pointer to a member function instead? – Matt Vaughan Feb 06 '14 at 20:46
  • 1
    @MattVaughan: No, you get virtual dispatch when you use a pointer-to-member-function, as my answer describes. – Mike Seymour Feb 07 '14 at 02:19
  • Alright thank you. I think the Handle:: prefix is what's got me confused, but it sounds like even if you use that with a pointer-to-member-function it will use the most derived if it is a virtual function despite the prefix. – Matt Vaughan Feb 07 '14 at 02:43
1

when you do

std::thread(&Handler::doWork, this, socket);

You ask to call this->doWork(socket) virtually.

You may create an other method which call not virtually your virtual method. as:

void Handler::callHandlerDoWork(SOCKET socket)
{
    Handler::doWork(socket); /* no virtual call */
}

void Handler::handle(SOCKET socket)
{
    handlerThread = new std::thread(&Handler::callHandlerDoWork, this, socket);
}

Note: Do you really need that Handler::handle is virtual ?

Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • The way it calls the sub class instead of the base class is what I wanted. But I couldn't think of a way to just call the base class. I have it as virtual so that other classes can define thread behavior. – Matt Vaughan Feb 06 '14 at 17:42