【发布时间】:2017-03-12 01:58:38
【问题描述】:
谁能帮助解释这种意外行为?
前提
我创建了包含成员 std::thread 变量的类 Thread。 Thread 的 ctor 构造成员 std::thread,提供指向调用纯虚函数(由基类实现)的静态函数的指针。
守则
#include <iostream>
#include <thread>
#include <chrono>
namespace
{
class Thread
{
public:
Thread()
: mThread(ThreadStart, this)
{
std::cout << __PRETTY_FUNCTION__ << std::endl; // This line commented later in the question.
}
virtual ~Thread() { }
static void ThreadStart(void* pObj)
{
((Thread*)pObj)->Run();
}
void join()
{
mThread.join();
}
virtual void Run() = 0;
protected:
std::thread mThread;
};
class Verbose
{
public:
Verbose(int i) { std::cout << __PRETTY_FUNCTION__ << ": " << i << std::endl; }
~Verbose() { }
};
class A : public Thread
{
public:
A(int i)
: Thread()
, mV(i)
{ }
virtual ~A() { }
virtual void Run()
{
for (unsigned i = 0; i < 5; ++i)
{
std::cout << __PRETTY_FUNCTION__ << ": " << i << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
protected:
Verbose mV;
};
}
int main(int argc, char* argv[])
{
A a(42);
a.join();
return 0;
}
问题
您可能已经注意到,这里有一个微妙的错误:Thread::ThreadStart(...) 是从 Thread ctor 上下文调用的,因此调用纯/虚拟函数不会调用派生类的实现。运行时错误证实了这一点:
pure virtual method called
terminate called without an active exception
Aborted
但是,如果我在 Thread ctor 中删除对 std::cout 的调用,则会出现意外的运行时行为:
virtual void {anonymous}::A::Run(){anonymous}::Verbose::Verbose(int): : 042
virtual void {anonymous}::A::Run(): 1
virtual void {anonymous}::A::Run(): 2
virtual void {anonymous}::A::Run(): 3
virtual void {anonymous}::A::Run(): 4
即在Thread ctor 中删除对std::cout 的调用似乎具有能够从基类的构造函数上下文中调用派生类的纯/虚拟函数的效果!这与之前的学习和经验不符。
Windows 10 上的 Cygwin x64 构建环境。gcc 版本为:
g++ (GCC) 5.4.0
Copyright (C) 2015 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
我对这个观察感到困惑,并对发生的事情充满好奇。有人能解释一下吗?
【问题讨论】:
-
这里没有什么意外的。当对象仅构造为任何特定的基类 A 时,唯一可用的虚函数实现是那些从 A 可见的。
-
很遗憾我们没有额外的 post-ctor。在这里会很有用...
标签: c++ c++11 inheritance pure-virtual stdthread