Abhinav Vishak
Abhinav Vishak

Reputation: 371

Constructors with objects as parameters

Suppose I have a class as follows:

class A{
    int x ; 
    A( int i ){
        x = i ; 
    }
}

And I have another class B which has an instance of class A as an member object.

class B{
    int y ; 
    A obj_a ; 
    B( int j , A a ){
        y = j ; 
        obj_a = a ; 
    }
}

When I do the following :

int main(){
        A obj1( 1 ) ; // obj.x has value 1
        B obj2( 2 , obj1 ) ; 
    }

The 2nd line throws an error saying no function call of the form A::A(). I know this means that a default style constructor is missing , but why do I need this ? obj1 is created using the defined constructor so that isn't an issue.

My current line of thought is that A a and obj_a = a would invoke the copy constructor which is implicitly defined.

Note: I have excluded private,public etc for brevity.

Upvotes: 2

Views: 12557

Answers (2)

user4581301
user4581301

Reputation: 33931

An object must be fully consistent, all of its members constructed, by the time it enters the body of the constructor. So in

B( int j , A a ){
    y = j ; 
    obj_a = a ; 
}

before

{
    y = j ; 
    obj_a = a ; 
}

gets a chance to do anything, obj_a must have been constructed.

Since no instruction on how to construct obj_a has been provided with the Member Initializer List, obj_a will be built with the default constructor for class A. Class A has no default constructor, no A::A(), so the error is raised.

The solution is to use the Member Initializer List instead of assignment inside the body of the function. Not only does this save you construction of an object that will promptly be over written, the compiler also has more lee-way to optimize and you may get some other small improvements.

Class B should be:

class B{
    int y ; 
    A obj_a ; 
    B( int j , A a ): y(j), obj_a(a)
    {
    }
}

Upvotes: 4

Rakete1111
Rakete1111

Reputation: 48938

obj_a = a calls operator=, not the copy constructor. The thing is, obj_a is initialized using the default constructor, because you haven't specified which constructor to call in the initializer list.

B( int j , A a ) /*: obj_a{}*/ { /*...*/ }
                 ^^^^^^^^^^^^^
          implicit call to default constructor

You have to explictly call the constructor with one argument in the member initialization list:

B( int j , A a ) : obj_a{ a } { /*...*/ }

Upvotes: 3

Related Questions