如何使模板类的超类抽象?

JJB*_*JJB -2 c++ virtual templates abstract-class

我已经在头文件(Environment.h)中声明了以下类,并且我想使超类 FieldAccessor 抽象:

#include <jni.h>

class FieldAccessor {

    public:
        FieldAccessor(
            JNIEnv* env
        ) {
            this->jNIEnv = env;
        }

        virtual jobject getValue(jobject, jobject) = 0;

    protected:
        JNIEnv* jNIEnv;
};

template<typename Type>
class PrimitiveFieldAccessor : public FieldAccessor {
    public :
        PrimitiveFieldAccessor (
            JNIEnv* env, const char name[], const char ctorSig[],
            Type (JNIEnv::*getFieldValueFunction) (jobject, jfieldID)
        );

        jobject getValue(jobject, jobject);

    private:
        jclass type;
        jmethodID constructorId;
        Type (JNIEnv::*getFieldValueFunction) (jobject, jfieldID);
};
Run Code Online (Sandbox Code Playgroud)

但我得到以下编译错误:

#include <jni.h>

class FieldAccessor {

    public:
        FieldAccessor(
            JNIEnv* env
        ) {
            this->jNIEnv = env;
        }

        virtual jobject getValue(jobject, jobject) = 0;

    protected:
        JNIEnv* jNIEnv;
};

template<typename Type>
class PrimitiveFieldAccessor : public FieldAccessor {
    public :
        PrimitiveFieldAccessor (
            JNIEnv* env, const char name[], const char ctorSig[],
            Type (JNIEnv::*getFieldValueFunction) (jobject, jfieldID)
        );

        jobject getValue(jobject, jobject);

    private:
        jclass type;
        jmethodID constructorId;
        Type (JNIEnv::*getFieldValueFunction) (jobject, jfieldID);
};
Run Code Online (Sandbox Code Playgroud)

这是实现文件的一部分(DriverFunctionSupplierNative.cpp)

template<typename Type>
PrimitiveFieldAccessor<Type>::PrimitiveFieldAccessor (
    JNIEnv* env,
    const char name[],
    const char ctorSig[],
    Type (JNIEnv::*getFieldValueFunction) (jobject, jfieldID)
) : FieldAccessor(env) {
    this->jNIEnv = env;
    this->type = (jclass)jNIEnv->NewGlobalRef(env->FindClass(name));
    this->constructorId = jNIEnv->GetMethodID(this->type, "<init>", ctorSig);
    this->getFieldValueFunction = getFieldValueFunction;
}

template<typename Type>
jobject PrimitiveFieldAccessor<Type>::getValue(jobject target, jobject field) {
    jfieldID fieldId = jNIEnv->FromReflectedField(field);
    return jNIEnv->NewObject(
        this->type,
        this->constructorId,
        this->getFieldValueFunction(target, fieldId)
    );
}
Run Code Online (Sandbox Code Playgroud)

Gui*_*cot 6

编译错误很能描述问题。花时间阅读它们并了解它们的含义:

error: must use '.*' or '->*' to call pointer-to-member function in '...', e.g. ...
Run Code Online (Sandbox Code Playgroud)

现在看看如何尝试调用该函数:

this->callTypeMethodFunction(
    ...
)
Run Code Online (Sandbox Code Playgroud)

语法如下:

(jNIEnv->*callTypeMethodFunction)(value, this->callTypeMethodId);
Run Code Online (Sandbox Code Playgroud)

同样的事情也适用于指向成员函数调用的另一个指针:

return jNIEnv->NewObject(
    this->type,
    this->constructorId,
    (jNIEnv->*getFieldValueFunction)(target, fieldId)
);
Run Code Online (Sandbox Code Playgroud)

为什么只有在使用虚方法时才会出现编译错误?这是因为模板实例化的工作原理。您没有发布该类将如何实例化,但从症状来看,虚拟函数会提前实例化以构建 vtable,但其他方法(非虚拟)只会在使用时实例化。