【问题标题】:How can I make a superclass of a template class abstract?如何使模板类的超类抽象?
【发布时间】:2021-11-04 08:44:07
【问题描述】:

我已在头文件 (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);
};

但我得到以下编译错误:

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) (...)'

这是一段实现文件(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)
    );
}

【问题讨论】:

  • 它不适用于六个字段和方法?你先试一试怎么样。重点是,创建minimal reproducible example 有助于理解问题,这也是需要它的原因。作为这里比较新的用户,也请收下tour阅读How to Ask
  • 所有 4 个声明为 virtual 的方法的错误都是相同的:如果我删除了 virtual 关键字和方法末尾的表达式 '= 0' 我没有编译错误,但是我修改它
  • 我减少了代码。而且错误很可能出在方法jobject PrimitiveFieldAccessor&lt;Type&gt;::getValue(jobject target, jobject field) 正是在这行代码中:this-&gt;getFieldValueFunction(target, fieldId) 但是我还没明白哪个是正确的代码
  • stackoverflow.com/search?q=error%3A+must+use+%27.*%27+or+%27-%3E*%27+to+call+pointer-to-member+function -- 只搜索错误。顺便说一句:它仍然不是minimal reproducible example
  • 您是否尝试将其复制并粘贴到文件中以重现该问题?您可能会发现它并不那么容易,因为它并不完整。例如,对 JNI 的依赖可能仍然是不必要的。

标签: c++ templates abstract-class virtual


【解决方案1】:

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

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

现在看看你是如何尝试调用函数的:

this->callTypeMethodFunction(
    ...
)

语法是这样的:

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

同样的事情也适用于其他指向成员函数调用的指针:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-11-18
    • 1970-01-01
    • 1970-01-01
    • 2018-12-28
    • 2014-11-02
    • 2010-11-18
    • 2015-06-17
    • 1970-01-01
    相关资源
    最近更新 更多