C++设计多层通信软件体系结构
众所周知,每个通信通道都有不同的最大数据长度功能。 例如,USB HID中的最大数据长度为64字节,对于UART modbus通道为256字节。 然而,作为一个用户,我不想关心这些限制。我的通信应该能够根据通道的最大数据长度将大数据包拆分为多个小数据包。实际的拆分例程是相同的,只是每个数据包的数据长度不同 这就是我编写通用通信API的动机 让我们从更高的层次开始: 其思想是,您可以为每个通道初始化API实例。i、 eC++设计多层通信软件体系结构,c++,inheritance,C++,Inheritance,众所周知,每个通信通道都有不同的最大数据长度功能。 例如,USB HID中的最大数据长度为64字节,对于UART modbus通道为256字节。 然而,作为一个用户,我不想关心这些限制。我的通信应该能够根据通道的最大数据长度将大数据包拆分为多个小数据包。实际的拆分例程是相同的,只是每个数据包的数据长度不同 这就是我编写通用通信API的动机 让我们从更高的层次开始: 其思想是,您可以为每个通道初始化API实例。i、 e CSlave_Com_API<64> usb_slave_com;
CSlave_Com_API<64> usb_slave_com;
CSlave_Com_API<256> modbus_slave_com;
现在,每个频道的LL都明显不同。
问题是,我有两个不同的任务:
高级任务由用户请求触发,实际的硬件通信在单独的任务中运行,以确保仅在硬件实际准备好发送数据时才发送数据
示例LL类可能如下所示:
class CSlave_Com_LL_Slave_Com
{
public:
/**
*Constructor
* @param mid_level_reference reference to the used midlevel class instance. This instance is needed to correctly
* pass the received data to the higher levels and to get the next data to be send
*/
CSlave_Com_LL_Slave_Com(const CSlave_Com_Mid_level<message_length>& mid_level_reference);
///Destruktor
~CSlave_Com_LL_Slave_Com();
private:
///Midlevel Reference
const CSlave_Com_Mid_level<message_length>& mid_level_instance;
};
问题是:我的LL类需要访问某个API实例的中级基础。然而,这个基地受到保护。
显然,我可以公开中间层基础,但这意味着用户可以意外地访问中间层。我不想那样
你对如何解决我的问题有什么建议吗
谢谢您的帮助:更新:对不起,我想我想不明白您的意思,这是解决方案,我想您要求的是:
#include <string>
#include <iostream>
template<size_t user_data_length>
class CSlave_Com_Mid_level
{
public:
///This is the structure of a single packet with is sent or received
struct Single_Packet_T
{
//some header Info...
uint8_t data[user_data_length]; ///< the actual user data
};
/**
* Called be the LL Driver when new data was received
* @param rx_packet Received data
* @return true when the received data could be processed
*/
bool Process_received_Packet(const Single_Packet_T& rx_packet) const {
std::cout << "Test\n";
return false;
}
/**
* Called by the LL driver. Stores new data to sent in tx_packet
* @param tx_packet Storage buffer for the new TX Data
* @return true when the buffer was filled correctly
*/
bool Get_Next_Packet_To_Send(Single_Packet_T& tx_packet);
};
template<size_t user_data_length>
class CSlave_Com_API;
template <size_t message_length>
class CSlave_Com_LL_Slave_Com
{
public:
/**
*Constructor
* @param mid_level_reference reference to the used midlevel class instance. This instance is needed to correctly
* pass the received data to the higher levels and to get the next data to be send
*/
CSlave_Com_LL_Slave_Com(const CSlave_Com_API<message_length>& mid_level_reference)
: mid_level_instance(mid_level_reference) {
typename CSlave_Com_Mid_level<message_length>::Single_Packet_T packet{};
this->mid_level_instance.Process_received_Packet(packet);
}
///Destruktor
~CSlave_Com_LL_Slave_Com() = default;
private:
///Midlevel Reference
const CSlave_Com_Mid_level<message_length>& mid_level_instance;
};
template<size_t user_data_length>
class CSlave_Com_API: protected CSlave_Com_Mid_level<user_data_length> {
friend class CSlave_Com_LL_Slave_Com<user_data_length>;
};
int main()
{
CSlave_Com_API<42UL> foo{};
CSlave_Com_LL_Slave_Com<42UL> bar{foo};
}
让LL类成为朋友有帮助吗?我不太清楚需要访问的确切位置,但要么使用受保护的而不是私有的,要么按照Serge的建议,让它成为朋友。我修改了我的第一个,使访问更清晰。这是朋友选项的一个好点。我没有想到这一点。谢谢!
#include <string>
#include <iostream>
template<size_t user_data_length>
class CSlave_Com_Mid_level
{
public:
///This is the structure of a single packet with is sent or received
struct Single_Packet_T
{
//some header Info...
uint8_t data[user_data_length]; ///< the actual user data
};
/**
* Called be the LL Driver when new data was received
* @param rx_packet Received data
* @return true when the received data could be processed
*/
bool Process_received_Packet(const Single_Packet_T& rx_packet) const {
std::cout << "Test\n";
return false;
}
/**
* Called by the LL driver. Stores new data to sent in tx_packet
* @param tx_packet Storage buffer for the new TX Data
* @return true when the buffer was filled correctly
*/
bool Get_Next_Packet_To_Send(Single_Packet_T& tx_packet);
};
template<size_t user_data_length>
class CSlave_Com_API;
template <size_t message_length>
class CSlave_Com_LL_Slave_Com
{
public:
/**
*Constructor
* @param mid_level_reference reference to the used midlevel class instance. This instance is needed to correctly
* pass the received data to the higher levels and to get the next data to be send
*/
CSlave_Com_LL_Slave_Com(const CSlave_Com_API<message_length>& mid_level_reference)
: mid_level_instance(mid_level_reference) {
typename CSlave_Com_Mid_level<message_length>::Single_Packet_T packet{};
this->mid_level_instance.Process_received_Packet(packet);
}
///Destruktor
~CSlave_Com_LL_Slave_Com() = default;
private:
///Midlevel Reference
const CSlave_Com_Mid_level<message_length>& mid_level_instance;
};
template<size_t user_data_length>
class CSlave_Com_API: protected CSlave_Com_Mid_level<user_data_length> {
friend class CSlave_Com_LL_Slave_Com<user_data_length>;
};
int main()
{
CSlave_Com_API<42UL> foo{};
CSlave_Com_LL_Slave_Com<42UL> bar{foo};
}