1

I read about references and objects that are initialised in a class. However, I couldn't find a clear statement, except for hints, to the following question:

Can I initialise a member object obj1 in an initialisation list if it doesn't have a default constructor (no Object(){})?

class Sample
{
private:
      Object1 obj1(arguments);
public:
     Sample(Object1 o1)  : obj1( o1(arguments) )
     { }
};

The question came up, because if have a problem related to this How can I initialize C++ object member variables in the constructor?. The code is taken form there as well. Thanks for your effort.

Daniel

EDIT:

Since the answer suggest that it works, a test returned an error (which is exactly the reason I ask this question):

../src/Timestep.h:45:12: error: field ‘myFEMSolver’ has incomplete type FEMSolver myFEMSolver;

Code:

class Timestep {
public:
  Timestep();
private:
  FEMSolver myFEMSolver;
}

Timestep::Timestep() : myFEMSolver(*this)
  { //do some stuff
}

FEMSolver::FEMSolver(const Timestep& theTimestep) : myTimestep(theTimestep)
  { //do some stuff
}

main(){
  Timestep myTimestep();
}
3
  • 1
    That code does not produce that error. Namely, you get that error when the FEMSolver class itself is declared but not defined at the point that TimeStep is defined. FEMSolver must be defined fully first. This has nothing whatsoever to do with initializer lists. meta.stackexchange.com/questions/66377/what-is-the-xy-problem Commented Mar 25, 2014 at 19:12
  • In fact it is not a XY problem. The original question was important to realise that what I intend to do would actually work. But you were right about the declaration. I switched come header an now it works. Thanks you very much. Commented Mar 25, 2014 at 20:21
  • X was "what is producing this incomplete type error". Y is "Can I initialize a member object in an initialization list if it doesn't have a default constructor " This is very much an X/Y problem. Commented Mar 25, 2014 at 20:26

3 Answers 3

6

Can I initialise a member object obj1 in an initialisation list if it doesn't have a default constructor (no Object(){})?

Yes. In fact, you must do so.

class Sample
{
    private:

        Object1 obj1;

    public:

        Sample() : obj1( /* ctor args */ )
        {
        }
};

If you're passing another Object1 to your Sample constructor, and passing that to Object1's copy constructor, then you probably want to pass it by reference:

Sample(const Object1& o) : obj1(o)
{
}

If Object1 doesn't have a no-argument constructor, and you don't initialize obj1 in the initializer list, you'll get a compile error.

Sign up to request clarification or add additional context in comments.

Comments

0

Change your class declaration as follows:

class Sample
{
private:
      Object1 obj1;
public:
     Sample(const Object1& o1)  : obj1(o1)
     { }
};

To call the Sample constructor use:

Sample s(Object1(arguments));

This requires, that your Object1 is a so called nice class (provides copy constructor and assignment operator).
For any other case you'll need to use a reference or pointer of Object1 as member in the Sample class.

Another (easier) way is to pass the arguments through:

class Sample
{
private:
      Object1 obj1;
public:
     Sample(Args& arguments)  : obj1(arguments)
     { }
};

Comments

0

It appears you either want to give an existing Object1 in a list-initializer, or make an Object1 inside a nested list-initializer, unless Object1's constructor is explicit. So let's say we have

struct Object1
{
    Object1(int, int) { };
};

Then the most generic way to initialize Object1 within Sample by copy, move, or its own arguments without ambiguities is:

class Sample
{
private:
    Object1 obj1;
public:
    Sample(Object1&& o1) : obj1(std::move(o1)) { }
    Sample(const Object1& o1) : obj1(o1) { }

    template<
        typename... A,
        typename = typename std::enable_if<std::is_constructible<Object1, A...>{}>
    >
    Sample(A&&... a) : obj1(std::forward<A>(a)...) { }
};

This allows us a variety of Sample constructions:

int main ()
{
    Object1 o1{1, 2};
    const Object1& o2{o1};
    Sample s1{Object1{1, 2}};
    Sample s2{{1, 2}};
    Sample s3{1, 2};
    Sample s4{o1};
    Sample s5{o2};
}

If Object1's constructor is explicit, then s2 is not allowed. Depending on what you want to support, you can of course simplify Sample in a number of ways.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.