1

我目前正在为我的 beaglebone 做一个小项目。本质上,目标是创建一个框架,它提供了 c++ 的全部功能,而不是 beaglebone 的股票 javaScript 框架,但也像 arduino 框架一样易于开发人员使用。

我构建的其中一件事是针对不同类型的简单 GPIO 中断(如按钮、旋转编码器等)的预制类,因此开发人员只需定义一个按钮,并告诉它它连接的 beaglebone 上的哪个 GPIO 引脚。

现在我必须手动将中断对象的 pollInterupt() 函数添加到主循环中,以便程序可以反复检查中断 GPIO 引脚的状态。

问题来了:我想在按钮的类构造函数中添加代码,定义后会自动将自身传递给后台的中断处理程序,以重复运行新对象的 pollInterupt() 函数,因此开发人员永远不必这样做比定义按钮更复杂的事情。

不过,我似乎正在撞墙。试图让最终用户的框架变得简单,这意味着幕后的代码变得非常复杂。我能想到的自动处理定义的中断对象的最好方法是链接列表。这就是原型代码目前的样子。

#include <iostream>

class interuptButton;
class interuptHandler;

class interuptHandler{
    public:
        class node{
            public:
                node *next;
                node *prev;
            public:
                void *interupt;
        };

        node *first;
        node *last;
        node *current;
        node *temp;

public:
    interuptHandler(){
        first = new node;
        last  = new node;
        first -> prev = NULL;
        first -> next = last;
        last  -> prev = first;
        last  -> next = NULL;
    }
    void add(void *_interupt){
        temp = new node;

        current = last -> prev;
        current -> next = temp;
        temp    -> prev = current;
        temp    -> next = last;
        last    -> prev = temp;

        temp    -> interupt = _interupt;
    }
    void run(){
        current = first -> next;
        while(current -> next != NULL){
            std::cout << current -> interupt << std::endl;
//              std::cout << current -> interupt -> pin << std::endl;
//              current->interupt->pollInterupt();
//              std::cout << reinterpret_cast < interuptButton* > (current->interupt)->pin << std::endl;
            current = current -> next;
        }
    }
}handler;



class interuptButton{
public:
    int  pin;
    bool value;
public:
    interuptButton(int _pin){
        pin = _pin;
        handler.add(this);
    }
    void pollInterupt(){
        std::cout << "check pin " << pin << " to see if the GPIO has changed" << std::endl;
    }
};



int main(int argc, char **argv){

interuptButton buttonA(41);
interuptButton buttonB(45);
interuptButton buttonC(43);

handler.run();

return 0;
}

系统似乎正在工作,interuptButton 构造函数成功地将新创建的对象传递给 interuptHandler 的链接列表,然后它可以在 run() 函数中打印内存地址并输出:

bin/./test
0x7fff5fbff9e0
0x7fff5fbff9d0
0x7fff5fbff9c0

问题是当我取消注释 run() 中的任何其他行时,我尝试访问指针对象的变量或函数,g++ 开始抛出错误。

前两行返回:

src/main.cpp: In member function ‘void interuptHandler::run()’:
src/main.cpp:47: error: ‘void*’ is not a pointer-to-object type
make: *** [all] Error 1

第三行返回:

src/main.cpp:49: error: invalid use of incomplete type ‘struct interuptButton’
src/main.cpp:4: error: forward declaration of ‘struct interuptButton’
make: *** [all] Error 1

任何有关如何通过指针访问这些对象变量和函数的建议都将不胜感激。

更好的是,如果有人有更好的方法来自动将对象发送到幕后事件处理程序,我会全力以赴。

4

2 回答 2

0

您是否需要开始将函数定义移动到 .cpp 文件中?看起来您在定义 interuptbutton 之前正在访问其内部。

或者因为它只是 1 个大的 .cpp 文件,您可以在 main 之前定义该run函数来修复您的第二组错误。

第一个错误是不言自明的,也许您应该创建一个Interrupt 接口并保留指向它的指针,而不是 to void*? reinterpret_casting 只会让一切变得如此丑陋。

class IInterupt{
 // other stuff common to all interupt classes
    void pollInterupt() = 0; // pure virtual force all inheriting classes to implement.   
}

class interuptButton : public IInterupt{ //bla bla }

 class node{
        public:
            node *next;
            node *prev;
        public:
            IInterupt*interupt;
    };
于 2013-01-21T09:24:40.057 回答
0

node结构中,interrupt指针是一个指针,void这意味着它可以指向任何类型。但是,编译器不知道它指向什么,所以你必须通过类型转换告诉编译器它真正指向的类型:

reinterpret_cast<interuptButton*>(current->interrupt)->pollInterrupt();

至于另一个问题,你有一个循环依赖。班级interruptHandler取决于班级interruptButton,反之亦然。您必须通过分离一个或两个类的定义和实现来解决这个问题。最简单的方法是将interruptButton类定义放在定义之上interruptHandler,并将实现,即实际代码interruptButton放在interruptHandler类定义之后。


如果你想使用多个可中断的类,不仅仅是interruptButton类,你应该使用带有虚函数的继承和抽象基类。然后你就不需要void指针或类型转换:

struct baseIntertuptable
{
    virtual void pollInterrupt() = 0;
};

struct interruptHandler
{
private:
    struct node
    {
        // ...
        baseInterruptable* interrupt;
    };

public:
    void run()
    {
        // ...
        current->interrupt->pollInterrupt();
        // ...
    }
};

class interruptButton : public baseInterruptable
{
public:
    void pollInterrupt()
    {
        // ...
    }
};

这也应该解决您的类定义的循环依赖问题,因为抽象基类baseInterruptable现在在使用之前已完全定义,并且interruptHandler该类仅使用该类。

于 2013-01-21T09:27:09.737 回答