P7 封装 socket 客户端

封装时 send 函数为啥使用 const string & buf 作为参数类型 bool send(const string &buffer) // buffer不要用const char * const string & buf 既可以接收 string 也可以接受 char *. 估计是对 char * 进行了隐式转换成了 string. send 函数的参数为啥是 buf.data() 和 buf.size(), 而不是 buf.c_str() 和 buf.length if ((::send(m_clientfd,buffer.data(),buffer.size(),0))<=0) return false; buf.data() 和 buf.c_str() 都指向的是内容的指针,但是语义不一样。 data 表示的就是原始数据,而 c_str 表示的是转化为 char *. buf.size() 的语义是原始内容的大小,而 length 表示的是字符串的长度。 所以都是因为语义不合适。虽然都能用,但是确实不合适。 recv 函数的参数为啥是 & buf[0] 而不是 buf.c_str() 或者 buf.data() int readn=::recv(m_clientfd,&buffer[0],buffer.size(),0); // 直接操作buffer的内存。 因为后面两种返回的都是带有 const, 只有 &buf[0] 才没有 const, 适合对内容进行修改。...

<span title='2023-09-19 18:05:00 +0800 CST'>2023-09-19</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;125 words&nbsp;·&nbsp;RamLife

c++ json 库 nlohmann 中类和 json 转换

