子类中的虚拟函数调用父函数一次
Virtual function from child class calls parent function once
这个问题似乎与线程和运行程序的速度非常快有关。我有 2 个类,ThreadParent
个类和ThreadChild
类,一个从另一个继承。 ThreadParent
创建一个线程并运行函数func
,声明为静态以规避指针问题。但是,我确实希望继承的类(例如ThreadChild
)决定线程究竟做什么,func
调用虚拟函数Do
。
但是,当创建ThreadChild
对象并立即运行线程调用时,ThreadParent::Do
开始时调用一次,并且所有后续调用都将ThreadChild::Do
。有趣的是,当我在打电话之前等待Do
时,它不会发生。
有没有比等待更好的解决方案?更重要的是,为什么会发生这种情况?
这是一个小而完整的示例。它创建一个ThreadChild
对象,每 200 毫秒执行一次Do
。程序在 1 秒后结束(等待进入按)。
#include <iostream>
#include <windows.h>
#include <thread>
// The parent class
class ThreadParent {
protected:
bool _loopThread; //setting this to false should end the thread
std::thread _thread; //the thread
public:
// Basic constructor
ThreadParent(ThreadParent* child)
: _loopThread(true),
_thread(func, child, &_loopThread) {}
// Stops the thread and waits for it to finish
void StopThread() {
_loopThread = false;
_thread.join();
}
protected:
// The function the thread will be running (static because of pointer issues)
static void func(ThreadParent* child, bool* loopThread) {
//Sleep(10); //<- uncomment to solve the problem?
while (*loopThread) {
child->Do(); // Do is called every 200ms
Sleep(200);
}
}
// The function which is called repeatedly until _loopThread is set to false
virtual void Do() {
std::cout << "Parent calln";
}
};
// The child class
class ThreadChild : public ThreadParent {
public:
// Basic constructor
ThreadChild()
: ThreadParent(this) {}
protected:
// Redefines Do() with another message
void Do() {
std::cout << "Child calln";
}
};
// The program
int main() {
ThreadChild thread; // Create and run the thread
Sleep(1000); // Run the thread for 1s
thread.StopThread(); // End it
std::cout << "Press <enter> to terminate...";
std::cin.get(); // Wait for user to end program
return 0;
}
输出:
Parent call
Child call
Child call
Child call
Child call
Press <enter> to terminate...
在构造过程中,基类子对象是在派生类之前构造的。 在基类主体内部,动态类型实际上是基类的类型,因此动态函数调度(虚函数调用)将调用基类的相应函数。因此,根据时间的不同,您将看到正在调用的任一函数。
为了解决这个问题,只需在构造完成后调用的第二个初始化函数中显式启动线程。
顺便说一句:static
功能是一个红鲱鱼,你不会避免任何错误。此外,创建线程层次结构通常是一个坏主意。相反,类实例表示任务或作业,它们可能会也可能不会在单独的线程中执行。将这些对象紧密耦合到线程可能是一个坏主意。此外,将指针传递给基类构造函数的方式似乎很脆弱,因为它创建了一个本来就不应该存在的依赖项。
实例化派生类时,首先调用基类构造函数,并将 vtable 指针vptr
初始化为基类 vtable,该指针包含指向ThreadParent::Do
的指针。仅当派生类构造函数运行时,vtable 指针vptr
才会被覆盖(指向)派生类 vtable,该类包含指向 ThreadChild::Do
的指针。
构造函数调用虚拟方法将始终调用基类实现,而不是派生类重写的方法。
此常见问题解答更详细地解释了相同的内容
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 具有相同特征的两个对象是否只在内存中存储一次?无论定义它们的函数是什么,都是不同的
- 如何为非常量和常量重载实现一次成员函数?
- 某些 boost::asio 异步函数是否将处理程序连接到操作,以便处理程序被触发一次?
- 如何一次运行3个函数?
- 循环中本地对象的析构函数是否保证在下一次迭代之前被调用?
- 调用函数一次用于动态链接库,一次从可执行文件调用函数
- 仅在函数中设置静态变量一次
- 有没有办法一次运行 3 个创建窗口函数?
- 在可变函数调用中执行一次语句
- 为什么转换运算符调用复制构造函数两次,而等效函数只调用它一次
- 为什么一次包装 typedef 函数签名与原始签名不匹配
- (2 问题)"类"类型重新定义(即使 #pragma 一次),以及静态函数内的静态成员对象初始化?
- 我需要线程函数在不停止实际程序的情况下,每2秒打印一次随机数
- Android JNI RegisterNatives:对所有内容调用一次,或者每个函数调用一次
- 如何在 constexpr 构造函数中初始化矩阵一次?
- cppUnit:针对多个测试方法执行一次的设置函数
- 为什么调用 cout.operator<<(const char*) 打印地址而不是字符串? 如何创建一个函数本地静态"HashSet<char>"并初始化它一次?
- 跨类的多个实例调用函数一次
- C++一次将函数标记为静态就足够了?