Может ли кто-нибудь объяснить это неожиданное поведение?Неожиданно можно вызвать виртуальную функцию производного класса из базового класса ctor
предпосылка
Я создал класс тему, которая содержит член std::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
Однако, есть неожиданное поведение во время выполнения, если удалить вызов std::cout
в Thread
CTOR:
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
И.Э. удаление вызова в std::cout
в Thread
ctor, по-видимому, вызвано тем, что он может вызвать конструктор «чистый/виртуальный» производного класса из контекста конструктора базового класса! Это не соответствует предыдущему обучению и опыту.
среды сборки в Cygwin x64 на Windows, 10. 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. – EJP
Жаль, что у нас нет post-ctor. Было бы так полезно здесь ... – Deduplicator