有没有办法引用当前对象的类

时间:2019-04-07 22:07:45

标签: c++ multithreading inheritance

我正在创建一个类,该类的方法可以启动同一类中成员函数的一些线程。我对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虚拟化并在派生类中覆盖它,但是最好只编写一次并完成处理。有没有办法做到这一点,或者会导致同一件事?

3 个答案:

答案 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