Okay, maybe my C++ is getting rusty, but I’m stammering at coming up with a reasonable solution to this problem:
Imagine a class, like this one:
class Foo {
public:
Foo(string &name) : name_(name.c_str()) { }
private:
char *name_;
}
As you can see, it takes the guts of the string argument passed to the constructor, and stores them internally. In other words, it assumes that the caller is going to manage the lifetime of the string argument so that it lives at least as long as the instance of Foo. Ignore that this might be horribly bad style for a second, and pretend that this is an external class that you want to interface with. What I want to be able to do is this:
Foo f = Foo(string("foo"));
But, of course, that will totally crash. So, I’d like to write a wrapper class, that looks like this:
class FooWrapper : public Foo {
public:
FooWrapper(string &name) :
Foo(make_a_copy(name, name_copy_)) { }
string &make_a_copy(string &src, string &dest) {
dest = src;
return dest;
}
private:
string name_copy_;
}
But here’s the problem: The code in make_a_copy() crashes because the guts of the string representation stored in name_copy_ is total garbage and not initialized to a reasonable state yet. I could create a factory function and add some yucky methods to FooWrapper, but I’d really rather not. Is there an easier way to accomplish this “copy on construct” behavior?
You could have FooWrapper store a char* and strdup the .c_str.
Doesn’t really solve the general case though.
class FooWrapper : public Foo {
public:
FooWrapper(const string& blegga) : Foo(copy_ = strdup(blegga.c_str())) {}
~FooWrapper() { free(copy_); }
private:
char* copy_;
};
Its funny that your example uses std::string because it has the solution you’re looking for.
What you’re trying to do is initialize a class member before initializing the base class, and you found that you can’t. The typical way to get around this is to abandon hope of extending Foo and implement the wrapper in terms of Foo. (has-a vs. is-a) This solution has the annoyance of you needing to redeclare each and every method you want to use and then forwarding those calls to Foo, and you won’t be able to use a FooWrapper in place of a Foo as well, meaning you may need to change a ton of references in your code. However, all you have to do is have FooWrapper expose its underlying Foo and you’re good. (kinda like what string::c_str() does)
Check out your copy of “Effective C++.” From the TOC I think item 40 discusses this.
Is the problem the lifetime of string?
Your code seems fine, but your premise is that string lives as long as Foo, and it doesn’t in your code snippet. String is gone before the assignment to f.
How about:
class StringCopyHolder {
public:
StringCopyHolder(const string& copy) : copy_(copy) {}
protected:
string copy_;
};
class FooWrapper : public StringCopyHolder, public Foo {
public:
FooWrapper(const string& blegga) : StringCopyHolder(blegga), Foo(copy_.c_str
()) {}
~FooWrapper() {}
};
and everyone says multiple inheritance is useless.
why am I here?
template
class CopyHolder {
public:
CopyHolder(const T& copy) : copy_(copy) {}
protected:
T copy_;
};