C++: How do you initialize an internal struct's members using an initialization list?
This is really two questions, noted below:
Currently I have some public internal helper structs (strictly used to pass data around as one object), during construction of an instance of the class I attempted to use initialization lists instead of assignment, but the compiler complained about the individual struct members so I added constructors to the structs...but that just seems like I'm headed down the wrong path.
Is there a way to initialize a struct in an initializer list without using a constructor?
Would these helpers be better suited as an external class?
class Foo {
public:
//...
struct Bar {
double mass;
std::pair<double, double> gravMod;
std::pair<double, double> position;
std::pair<double, double> velocity;
bool falling;
Bar() : mass(0.0), gravMod(std::make_pair(0.0, 0.0)), position(std::make_pair(0.0, 0.0)), velocity(std::make_pair(0.0, 0.0)), falling(false) { };
Bar(double _mass, std::pair<double, double> _gravMod, std::pair<double, double> _position, std::pair<double, double> _velocity, bool _falling)
: mass(_mass), gravMod(_gravMod), position(_position), velocity(_velocity), falling(_falling) { }
Bar(const Bar& other)
: mass(other.mass), gravMod(other.gravMod), position(other.position), velocity(other.velocity), falling(other.falling) { }
};
struct Baz {
std::pair<double, double> acceleration;
std::pair<double, double> force;
Baz() : acceleration(std::make_pair(0.0, 0.0)), force(std::make_pair(0.0, 0.0)) { }
Baz(std::pair<double, double> _acceleration, std::pair<double, double> _force)
: acceleration(_acceleration), force(_force) { }
Baz(const Baz& other) : acceleration(other.acceleration), force(other.for开发者_StackOverflow社区ce) { }
};
//...
protected:
//...
private:
Bar _currBar;
Bar _prevBar;
Baz _currBaz;
Baz _prevBaz;
};
EDIT
Examples and their associated errors:
Foo::Foo() : _currBar{0.0, std::make_pair(0.0, 0.0), std::make_pair(0.0, 0.0), std::make_pair(0.0, 0.0), false}, _currBaz{std::make_pair(0.0, 0.0), std::make_pair(0.0, 0.0)} { }
_currBar{
throws: expected '('
. The first }
throws: expected';'
.
Foo::Foo() : _currBar.mass(0.0), _currBar.gravMod(std::make_pair(0.0, 0.0)), _currBar.position(std::make_pair(0.0, 0.0)), _currBar.velocity(std::make_pair(0.0, 0.0)), _currBar.falling(false) { }
The first _currBar.
throws: expected '('
. All _currBar.
afterwards throw Member 'Foo::_currBar' has already been initialized.
.
In C++03, there is no way to initialize individual fields of a nested struct
, nor is there a way to initialize individual fields of a nested array. In C++0x (now C++11, I guess), they've relaxed this restriction and you can initialize nested struct
s with a syntax like this:
Foo::Foo() : _currBar{fieldOneValue, fieldTwoValue, /* ... */, fieldNValue}, /* ... etc ... */
Adding constructors to your nested struct
s is a perfectly viable option in the interim as we wait for more compilers to completely support this feature.
There is nothing wrong with the approach you are using as long as you maintain the following:
strictly used to pass data around as one object
When deciding whether to use a struct or a class the question to ask is: Does an invariant exist for this object? An invariant being a description of what constitutes a valid state for the object. If you can define an invariant, then it follows that you can also define an invalid state and that you should provide access to internal member variables only through member functions to ensure that a valid state can be maintained. This is best performed by a class. If, however, any old state will do; then use a struct.
Your constructors are merely giving sensible defaults and not attempting to maintain a valid state so there is nothing wrong with using them in a struct.
You can in principle do without the constructors:
Foo::Foo(): _currBar(), _prevBar(), _currBaz(), _prevBaz() {}
This syntax zero-initializes a constructor-less object (sets all fields to 0 / invokes their default constructor).
If you want a constructor with parameters, you can use a helper function:
Bar make_bar(double mass, std::pair<double, double> gravMod, std::pair<double, double> position, std::pair<double, double> velocity, bool falling)
{
Bar bar = { mass, gravMod, position, velocity, falling };
return bar;
}
Foo::Foo(args...): _currBar(make_bar(args...)), ...
In any case, you don't need to add a copy constructor. The compiler will generate a copy constructor that will do exactly that.
(BTW, I probably wouldn't use std::pair
when a math vector class would be more appropriate. I assume, things like position
could rather use properties called x
and y
over first
and second
.)
精彩评论