指向被覆盖方法的 C++ 方法指针

Posted

技术标签:

【中文标题】指向被覆盖方法的 C++ 方法指针【英文标题】:C++ method pointer to overriden method 【发布时间】:2014-02-06 08:07:56 【问题描述】:

我最近完成了一个程序,我希望它能够按我预期的方式运行,而事实证明,它确实做到了!情况如下:

我有一个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 线程中,它为您提供了一种从子类中执行此操作的方法。 如何从基类调用原始基类方法,对象的实际结构在内存中是什么样的?

我知道这可能有很多要回答的问题,所以如果您可以提供您对第一段中问题的知识并建议阅读第二段中的问题,我认为这将是最合适的。

谢谢!

【问题讨论】:

【参考方案1】:

当我以我所做的方式覆盖一个方法时,它会替换内存中的基类方法吗?

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

到底有没有调用原基类doWork方法?

是的,你可以非虚拟地调用它:

Handler::doWork();

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

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

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

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

【讨论】:

您说调用Handler::doWork(); 是非虚拟的,但在我的代码中handlerThread = new std::thread(&amp;Handler::doWork, this, socket); 调用派生的doWork()。这两个调用不是同一个东西,只是使用指向成员函数的指针吗? @MattVaughan:不,正如我的回答所描述的,当您使用指向成员函数的指针时,您会获得虚拟调度。 好的,谢谢。我认为 Handle:: 前缀让我感到困惑,但听起来即使你将它与指向成员函数的指针一起使用,如果它是一个虚函数,尽管有前缀,它也会使用最派生的。【参考方案2】:

当你这样做时

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

您要求以虚拟方式致电this-&gt;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 吗?

【讨论】:

它调用子类而不是基类的方式是我想要的。但我想不出一种方法来调用基类。我将它作为虚拟的,以便其他类可以定义线程行为。

以上是关于指向被覆盖方法的 C++ 方法指针的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的对象会在 C++ 中被覆盖?

为啥基类指针指向基类中的纯虚方法,而不是派生类中的覆盖方法?

virtual虚函数

C++ - 如何使用基指针覆盖子类方法

C++ 中的堆栈损坏

深入理解C++ 虚函数表