因为长时间没有写过继承相关的代码,竟然忘记子类需要给父类初始化成员,即调用父类的构造函数初始化继承过来的成员变量。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| MsgNode::MsgNode(char* msg, int max_len) : cur_len_(0) , total_len_(max_len + HEAD_LENGTH) { data_ = new char[total_len_ + 1](); memcpy(data_, &max_len, HEAD_LENGTH); memcpy(data_ + HEAD_LENGTH, msg, max_len); data_[total_len_] = '\0'; }
MsgNode::MsgNode(int max_len) : cur_len_(0) , total_len_(max_len) { data_ = new char[total_len_ + 1](); }
RecvNode::RecvNode(int max_len, int msgID) : MsgNode(max_len) , msgID_(msgID) {
}
SendNode::SendNode(const char* msg, short max_len, short msgID) : MsgNode(max_len + HEAD_LENGTH) , msgID_(msgID) {
}
|
子类对象包含父类部分,必须确保父类部分被正确初始化。否则,父类的数据成员可能会处于未定义状态,从而导致程序错误或不稳定。通过调用父类构造函数,可以重用父类中已有的初始化逻辑,避免在每个子类中重复编写相同的初始化代码。如果父类的构造函数有某些重要的初始化操作,这些操作需要在任何子类对象创建时都执行,以确保一致的行为。
- 父类构造函数无参:如果父类提供了一个无参构造函数,子类构造函数可以不显式调用它。编译器会自动调用它
- 父类构造函数有参数:如果父类构造函数需要参数,子类必须在其构造函数的初始化列表中显式调用父类的构造函数,并传递适当的参数