我正在创建一个类,该类的方法可以启动同一类中成员函数的一些线程。我对c ++中的线程还是很陌生的,尤其是在涉及到类的时候,但这是我想出的。
class A
{
public:
void StartThreads()
{
std::thread fooThread(&A::FooFunc, this);
fooThread.join();
}
protected:
virtual void FooFunc()
{
while (true)
std::cout << "hello\n";
}
};
我的问题是,如果我可以获取当前对象的名称,因为现在如果我创建一个继承自A的类B并覆盖FooFunc,那么当我这样做时,将调用类A的FooFunc:
B b;
b.StartThreads();
所以我正在寻找一种将std::thread fooThread(&A::FooFunc, this)
替换为std::thread fooThread(&this->GetClass()::FooFunc, this)
之类的方法。我可以将StartThreads
虚拟化并在派生类中覆盖它,但是最好只编写一次并完成处理。有没有办法做到这一点,或者会导致同一件事?
答案 0 :(得分:0)
如果您的this
在编译时是已知的,则可以使用静态元编程进行救援。
C ++,Swift和Rust(现在也包括Scala)是静态语言,它们有很多编译时技巧来解决此类问题。
如何?在您的情况下,模板可以为您提供帮助。
此外,您不需要将其作为成员函数,而可以将其作为朋友函数(这样您就可以轻松使用模板)。
class A
{
public:
template<typename T>
friend void StartThreads(const T& obj);
protected:
virtual void FooFunc()
{
while (true)
std::cout << "hello\n";
}
};
template<typename T>
void StartThreads(const T& obj) {
std::thread fooThread(&T::FooFunc, obj);
fooThread.join();
}
警告: :只有在编译时(即
)知道该类的情况下,此仅有效class B: public A {
};
...
B b;
A &a = b;
StartThreads(a); // Will call it AS IF IT IS A, NOT B
另一种解决方案:
为了进行功能编程,可以使用lambda(如果您使用的是C ++ 11之前的C ++,则可以使用结构的函子)
C ++ 11:
void StartThreads()
{
std::thread fooThread([=](){ this->FooFunc(); });
fooThread.join();
}
C ++ 98:
// Forward declaration
class A;
// The functor class (the functor is an object that is callable (i.e. has the operator (), which is the call operator overloaded))
struct ThreadContainer {
private:
A &f;
public:
ThreadContainer(A &f): f(f) {}
void operator() ();
};
class A
{
public:
// To allow access of the protected FooFunc function
friend void ThreadContainer::operator() ();
void StartThreads()
{
// Create the functor
ThreadContainer a(*this);
// Start the thread with the "call" operator, the implementation of the constructor tries to "call" the operand, which here is a
std::thread fooThread(a);
fooThread.join();
}
protected:
virtual void FooFunc()
{
while (true)
std::cout << "hello\n";
}
};
class B: public A {
protected:
virtual void FooFunc() {
while(true)
std::cout << "overridden\n";
}
};
void ThreadContainer::operator() () {
f.FooFunc();
}
答案 1 :(得分:0)
您已经看过直接使用虚拟01 A
01 B
01 C
02 A
02 B
02 Y
24 U
,并且以某种方式推测它不起作用。 (我不会在这里解决这个问题的准确性,因为问题的注释中已经提到了这一点。)您不喜欢在过程的早期移动虚拟函数的想法。那么,为什么不以后再移动它呢?有一种使用非虚拟包装器来实现虚拟功能的通用范例。 (通常,包装程序是公共的,而虚拟功能是受保护的或私有的。)因此,类似:
FooFunc()
当然,如果直接调用虚拟class A
{
public:
void StartThreads()
{
std::thread fooThread(&A::FooFuncCaller, this); // <-- call the new function
fooThread.join();
}
protected:
void FooFuncCaller() // <-- new function layer
{
FooFunc();
}
virtual void FooFunc()
{
while (true)
std::cout << "hello\n";
}
};
可行,则最好使用它。不过,这比使用模板或自定义函子类要简单。 Lambda是一种合理的选择,其优点是不更改类的界面(头文件)。
答案 2 :(得分:0)
感谢您的所有回答,结果证明我的问题与我无关,并且我弄乱了班上其他一些成员。
感谢您的回答,这使我对使用不同方法可以完成相同操作的其他方式有所了解。 (https://stackoverflow.com/users/9335240/user9335240)