事件类
短信验证码事件相关类的基类,实现多态的接口。其中数据成员 sn_ 作为每个事件的标识。定义在函数内部的静态成员变量会进行 sn_ 的初始化,保证每个事件标识符的唯一性。
class iEvent
{
public:
iEvent(u32 eid, u32 sn);
virtual ~iEvent(); //派生类未不继承基类构造和析构函数,需要使用虚析构函数实现用基类指针删除派生类释放派生类中的空间
virtual std::ostream& dump(std::ostream& out) const { return out; };
virtual i32 ByteSize() { return 0; };
virtual bool SerializeToArray(char* buf, int len) { return true; };
//调用 iEvent::generateSeqNo() 生成一个唯一的序列号,可以为每个事件对象提供一个唯一的标识符。
//这对于事件跟踪和日志记录非常有用,可以帮助开发者在调试和分析系统时识别特定的事件实例。
u32 generateSeqNo(); // generateSegNo 将在初始值设定项列表中调用
u32 get_eid() const { return eid_; };
void set_eid(u32 eid) { eid_ = eid; };
u32 get_sn() const { return sn_; };
void set_args(void* args) { args_ = args; };
void* get_args() { return args_; };
private:
u32 eid_; // 事件 id
u32 sn_; // 每个事件的内部序列号
void* args_; // 参数
};
u32 iEvent::generateSeqNo() {
static u32 sn = 0; // 初始化一次
return sn++;
}
短信验证码请求与响应类
class MobileCodeReqEv : public iEvent //手机验证码请求
{
public:
MobileCodeReqEv(const std::string& mobile) :iEvent(EEVENTID_GET_MOBLIE_CODE_REQ, iEvent::generateSeqNo()) // 显式调用基类构造函数
{
msg_.set_mobile(mobile);
};
const std::string& get_mobile() { return msg_.mobile(); };
virtual std::ostream& dump(std::ostream& out) const; // 将对象信息输出到 std::ostream 流
virtual i32 ByteSize() { return msg_.ByteSize(); }; // 返回 msg_ 对象的字节大小
virtual bool SerializeToArray(char* buf, int len) { return msg_.SerializeToArray(buf, len); }; // 将 msg_ 对象序列化到一个字符数组中
private:
tutorial::mobile_request msg_; //用于存储和操作手机验证码请求的相关信息。
};
class MobileCodeRspEv : public iEvent //手机验证码响应
{
public:
MobileCodeRspEv(i32 code, i32 icode) :
iEvent(EEVENTID_GET_MOBLIE_CODE_RSP, iEvent::generateSeqNo()) {
printf("code: %d , icode:%d\n", code, icode);
const char* tmp = getReasonByErrorCode(code);
printf("tmp:%s\n", tmp);
msg_.set_code(code); // 响应代号
msg_.set_icode(icode); // 验证码
msg_.set_data(tmp);
}
const i32 get_code() { return msg_.code(); };
const i32 get_icode() { return msg_.icode(); };
const std::string& get_data() { return msg_.data(); };
virtual std::ostream& dump(std::ostream& out) const;
virtual i32 ByteSize() { return msg_.ByteSize(); };
virtual bool SerializeToArray(char* buf, int len) { return msg_.SerializeToArray(buf, len); };
private:
//std::string mobile_;
tutorial::mobile_response msg_;
};
输出封装
std::ostream& MobileCodeReqEv::dump(std::ostream& out) const
{
out << "MobileCodeReq sn=" << get_sn() << ",";
out << "mobile=" << msg_.mobile() << std::endl;
return out;
}
std::ostream& MobileCodeRspEv::dump(std::ostream& out) const
{
out << "MobileCodeReqEv sn =" << get_sn() << ",";
out << "code=" <<msg_.code() << std::endl;//出现问题,一旦调用,code_与icode就会变为随机值
out << "icode=" << msg_.icode() << std::endl;
out << "describle = " << msg_.data() << std::endl;
return out;
}
使用
iEvent *ie = new iEvent(EEVENTID_GET_MOBILE_CODE_REQ, 2);
MobileCodeReqEv me("18266666666");
me.dump(std::cout);
相关知识
C++流是指信息从外部输入设备(如键盘)向计算机内部(如内存)输入和从内存向外部输出设备(显示器)输出的过程。
C++标准库提供了4个全局流对象cin、cout、cerr、clog
使用cout
进行标准输出,即数据从内存流向控制台(显示器)。
使用cin
进行标准输入 , 即数据通过键盘输入到程序中,
cerr
进行标准错误的输出
clog
进行日志的输出
- cin为缓冲流。键盘输入的数据保存在缓冲区中,当要提取时,是从缓冲区中拿。如果一次输入过多,会留在那儿慢慢用,如果输入错了,必须在回车之前修改,如果回车键按下就无法挽回了。只有把输入缓冲区中的数据取完后,才要求输入新的数据。
- 输入的数据类型必须与要提取的数据类型一致,否则出错。出错只是在流的状态字state中对应位置位(置1),程序继续。
- 空格和回车都可以作为数据之间的分格符,所以多个数据可以在一行输入,也可以分行输入。但如果是字符型和字符串,则空格(ASCII码为32)无法用cin输入,字符串中也不能有空格。回车符也无法读入。
- cin和cout可以直接输入和输出内置类型数据,原因:标准库已经将所有内置类型的输入和输出全部重载了:
- 自定义类型如果要支持cin和cout的标准输入输出,需要对<<和>>进行重载。连续输入时,vs系列编译器下在输入ctrl+Z时结束。