我最近完成了一个程序,我希望它能像我预期的那样工作,事实证明它确实如此!情况如下:
我有一个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线程中,它为您提供了从子类中执行此操作的方法。 如何从基类中调用原始基类方法,对象的实际结构在内存中是什么样的?
我理解这可能需要回答很多,所以如果您可以提供第一段中的问题知识,并在第二段中提出一些问题,我认为这是最合适的。
谢谢!
答案 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::handle
是virtual
吗?