C ++方法指向重写方法

时间:2014-02-06 08:07:56

标签: c++ multithreading polymorphism function-pointers member-function-pointers

我最近完成了一个程序,我希望它能像我预期的那样工作,事实证明它确实如此!情况如下:

我有一个Handler类,它是基类:

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);
};

我有一个PrintHandler,它是Handler的子类:

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

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

以下是基类Handler和子类PrintHandler中doWork的定义:

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;
}

当我创建指向PrintHandler的指针并将其转换为指向Handler的指针并通过方法指针调用该对象上的handle方法时:

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

doWork作为覆盖基类方法的子类方法执行。 当我以我的方式覆盖方法时,它是否替换了内存中的基类方法?反正有没有调用原来的基类doWork方法?用方法指针调用它会改变调用哪个方法吗?

this线程中,它为您提供了从子类中执行此操作的方法。 如何从基类中调用原始基类方法,对象的实际结构在内存中是什么样的?

我理解这可能需要回答很多,所以如果您可以提供第一段中的问题知识,并在第二段中提出一些问题,我认为这是最合适的。

谢谢!

2 个答案:

答案 0 :(得分:2)

  

当我以我的方式覆盖方法时,它是否替换了内存中的基类方法?

不,两种功能仍然存在。覆盖会影响在特定对象上调用时选择的版本;对于该类型的对象,或者不覆盖它的其他派生类,仍然需要基本版本。

  

无论如何都要调用原来的基类doWork方法吗?

是的,您可以非虚拟地称呼它:

Handler::doWork();
  

用方法指针调用它会改变调用哪个方法吗?

不,无论是直接调用函数还是通过指向成员函数的指针,虚拟调度都会选择相同的覆盖。它只取决于它被调用的对象的动态类型。

  

对象的实际结构在内存中是什么样的?

这取决于实施。通常,对象包含指向某些特定于类的元数据的指针(称为 vptr 虚拟指针),其中包含指向虚函数的指针表(称为一个 vtable )。当您(虚拟地)调用虚函数时,它会查找该表以查找要调用的函数。指向虚函数的指针将指定要使用的表条目,而不是要调用的函数,以便虚拟分派仍然适用于覆盖该函数的任何类型。

答案 1 :(得分:1)

当你做

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

您要求虚拟致电this->doWork(socket)

您可以创建一个其他方法,它几乎不会调用您的虚方法。为:

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

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

注意:您真的需要Handler::handlevirtual吗?