需求 尝试使用 nlohmman 把复杂的类转为 json。 解决 复杂的类需要对其中的某些部分单独抽出来进行转换。 用于转换为 json 的类 struct VoltageSetConfigData { float w1; float p1; float w2; float p2; float ref; float pf; }; using VoltageGetConfigData = VoltageSetConfigData; class VoltageConfigJson { public: std::string name; std::vector<VoltageGetConfigData> data; }; 数组单个元素转换 void to_json(json& j, const VoltageGetConfigData& data) { j = json{{"w1", data.w1}, {"p1", data.p1}, {"w2", data.w2}, {"p2", data.p2}, {"ref", data.ref}, {"pf", data.pf}}; } void from_json(const json& j, VoltageGetConfigData& data) { j.at("w1").get_to(data.w1); j....

<span title='2023-06-26 18:45:00 +0800 CST'>2023-06-26</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;135 words&nbsp;·&nbsp;RamLife

c++ 17 inline 单例模式

需求 在写硬件驱动的时候,有些串口之类的硬件,适合独占访问,适合用单例模式去实现,那么 c++ 中如何实现单例呢? 解决 c++ 17 中拓展了 inline 变量,可以在类内部直接初始化静态变量,这样就方便实现单例模式。如果是需要在多线程情况下使用,那么还可以使用 std::once_flag, std::call_once() 之类的来确保只初始化一次,使用 once 之类的需要引入头文件 <mutex . /* * 多线程条件下只执行一次 * once_flag的生命周期。它必需要比使用它的线程的生命周期要长。所以通常定义成全局变量比較好。 */ static std::once_flag init_flag; // 单例模式 class singleton_pattern { private: inline static singleton_pattern* _instance_ptr{nullptr};// C++ 17 inline static 直接初始化 private: singleton_pattern() { cout << "constructor called" << endl; } singleton_pattern(singleton_pattern&) = delete; singleton_pattern& operator=(const singleton_pattern&) = delete; public: ~singleton_pattern() { cout << "destructor called" << endl; } static singleton_pattern* get_instance() { std::call_once(init_flag, []() { if (_instance_ptr == nullptr) _instance_ptr = new singleton_pattern; }); return _instance_ptr; } void print_addr() { cout << std::format("address: {} \n", (void*)_instance_ptr); } }; 参考 C++ 17 inline static 实现单例模式...

<span title='2023-05-19 10:30:00 +0800 CST'>2023-05-19</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;118 words&nbsp;·&nbsp;RamLife

c++ 类内初始化非常量静态成员

需求 在类内直接初始化非常量静态成员,编译时给了报错: error: ISO C++ forbids in-class initialization of non-const static member 解决 解决也非常简单,使用 C++17, 然后增加 inline 标识,就可以了。 class A { virtual void fun1(){}; int a; public: static inline int b=0; } 参考 C++:错误:ISO C++ forbids in-class initialization of non-const static member ‘A::b’

<span title='2023-05-19 10:30:00 +0800 CST'>2023-05-19</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;43 words&nbsp;·&nbsp;RamLife

成员变量是数组,通过初始化列表来初始化

需求 今天编译是报错: warning: list-initializer for non-class type must not be parenthesized, 报错的地方是对类中包含的成员变量是一个数组,然后使用了列表初始化。 解决 其实这个报错提示已经说的很清楚了,对非类使用了列表初始化并且加了括号。所以解决的方法也很简单,这种数组成员变量初始化使用列表初始化时,不要加括号就 ok 了。 class Sn74cbtlv3253 { //using FuncVoidVoid = void (*)(void); using FuncVoidBool = void (*)(bool); public: enum Index { kIndex1 = 0, kIndex2, kIndex3, kIndex4, }; public: Sn74cbtlv3253(FuncVoidBool s0, FuncVoidBool s1, FuncVoidBool oe) : s0_(s0), s1_(s1), oe_(oe) {}; void Switch(Index index); void Disconnect(); private: FuncVoidBool s0_; FuncVoidBool s1_; FuncVoidBool oe_; }; class Channel { public: enum ChannelIndex { kChannel1 = 0, kChannel2, kChannel3, kChannel4, kChannel5, kChannel6, kChannel7, kChannel8, kChannel9, kChannel10, kChannel11, kChannel12, }; public: Channel(); void Switch(ChannelIndex index); void Disconnect(); private: Sn74cbtlv3253 sn74cbtlv3253_[6][2]; }; Channel::Channel() : sn74cbtlv3253_{ {{Chip1S0PinControl, Chip1S1PinControl, Chip1En1PinControl}, {Chip1S0PinControl, Chip1S1PinControl, Chip1En2PinControl}}, {{Chip2S0PinControl, Chip2S1PinControl, Chip2En1PinControl}, {Chip2S0PinControl, Chip2S1PinControl, Chip2En2PinControl}}, {{Chip3S0PinControl, Chip3S1PinControl, Chip3En1PinControl}, {Chip3S0PinControl, Chip3S1PinControl, Chip3En2PinControl}}, {{Chip4S0PinControl, Chip4S1PinControl, Chip4En1PinControl}, {Chip4S0PinControl, Chip4S1PinControl, Chip4En2PinControl}}, {{Chip5S0PinControl, Chip5S1PinControl, Chip5En1PinControl}, {Chip5S0PinControl, Chip5S1PinControl, Chip5En2PinControl}}, {{Chip6S0PinControl, Chip6S1PinControl, Chip6En1PinControl}, {Chip6S0PinControl, Chip6S1PinControl, Chip6En2PinControl}}, } { Disconnect(); } 参考 list initializer for non class type must not be parenthesized werror...

<span title='2023-05-19 10:30:00 +0800 CST'>2023-05-19</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;155 words&nbsp;·&nbsp;RamLife

成员变量是类的对象,通过初始化列表来初始化

需求 类中包含的成员变量是另外一个类的对象,如何对这种成员变量进行初始化? 解决 这种类对象成员变量初始化可以使用初始化列表。 class Hc595 { using FuncVoidVoid = void (*)(void); using FuncVoidBool = void (*)(bool); public: Hc595(FuncVoidVoid sck, FuncVoidVoid rck, FuncVoidBool bit, FuncVoidBool oe, FuncVoidVoid bit_delay) : sck_(sck), rck_(rck), bit_(bit), oe_(oe), bit_delay_(bit_delay) {}; void ShiftByte(uint8_t b); void Store(); void Display(bool en); private: FuncVoidVoid sck_; FuncVoidVoid rck_; FuncVoidBool bit_; FuncVoidBool oe_; FuncVoidVoid bit_delay_; }; class Led { public: enum LedIndex { kLed1 = 0, kLed2, kLed3, kLed4, kLed5, kLed6, kLed7, kLed8, kLed9, kLed10, kLed11, kLed12, }; public: Led(); void Set(LedIndex index, bool g, bool r, bool b); void Refresh(); void ClearData(); private: static const uint8_t kDataLength = 12; static const uint8_t kBufLength = 5; std::array<uint8_t, kDataLength> data_ {}; std::array<uint8_t, kBufLength> buf_ {}; Hc595 hc_; }; Led::Led() : hc_({SckRiseEdge, RckRiseEdge, DataBitPinControl, nullptr, nullptr}) { //hc_ = {SckRiseEdge, RckRiseEdge, DataBitPinControl, nullptr, nullptr}; hc_....

<span title='2023-05-18 10:30:00 +0800 CST'>2023-05-18</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;138 words&nbsp;·&nbsp;RamLife

成员变量是引用,需要通过初始化列表来初始化

需求 类中包含的成员变量是引用,如何对这种引用成员变量进行初始化? 解决 这种引用成员变量初始化只能使用初始化列表。 class CommandProcess { public: CommandProcess(uint64_t& send_count); private: uint64_t& msg_send_count_; }; CommandProcess::CommandProcess(uint64_t& send_count) : msg_send_count_(send_count) { } 参考 C/C++ - 类中成员变量是引用

<span title='2023-05-10 14:51:00 +0800 CST'>2023-05-10</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;24 words&nbsp;·&nbsp;RamLife

c++ error: is an inaccessible base of

需求 今天编译报错 error: is an inaccessible base of 解决 这个问题解决也非常简单,主要是默认的继承实际上是 private, 所以不能直接访问父类的成员,只要在继承时,用 public 进行标识即可。 class A { public: virtual int add(int a, int b); }; class B : public A { int add(int a, int b) { return a + b; } }; 参考 ‘A’ is an inaccessible base of ‘B’解决方案 C++ is an inaccessible base of 问题的解决方法

<span title='2023-05-10 10:30:00 +0800 CST'>2023-05-10</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;58 words&nbsp;·&nbsp;RamLife

c++ 子类构造初始化和父类构造初始化

需求 子类构造时会调用父类构造函数,具体如何匹配? 解决 父类 子类 匹配 null null 编译器默认生成 父类和子类的构造函数 null 无参 或 带参 调用编译器生成的父类构造函数 无参 没有显式调用父类构造函数 隐式调用父类无参构造函数 带参 必须显式调用父类构造函数 显式调用,否则编译会报错 带参且都有默认值 不用显式调用父类构造函数 可以隐式调用父类有默认值的带参构造函数 无参或带参 只需要实现父类构造函数中的任何一个即可 没有显式调用的情况下,默认调用父类无参构造函数 参考 c++ 子类构造函数初始化及父类构造初始化 C++子类构造函数初始化及父类构造初始化

<span title='2023-05-10 10:30:00 +0800 CST'>2023-05-10</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;31 words&nbsp;·&nbsp;RamLife

子类调用父类被重写的虚函数

需求 今天需要在子类的虚函数中,调用父类被重写的同名方法,来完成部分工作。 解决 this->Command::ToString(cmd) 类似上面这样,可以通过 this 指针直接拿到父类的方法 Command::ToString . 编译器可以自动找到并调用父类的方法。 参考 C++——子类调用父类方法 c++父类虚函数被子类虚函数覆盖后,如何直接调用父类的虚函数? C++ | 子类对象调用父类函数

<span title='2023-04-19 18:20:00 +0800 CST'>2023-04-19</span>&nbsp;·&nbsp;1 min&nbsp;·&nbsp;16 words&nbsp;·&nbsp;RamLife