Reputation: 6606
I have a class Foo
that has a reference to Bar
as an instance variable. Is there a way to have one of the Foo
constructors create a Bar
instance (so users of the Foo
class need not explicitly create a Bar
object themselves)?
I'd like to do something like this:
class Foo {
private:
int size;
Bar& bar; // shared by other objects
//several other instance variables
public:
Foo(int s, Bar& b) : size(s), bar(b) {}
// This, of course, doesn't work. I can't think of an
// alternative that doesn't require users of Foo to
// create Bar
Foo(int s) : size(s), bar(Bar(s)) {}
}
(In "real life", Foo
and Bar
are more complicated. Bar
is a friend of Foo
that has a private constructor used only by Foo
. Each Bar
can be shared by several Foo
s. This isn't a major problem, I'm just curious if it can be done without pointers.)
Upvotes: 1
Views: 167
Reputation: 29072
The simplest solution would be to allocate a Bar
if and when you need one. Adding a member std::unique_ptr<Bar>
is the easiest way of achieving this. I can't conceive of a system that addresses your problem that will not add some memory overhead to your class. You either have to account for storage for a Bar
even when it isn't needed or you have to account for some state to track rather or not your Bar
is internally managed. Using a unique_ptr
adds the size of a pointer to your class.
#include <memory>
class Foo {
private:
std::unique_ptr<Bar> storage;
Bar& bar;
int size;
public:
Foo(int s, Bar& b) : bar(b), size(s) {}
Foo(int s) : storage(std::make_unique<Bar>(s)), bar(*storage), size(s) {}
};
A more elaborate solution could be to provide a wrapper for Bar
that provides a default constructor that takes care of initializing a new instance.
Note that in your example, you do not initialize the member in the same order as they are declared. Members will be initialized in the order they are declared regardless of how you order them in your initialization list.
Upvotes: 3
Reputation: 206737
// This, of course, doesn't work. I can't think of an // alternative that doesn't require users of Foo to // create Bar Foo(int s) : size(s), bar(Bar(14)) {}
You can use a default Bar
object, which can be a static
member variable of Foo
or any other class that can provide such an object.
E.g.
class Foo {
private:
Bar& bar; // shared by other objects
int size;
//several other instance variables
static Bar& getDefaultBar();
public:
Foo(int s, Bar& b) : size(s), bar(b) {}
Foo(int s) : size(s), bar(getDefaultBar()) {}
}
Bar& Foo::getDefaultBar()
{
static Bar b(24);
return b;
}
Upvotes: 0
Reputation: 35164
If every Foo
shall have it's own individual Bar
-object (not a single shared one), then you could try the following:
class Foo {
private:
Bar& bar; // shared by other objects
int size;
Bar* defaultBar;
//several other instance variables
public:
Foo(int s, Bar& b) : size(s), bar(b), defaultBar(nullptr) {}
Foo(int s) : Foo(s, *(new Bar(14))) { defaultBar=&bar; };
virtual ~Foo() {
if (defaultBar)
delete defaultBar;
}
void setBar(Bar &b) {
if (defaultBar)
delete defaultBar;
defaultBar = nullptr;
bar=b;
}
};
Hope it is what you are looking for.
Upvotes: 0