首页 文章

未解析的外部符号(构造函数)

提问于
浏览
1

在建设中,我收到以下错误:

main.obj:错误LNK2019:未解析的外部符号“”public:__ cdecl Worker :: Worker(void)“(?? 0Worker @@ QEAA @ XZ)”在函数“main”中 . main.obj:错误LNK2019:未解析的外部符号“”public:virtual __cdecl Worker :: ~Worker(void)“(?? 1Worker @@ UEAA @ XZ)”在函数“main”中 .

我找不到问题 . (我也看了here

main.cpp

#include <iostream>
#include <thread>
#include "worker.h"

using namespace std;

void pause_thread(int n)
{
    std::this_thread::sleep_for (std::chrono::seconds(n));
    std::cout << "pause of " << n << " seconds ended\n";
}

int main()
{
    std::cout << "Spawning and detaching 3 threads...\n";
    std::thread (pause_thread,1).detach();
    std::thread (pause_thread,2).detach();
    std::thread (pause_thread,3).detach();
    std::cout << "Done spawning threads.\n";

    std::cout << "(the main thread will now pause for 5 seconds)\n";
    // give the detached threads time to finish (but not guaranteed!):
    pause_thread(5);

    Worker w;



    return 0;
}

worker.h

#ifndef WORKER_H
#define WORKER_H


#include "jobqueue.h"
#include "job.h"
#include <mutex>
#include <thread>

using namespace std;

class Worker
{
private:
    JobQueue jobs;
    mutex mu;
    thread & workerThread;
    bool stop;

    void work();

public:
    Worker();
    virtual ~Worker();
    void addJob(Job*);
    int getJobCount();


};

#endif // WORKER_H

worker.cpp

#include "worker.h"

Worker::Worker(): workerThread(work), stop(false)
{
}

Worker::~Worker()
{
    workerThread.join();
}

void Worker::work(){
    while (!stop) {
        unique_lock<mutex> lock(mu, defer_lock);
        lock.lock();
            Job* job = jobs.getNextJob();
        lock.unlock();

        job->run();
        delete job;
    }
}

void Worker::addJob(Job* job){
    jobs.append(job);
}

int Worker::getJobCount(){
    unique_lock<mutex> lock(mu);
    return jobs.size();
}

project.pro

TEMPLATE = app
CONFIG += console
CONFIG -= app_bundle
CONFIG -= qt

SOURCES += main.cpp \
    jobqueue.cpp \
    worker.cpp

HEADERS += \
    jobqueue.h \
    worker.h \
    job.h

Deleting the Project.pro.user solves the (main-) problem, now errors are shown again

1 回答

  • 4

    您的代码中存在许多错误,因为我建议您在此之前应该了解更多C基础知识 .
    当我在评论中显示错误时,让我用成员函数回答你的问题:

    C将函数视为一等公民,而不是Java(Java 8改进修复了一些问题,但它并未将函数视为一等公民) .
    C将函数理解为 callable entity 的概念:可调用实体是可以被调用的任何东西,即被视为函数 . 所以可调用的实体可以是:

    • A global function :只是好老C功能 . 它可以被定义,实现和调用:
    void f() {}
    
    int main()
    {
        f(); //Call to f
    }
    
    • A member function :经典的OO成员函数 . 它在一个对象中调用,并对其数据进行操作:
    struct foo
    {
        void f();   
    };
    
    int main()
    {
        foo myfoo;
    
        myfoo.f(); //Call to foo::f
    }
    
    • A static member function :它是一个没有链接到对象的成员函数,它在类级别运行,所以 its signature is the same as the signature of a global function (记住这一点,重要的,我们稍后会看到)
    struct foo
    {
        static void f();
    {
    
    int main()
    {
        foo::f(); //Call to foo::f
    }
    
    • A functor :仿函数只是一个对象被设计为在函数中工作的类 . 这实现了重载()运算符:
    struct f
    {
        void operator()() const
        {}
    };
    
    int main()
    {
        f myf;
    
        myf(); //Call to foo
    }
    

    标准库定义了模板 std::function ,它是一种类型擦除函子,用于存放任何类型的可调用实体:

    #include <functional>
    
    void f() {}
    
    int main()
    {
        std::function<void()> f_wrapper;
    
        f_wrapper(); //Call to f_wrapper, which is an indirect call to f
    }
    
    • A lambda expression: lambda表达式只是一个inplace-defined匿名仿函数:
    int main()
    {
        std::function<void()> lambda = [](){ std::cout << "hello!"; };
    }
    

    你好!

    • A pointer to a function: C允许用户通过函数指针存储函数,就像它允许存储指向数据一样 . C具有相同的功能,也扩展了成员函数:
    void f() {}
    void g( void(*function)() ) 
    { 
        function(); //Call to the function referenced by the pointer passed as parameter 
    }
    
    int main()
    {
        g(f); //Call to g passing f as parameter. Its an indirect call to f. Note that the & is not needed
    }
    

    如上所述,静态成员函数与全局函数具有相同的签名,因此语法与上例中的完全相同 .
    但是对于成员函数是不一样的:成员函数链接到一个对象 so its called within an object . 成员函数指针的语法如下:

    struct foo
    {
        voif f();
    };
    
    typedef void(foo::* pointer_to_f_type)();
    
    int main()
    {
        pointer_to_f_pointer ptr = &foo::f; //Note that the & is needed, just like in variable pointers
        foo myfoo;
    
        (myfoo.*ptr)(); //Call to the foo member function pointed by ptr (foo::f) using myfoo as object
    }
    

    特定签名 has nothing to do with a pointer to a global/static function of the same signature, and cannot be convertible from/to member-pointer to non member pointer and vice-versa 的成员函数指针 .

    因为函数指针和成员函数指针是完全分离的东西,例如,我们不能创建一个包含函数指针和成员函数指针的数组 . 但是,标准库提供了函数模板 std::bind ,它允许我们将函数绑定到某些(或所有)调用参数 . 也就是说, std::bind() 返回的对象代表 a partial (or complete) call to a callable entity .
    例如:

    void f( int , int , int ) {}
    
     int main()
     {
         std::function<void(int,int,int)> f_wrapper = f;
    
         f(1,2,3); //Ok
         f_wrapper(1,2,3); //Ok
    
         std::function<void()> f_call = std::bind( f , 1 , 2 , 3 ); //f_call represents a partial call (Complete in this case) fo f
         f_call(); //Execute the call
    
         std::function<void(int)> partial_f_call = std::bind( f , std::placeholders::_1 , 2 , 3 );
         partial_f_call( 1 ); //Same execution as above
     }
    

    如您所见, std::bind() 允许我们将某些参数绑定到函数,从而形成一个可调用的实体,该实体表示对函数的调用 . 那么 it could be used to bind an object to a member function, making a callable entity with exactly the same form of a std::function instance initialized with any other kind of callable entity. 那就是我们可以用 std::function 以相同的方式存储成员函数和非成员函数,并以相同的方式使用它**:

    void f();
    
     struct foo
     {
         void f();
     };
    
     int main()
     {
         std::vector<std::function<void()>> functions;
         foo myfoo;
    
         functions.push_back( f );
         functions.push_back( std::bind( &foo::f , myfoo ) );
         functions.push_back( [](){} );
         ...
    
         for( const auto& function : functions )
             function();
     }
    

    如您所见,有许多形式的可调用实体 . 一个重点是有人可以使用C模板并依赖duck typing来使用作为参数传递的可调用实体:

    template<typename F>
     void call_function( const F& function )
     {
         function(); //function should be any kind of thing which could be called, that is, a callable entity
     }
    

    That's exactly what the std::thread constructor does . 它只需要任何类型的可调用实体,一组调用参数,启动一个新线程,然后在该新线程上调用可调用实体(通过 join()detach() . 它的实现可能类似于:

    template<typename F , typename... ARGS>
    thread::thread( F&& function , ARGS&&... args )
    {
        _thread = create_thread();
    
        _function = std::bind( std::forward<F>( function ) , std::forward<ARGS>( args )... ); 
    }
    
    
    void thread::detach()
    {
        detach_thread( _thread );
        _function();
    }
    
    void thread::join()
    {
        join_thread( _thread );
        _function();
    }
    

    当然这不是一个有效的实现,只是一个概述:p

    所以现在你可以理解为什么你的方法不起作用,以及你可以做些什么来解决这个问题 . 具体来说, use std::bind() to create a callable entity if you want to use a member function on the thread .

相关问题