【问题标题】:C++ class inheritance with "get" method使用“get”方法的 C++ 类继承
【发布时间】:2015-05-10 01:12:57
【问题描述】:

我想创建一个主要包含静态成员/方法的基类,例如:

class LuaObject {
    public:
        static const luaL_Reg Methods[];

        static int Create(lua_State *L);

        static LuaObject* get(lua_State *L, int pos) {
            return *(LuaObject**)luaL_checkudata(L, pos, LuaObject::Metatable);
        }
};

然后从中派生出特定类型的对象:

class Pulse: public LuaObject {
    public:
        int n;
    //...
};

const luaL_Reg Pulse::Methods[] = {
    //...
};

static int Pulse::Create(lua_State *L) {
    Pulse **ud = (Pulse**)lua_newuserdata(L, sizeof(Pulse*));
    *ud = new Pulse();
    //...
}

但是,如果没有大量的复制和粘贴,我不知道该怎么做(违背了LuaObject 的目的)。出现两个问题:

  1. 我收到如下错误:error: ISO C++ does not permit ‘LuaObject::Methods’ to be defined as ‘Pulse::Methods’ [-fpermissive]error: no ‘int Pulse::Create(lua_State*)’ member function declared in class ‘Pulse’。也就是说,Pulse 似乎没有从 LuaObject 继承静态成员/方法。

  2. get(L, n) 方法旨在返回指向类实例的指针,例如我希望能够写:

    脉冲 *p = 脉冲::get(L,1);
    printf("p->n = %d\n", p->n);

    但是,似乎因为 get 只为 LuaObject 定义,所以我会得到 LuaObject*,而不是 Pulse*

如何解决这些问题,而不必将MethodsCreateget 等复制到Pulse(以及从LuaObject 派生的所有其他类)?
我认为将其转换为模板可能会有所帮助:

template <class T>
class LuaObject {
    public:
        static const luaL_Reg Methods[];

        static int Create(lua_State *L);

        static T* get(lua_State *L, int pos) {
            return *(T**)luaL_checkudata(L, pos, T::Metatable);
        }
};

class Pulse: public LuaObject<Pulse> {
    public:
        //...
};

但即使这样也给出了同样的错误,所以我很难过。

编辑:根据要求,一个最小的示例程序,包括编译错误:(使用g++ test.cpp -Llua -Lpulse -o test构建)

#include <stdio.h>
#include <stdlib.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
#include <pulse/pulseaudio.h>

class LuaObject {
    public:
        static const char *Metatable;
        static const luaL_Reg Methods[];

        static void InitModule(lua_State *L);
        static int Create(lua_State *L);

        //Retrieve object instance from Lua stack at specified position
        static LuaObject* get(lua_State *L, int pos) {
            return *(LuaObject**)luaL_checkudata(L, pos, LuaObject::Metatable);
        }
};


class Pulse: public LuaObject {
    //Here I want to avoid having to declare/define Metatable, get() etc again.
    public:
        static int getEvent(lua_State *L);
        pa_context *ctx;
};



const char *Pulse::Metatable = "pulse"; //error: ISO C++ does not permit ‘LuaObject::Metatable’ to be defined as ‘Pulse::Metatable’ [-fpermissive]
const luaL_Reg Pulse::Methods[] = { //error: ISO C++ does not permit ‘LuaObject::Methods’ to be defined as ‘Pulse::Methods’ [-fpermissive]
    {"getEvent", Pulse::getEvent},
    {NULL, NULL}
};


//Set up the "pulse" module in a Lua state
static void Pulse::InitModule(lua_State *L) { //error: no ‘void Pulse::InitModule(lua_State*)’ member function declared in class ‘Pulse’
    if(luaL_newmetatable(L, Pulse::Metatable)) {
        luaL_setfuncs(L, Pulse::Methods, 0);
    }
    lua_pop(L, 1); //remove metatable from Lua stack, leave in Lua registry

    static luaL_Reg lib[] = {
        {"new", Pulse::Create},
        {NULL, NULL}
    };
    luaL_newlibtable(L, lib);
    lua_setglobal(L, "pulse");
}

//Called from Lua (as pulse.new()) to create a Pulse object
static int Pulse::Create(lua_State *L) { //error: no ‘int Pulse::Create(lua_State*)’ member function declared in class ‘Pulse’
    Pulse **ud = (Pulse**)lua_newuserdata(L, sizeof(Pulse*));
    *ud = new Pulse();
    return 1;
}


