Home > Back-end >  How to make abstract a superclass of a template class?
How to make abstract a superclass of a template class?

Time:09-17

I have declared the following classes in a header file (Environment.h) and I would like to make the superclass FieldAccessor abstract:

I have declared the following classes in a header file (Environment.h) and I would like to make the superclass FieldAccessor abstract:

#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);
};

... But I obtain the following compilation error:

F:/Shared/Workspaces/Projects/JNI/src/DriverFunctionSupplierNative.cpp: In instantiation of '_jobject* PrimitiveFieldAccessor<Type>::getValue(jobject, jobject) [with Type = long int; jobject = _jobject*]':
F:/Shared/Workspaces/Projects/JNI/src/Environment.h:73:11:   required from here
F:/Shared/Workspaces/Projects/JNI/src/DriverFunctionSupplierNative.cpp:80:2: error: must use '.*' or '->*' to call pointer-to-member function in '((PrimitiveFieldAccessor<long int>*)this)->PrimitiveFieldAccessor<long int>::getFieldValueFunction (...)', e.g. '(... ->* ((PrimitiveFieldAccessor<long int>*)this)->PrimitiveFieldAccessor<long int>::getFieldValueFunction) (...)'

... This is a piece of the implementation file (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)
    );
}

CodePudding user response:

The compilation error is quite descriptive of the problem, take the time to read them and learn what they mean:

error: must use '.*' or '->*' to call pointer-to-member function in '...', e.g. ...

Now look at how you try to call the function:

this->callTypeMethodFunction(
    ...
)

The syntax would be something like this:

(jNIEnv->*callTypeMethodFunction)(value, this->callTypeMethodId);

Same thing applies for other pointer to member function calls:

return jNIEnv->NewObject(
    this->type,
    this->constructorId,
    (jNIEnv->*getFieldValueFunction)(target, fieldId)
);

Now why is the compilation error only happen when you have the virtual method? This is because of how template instantiation works. You didn't posted how the class will be instantiated, but looking at the symptoms is that the virtual function get instantiated early to build the vtable, but other method (non-virtual) will only be instantiated on usage.

CodePudding user response:

Solved by replacing the code of the call to member function pointer this->getFieldValueFunction(target, fieldId) with (jNIEnv->*getFieldValueFunction)(target, fieldId)

  • Related