在派生类的构造函数中初始化超类
Posted
技术标签:
【中文标题】在派生类的构造函数中初始化超类【英文标题】:Initializing superclass in derived class's constructor 【发布时间】:2013-11-27 22:18:44 【问题描述】:MemRef 是一个简单的类,用于指向它不拥有的一些内存。
基类:
class MemRef
protected:
const char * _ptr;
std::size_t _len;
public:
// Constructors
MemRef() : _ptr(0), _len(0)
MemRef(const string& s) : _ptr(s.c_str()), _len(s.length())
MemRef(const char* b, size_t l) : _ptr(b), _len(l)
;
Loaded_MemRef 是一个子类,它提供自己的缓冲区,当不能信任调用者提供在 MemRef 的生命周期内保持分配和不变的内存时。 Loaded_MemRef 将数据复制到它控制的秘密缓冲区中,然后指向它,让我可以将其视为普通的 MemRef。
派生类:
class Loaded_MemRef : public MemRef
private:
const string _memory;
public:
Loaded_MemRef(const string& s) : ???
Loaded_MemRef(const char*);
Loaded_MemRef(const char*, const size_t);
;
我在为 Loaded_MemRef 创建 ctor 时遇到问题。在调用 MemRef 的 ctor 之前,我必须将调用者 首先 提供的内存复制到 _memory;否则 MemRef 无法检索到有效的 _memory.c_str()。但我的理解是,在初始化 Loaded_MemRef 的成员之前,必须先调用 MemRef(_memory)。所以我尝试了这个:
Loaded_MemRef(const string& str) :
MemRef(), // get this over with
_memory(str), // copy str into _memory
MemRef::_ptr(_memory.c_str()), // (LINE 108) "reach up into" MemRef and set its protected members
MemRef::_len(_memory.length())
这抱怨:
MemRef.cpp: In constructor 'Loaded_MemRef::Loaded_MemRef(const std::string&)':
MemRef.cpp:108: error: expected class-name before '(' token
MemRef.cpp:108: error: expected '' before '(' token
(上面指出了第 108 行;下一行,设置 _len,不会被标记,尽管编译器可能会被保释。)
这样做的正确方法是什么?
【问题讨论】:
为什么Loaded_MemRef
会有这么奇怪的构造函数?
@KerrekSB:一个用于字符串引用,一个用于空终止 c 字符串,一个用于缓冲区(无空终止,需要长度)。
【参考方案1】:
你真的不需要在初始化器中设置东西。您可以在构造函数的主体中执行此操作:
Loaded_MemRef(const string& str) :
MemRef(), // get this over with
_memory(str), // copy str into _memory
_ptr = _memory.c_str();
_len = _memory.length();
如果你的基类有const size_t _len
,就不可能实现你想要的,因为const
成员需要初始化器,而C++强制的初始化顺序与你需要的相反。
【讨论】:
你所说的 const _len 是否也适用于 const _ptr? 是的;但是您的_ptr
不是那种 那种const
(这不是问题) - 有问题的是const char *const _ptr
【参考方案2】:
您可以从Loaded_MemRef
构造函数的主体中更改_ptr
和_len
(因为它们是protected
)。
您可以给 MemRef
一个 (protected
?) 成员函数来更改它指向的位置,并从 Loaded_MemRef
构造函数的主体中使用它。
或者,如果您真的、真的想要/需要只初始化一次 MemRef
,您可以将 string
移至在基类之前初始化的一件事:另一个基类(声明为 virtual
或更早)。
仅使用 C++03:
struct Loaded_MemRef__Base
std::string _memory;
explicit Loaded_MemRef__Base(const std::string& str)
: _memory(str)
;
class Loaded_MemRef
: private Loaded_MemRef__Base,
public MemRef
public:
Loaded_MemRef(const string& str) :
Loaded_MemRef__Base( str ),
MemRef( _memory.data(), _memory.length() )
;
具有 C++11 特性:
struct Loaded_MemRef__Base
std::string _memory;
;
class Loaded_MemRef
: private Loaded_MemRef__Base,
public MemRef
public:
Loaded_MemRef(std::string str) :
Loaded_MemRef__Base std::move(str) ,
MemRef( _memory.data(), _memory.length() )
;
【讨论】:
使用 C++11 的 std::move() 的好例子。我不清楚是否需要您的大括号,或者是否可以同样使用括号? 需要大括号,因为 C++11 示例没有为struct
定义构造函数。括号表示“使用这些参数调用构造函数”;大括号表示“使用这些值初始化结构(或 std::initializer_list)的成员”。【参考方案3】:
您不能在派生类初始化列表中初始化超类的成员,即使它们是受保护的。解决方案是使用超类的构造函数。
【讨论】:
以上是关于在派生类的构造函数中初始化超类的主要内容,如果未能解决你的问题,请参考以下文章