//Called from Lua (as myPulse:getEvent()) to read events
int Pulse::getEvent(lua_State *L) {
    //We only have L as parameter; the Pulse object is on the Lua stack,
    //so we need to read it using luaL_checkudata() (which is handled
    //by get())
    Pulse *self = Pulse::get(L, 1); //error: invalid conversion from ‘LuaObject*’ to ‘Pulse*’ [-fpermissive]

    //pretend get_pulse_event() is defined in pulseaudio.h (the actual mechanism
    //is much more complex and wouldn't help the example)
    int event = get_pulse_event(self->ctx);
    lua_pushinteger(L, event);
    return 1;
}


int main(int argc, char **argv) {
    lua_State *L = luaL_newstate();
    luaL_openlibs(L);
    Pulse::InitModule(L);
    return luaL_dofile(L, "main.lua");
}

【问题讨论】:

  • 嗯...为什么首先需要一个包含所有静态方法的对象?也许那些静态方法应该只是独立的方法。有点像在标准库中使用容器和算法完成的。 get 方法是静态的,这看起来也很奇怪。它看起来更像是一个设计问题。话虽如此,这个问题,为什么你的尝试不起作用,无论如何都很有趣。
  • 这个想法是让继承的类,如Pulse,都具有相同的方法,而不必复制它们。我不知道该怎么做。需要get,因为Lua 只给出void*。 (我想我可以投射,但这有点难看)
  • 不,不,不。我不是在问继承。我在问为什么一切都是静态的。这令人困惑。 get 之类的东西应该与一个实例相关联,至少这是我的直觉。您还应该发布一个最小的违规示例。好像您在派生类中重新声明了一个静态成员并搞砸了更多事情。
  • get 不能绑定到实例,因为这是我们首先检索实例的方式。当 Lua 调用我们的方法时,它只传递一个lua_State*,我们必须从中检索实际参数(例如Pulse*)。

标签: c++ class inheritance static-methods static-members


【解决方案1】:

必须为 base 定义来自 base 的静态成员。如果要为派生类定义它们,则必须再次声明它们。这并不意味着您无法从派生中访问静态成员,尽管您必须注意不能声明静态成员 virtual

顺便说一句:static 只能在类定义中指定。

【讨论】:

    【解决方案2】:

    您正在尝试做的事情不会按照您的想法进行。

    class ClassWithoutStaticMembers {
    private:
        int myInt; 
    public:
       void someFunc();
    };
    
    void ClassWithoutStaticMembers::someFunc() {
        // Here we can access member variable myInt in two ways:
        myInt = 10; // directly
    
        this->myInt = 12; // Using the pointer (this) that belongs to the class.
    }
    
    // When you declare functions that have static storage space
    // They do not have the class's (this) pointer associated with them
    
    class ClassWithStaticMembers {
    public:
        static int x;
        void someFunc();
        static void someStaticFunc();
    };
    
    void ClassWithStaticMembers::someFunc() {
        x = 3; // valid
        this->x = 9; // valid because x does belong to this class but is of static storage type
    }
    
    void ClassWithStaticMembers::someStaticFunc() {
        this->(anything); // not valid this pointer is not associated with this static member function.
    } 
    
    // You can still inherit from the second class, but the static member
    // function is not defined in your derived classes. However you
    // can still access that function either through an object
    // or without referencing that object.
    
    class DerivedA : public ClassWithStaticMembers {
    public:
        void anotherFunc();
    };
    
    int main() {
        DerivedA a;
        a.someStaticFunc(); // this is valid;
        return 0;
    }
    
    int main() {
        // Here we do not declare a variable of type ClassWithStaticMembers 
        // or DerivedA but we can access ::someStaticFunc() from either since 
        // it is declared public in the base class
    
        ClassWithStaticMembers::someStaticFunc(); // We invoke this function call - valid.
        DerivedA::someStaticFunc(); // We Invoke this function again because
        // DerivedA inherits publicly from ClassWithStaticMembers.
        return 0;
    }
    
    // Now if we go back to the class definition of DerivedA and look at its member function anotherFunc();
    void DerivedA::anotherFunc() {
        // Here we can use DerivedA this pointer to access the static function
        // because it is a member of this class's base type
        this->someStaticFunc(); // This is valid and will invoke the static function call
    }
    

    【讨论】:

      猜你喜欢
      • 2013-09-06
      • 1970-01-01
      • 2021-04-03
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多