You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将虚函数指针作为基类函数参数传递时的链接错误问题

C++纯虚函数与pthread_create链接错误

问题背景

首先定义了自定义类型:

typedef void* (*FUNCPTR)(void*);

接着创建基类P:

class P
{
  ...

  public:
    virtual void job() = 0; // 纯虚函数

    void start()
    {
      create((FUNCPTR) &P::job);
    }
  ...
};

(create函数的签名为void *(*__start_routine)(void *)。)

之后创建了派生类PD,并在其中实现了纯虚函数job()。

编译时出现如下错误:

/usr/bin/ld: /tmp/ccNwL4X6.o: in function P::start()': undefined reference to P::job()

有以下疑问:

  • 是否未正确实现虚函数?
  • 是不是链接时实际调用的是PD::job()而非P::job(),从而导致错误?

编辑1:最小可复现示例

#include <iostream>
#include <pthread.h>

using namespace std;

typedef void* (*THREADPTR)(void*);

class P
{
    protected:
        pthread_t thread;

    public:
        virtual void job() = 0;

        void start()
        {
            cout << "P::start()" << endl;
            pthread_create(&thread, NULL, (THREADPTR) &P::job, (void*) this);
        }
};

class PD: public P
{
    public:
        void job()
        {
            cout << "PD::job()" << endl;
        }
};

int main()
{
    P *pd;

    pd = new PD();
    pd->start();
}

编辑2:期望功能

仅需为每个继承抽象基类的类编写job()函数的逻辑。

编辑3:create()函数详情

此前create()函数被简化,实际它是pthread.h中定义的pthread_create:

extern int pthread_create (pthread_t *__restrict __newthread,
               const pthread_attr_t *__restrict __attr,
               void *(*__start_routine) (void *),
               void *__restrict __arg) __THROWNL __nonnull ((1, 3));

最小可复现示例已据此修改。

编辑4:重复问题解决方案不适用

被标记为重复的问题不符合需求,尝试其解决方案时出现解析错误:

virtual void P::job() 参数类型 "void (P::*)()" 与参数类型 "void *(*)(void *)" 不兼容 C/C++(167)

问题原因与解决方案

原因分析

  1. 非静态成员函数(包括虚函数)需要隐含的this指针作为第一个参数,和pthread_create要求的void*(*)(void*)函数签名完全不匹配,强制转换会导致未定义行为。
  2. 链接器报错找不到P::job(),是因为你直接取了纯虚函数的地址,链接器会尝试解析这个符号,但纯虚函数没有实现,因此抛出未定义引用错误。

解决方案

添加一个静态成员函数作为pthread_create的入口,在这个静态函数中调用对象的虚函数job(),修改后的代码如下:

#include <iostream>
#include <pthread.h>

using namespace std;

class P
{
protected:
    pthread_t thread;

public:
    virtual void job() = 0;

    void start()
    {
        cout << "P::start()" << endl;
        // 传递静态入口函数和当前对象指针
        pthread_create(&thread, NULL, &P::thread_entry, (void*)this);
    }

private:
    // 静态成员函数,匹配pthread_create的签名
    static void* thread_entry(void* arg)
    {
        P* obj = static_cast<P*>(arg);
        obj->job(); // 动态分派到派生类的job实现
        return nullptr;
    }
};

class PD : public P
{
public:
    void job()
    {
        cout << "PD::job()" << endl;
    }
};

int main()
{
    P* pd = new PD();
    pd->start();
    // 等待线程执行完成,避免main提前退出
    pthread_join(pd->thread, NULL);
    delete pd;
    return 0;
}

关键说明

  • 静态成员函数没有隐含的this指针,完美匹配pthread_create的函数签名,无需强制转换。
  • 通过pthread_create的第四个参数传递this指针,在静态函数中转换回基类指针后调用job(),会通过虚表自动调用派生类的实现,满足你只需编写派生类job()逻辑的需求。
  • 新增pthread_join是为了确保线程执行完毕后再退出程序,避免线程还未执行就被终止。

内容的提问来源于stack exchange,提问作者rober_dinero

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 18:48:24