【问题标题】:How is the proper way to use class members in another class?如何在另一个类中使用类成员的正确方法?
【发布时间】:2019-02-04 12:13:14
【问题描述】:

我正在尝试使用来自不同类的类成员,将“class uart”添加到“class parser : public uart

但是我不能在解析器类中使用成员变量,例如(缓冲区大小、缓冲区或状态枚举值没有改变或更新)我可以使用这些变量的唯一方法是将它们用作外部变量,但我会喜欢以班级成员的方式来做。

请在下面找到我的代码:

主要:

#include <stdio.h>
#include "parser.h"
int main()
{
    parser m_parser;
    m_parser.test();
    return 0;
}

uart.h

#include <stdint.h>
#include <stdio.h>

//extern uint16_t buffer_size;
//extern char buffer[1024];

class uart
{
public:
    // Construction
    uart();

    //..... some functions
    void Initialize();

    //members
    enum STATE_enum
    {
        Buffering_message=0,
        Message_received,
        Buffering_empty
    };
    STATE_enum state;

    uint16_t buffer_size;
    char buffer[1024];
protected:
    //  static void UARTHandler(app_uart_evt_t * p_event);
    void Message();
    // Singleton instance
    static uart * m_instance;
};

uart.cpp

#include "uart.h"
//uint16_t buffer_size=0;
//char buffer[1024];

uart * uart::m_instance = 0; // Singleton instance

uart::uart()// Construction
{
    state = Buffering_empty;
    m_instance = this;
}

void uart::Initialize()
{
}
/*void UART::UARTHandler(app_uart_evt_t * p_event)
{
    Message();
}*/
void uart::Message()
{
    uint8_t value;
//  while ((app_uart_get(&value)) == NRF_SUCCESS) //specific function from my microcontroller stack for reading RX bytes
    {
        if(value == 0x0A ) // message end /r
            state = Message_received;
    }       
    switch (state)
    {
        case Message_received:
                printf("message:[%s] buffer_size:[%d]", buffer,buffer_size); //printf fine from there
        break;      
        case Buffering_message:
                buffer[buffer_size++] = value;              
        break;
        default:
        break;      
    }       
}

parser.h

#include <stdio.h>
#include <stdint.h>
#include "uart.h"

class parser : public uart
{
public: 
    parser();

    void test();
    static parser * m_instance; 

    static inline parser & Instance()// Singleton access
    {
        return *m_instance;
    }       
};

parser.cpp

#include "parser.h"

class parser * parser::m_instance = 0;

// Constructor
parser::parser()
{
    m_instance = this;
}

void parser::test()
{       
    printf("state %s", state); // sending AT command

//  memset(buffer, 0, buffer_size); 
//  buffer_size = 0;    
}

我应该将上面的作为公共类使用还是添加为朋友类,或者只是用作外部变量?

【问题讨论】:

  • 题外话:不要实现单例模式提供公共构造函数!更好的变体(由标准保证甚至是线程安全的):SC&amp; instance() { static SC sc; return sc; }
  • 您在哪里尝试使用这些成员?我在parser 中看不到任何代码。您收到什么错误消息?
  • 当你说“我不能在解析器类中使用成员变量”时,那是什么意思 exactly ?编译器是否无法摄取您的代码?编译成功后运行代码有没有报错? Fwiw,这不是一个正确的单例模式(如果有的话),但不知何故,我认为这与你真正遇到的任何问题无关。即使这个编译 buffer_size 是不确定的,所以 memset 调用是运行时错误的秘诀。
  • 因为parser 继承自uart,所以创建parser 对象最终会在两个单例中指向同一个实例,丢失之前可能创建的单独uart 单例对象!这是你想要的吗?
  • 很容易忽略%s 问题,因为您的示例不是最小的。看看minimal reproducible example。您应该删除与错误无关的所有部分。迭代步骤:删除部分代码,测试问题是否仍然存在,如果仍然存在,则继续,否则保留刚刚删除的代码部分。您可能会从整个类开始,完成后,剩下的类的功能,最后是功能块......在这个过程中,您很可能已经自己发现了问题(但很可能,在特定情况下不是......) .

标签: c++ class public


【解决方案1】:

最初的问题显然是使用了错误的格式说明符:

void parser::test()
{       
    printf("state %s", state);
    //            ^^
}

%s 仅用于 C 字符串(即以 null 结尾的 char 数组)。在这里,state 被解释为一个指针,但它指向无效的地址(未定义的行为),因此您的应用程序可能在它能够产生任何输出之前就崩溃了。

即使state 确实包含一个有效的地址,你仍然会遭受未定义的行为,因为%s需要char*类型的参数(为了避免UB,你需要强制转换) .

使用正确的格式说明符来解决问题:

printf("state %u", static_cast<unsigned int>(state));

您仍然需要强制转换以避免 UB,因为 %u 需要 unsigned int,但您的枚举不是(或者您可以使用 %d 并强制转换为 int)。

显然,您现在也尝试(因为没有发现实际错误)通过使用单例来解决您假设的问题 - 不幸的是,通过糟糕地实现该模式,您你的设计有缺陷。

如何修复?首先,丢弃单例。在特定情况下绝对不需要。然后三思而后行(以下已经是一个问题之前):解析器真的是 UART 吗?不考虑代码,但考虑概念,我明确地说“不”。所以你也不应该让parser 继承 uart。而是让它聚合一个:

class parser // : public uart
{
    uart m_uart;
public:
    // ...
    void test()
    {
        printf("%u", static_cast<unsigned int>(m_uart.state);
    }

};

或者,您可以通过指针或引用(对构造函数)在外部提供它并按原样存储它,但是您很快也会遇到生命周期管理,我建议您返回更高级的概念再多一点经验...

应该习惯,但是:封装。不要公开成员变量,除非您真的希望它们可以从任何地方更改。例如,buffer 是私有(甚至不受保护)的热门候选。

最后buffer_size:如果你打算用它来计算缓冲区中当前的值的数量,那很好。如果它代表可以存储的最大数据数,那么它是冗余的。无论您在哪里需要它,都可以通过sizeof(buffer)/sizeof(*buffer) 获取大小(除非数组已衰减为指针!)。除以第一个元素的大小是必要的,因为sizeof 总是以字节为单位提供大小,而不是元素的数量。

元素数量的大小是你通过std::array::size得到的;由于高级界面,您应该更喜欢 std::array 而不是原始数组!也许std::vector 甚至是更好的选择?

【讨论】:

  • dude 谢谢你的帮助,我绝对应该学习更多关于编程模式的知识,我只是使用单例,因为我正在处理的一些代码使用它。我是 C++ 世界的新手,所以我还没有足够的经验
猜你喜欢
  • 2023-02-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-03-11
  • 1970-01-01
  • 2013-05-11
  • 2017-07-24
  • 2011-06-17
相关资源
最近更新 更多