Reputation: 3839
MemRef is a simple class to point to some memory it doesn't own.
Base class:
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 is a subclass that supplies its own buffer, when the caller can't be trusted to supply memory that remains allocated and unchanged for the lifetime of the MemRef. Loaded_MemRef copies the data into a secret buffer it controls, and then points to it, allowing me to treat it like a plain MemRef.
Derived class:
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);
};
I'm having trouble creating the ctors for Loaded_MemRef. I must copy into _memory the memory the caller provided first, before calling MemRef's ctor; otherwise MemRef can't retrieve a valid _memory.c_str(). But my understanding is that the call to MemRef(_memory) must come first, before I initialize Loaded_MemRef's members. So I tried this:
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())
{}
This complains:
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
(Line 108 is indicated above; the next line, setting _len, doesn't get flagged, although perhaps the compiler bailed.)
What is the right way to do this?
Upvotes: 1
Views: 341
Reputation: 72483
You could just change _ptr
and _len
from the body of the Loaded_MemRef
constructor (since they're protected
).
You could give MemRef
a (protected
?) member function for changing where it points, and use that from the body of the Loaded_MemRef
constructor.
Or if you really, really want/need to initialize the MemRef
just once, you can move that string
to the one thing that does get initialized before a base class: another base class (declared either virtual
or earlier).
Using only 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() )
{}
};
With C++11 features:
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() )
{}
};
Upvotes: 2
Reputation: 28320
You don't really need to set stuff in the initializers. You can do it in the body of the constructor:
Loaded_MemRef(const string& str) :
MemRef(), // get this over with
_memory(str), // copy str into _memory
{
_ptr = _memory.c_str();
_len = _memory.length();
}
If your base class had const size_t _len
, it would be impossible to implement what you want, because const
members require initializers, and initialization order mandated by C++ is opposite to what you need.
Upvotes: 2
Reputation: 339
You can't initialize the members of the superclass in the derived class initialization list, even if they are protected. The solution is to use a constructor of the superclass.
Upvotes: 1