2

I get the error: No appropriate default constructor for B. However, I don't understand why the compiler wants to call a default constructor, when I give the arguments ii and DONT want to call the default.

#include <iostream>
using namespace std;

class A {
    int i;
public:
    A(int ii) { i = ii; cout << "Constructor for A\n"; }
    ~A() { cout << "Destructor for A\n"; }
    void f() const{}
};

class B {
    int i;
public:
    B(int ii) { i = ii; cout << "Constructor for B\n"; }
    ~B() { cout << "Destructor for B\n"; }
    void f() const{}
};

class C:public B {
    A a;
public:
    C() { cout << "Constructor for C\n"; }
    ~C() { cout << "Destructor for C\n"; }
    void f() const {
        a.f();
        B::f();
    }
};

class D:public B {
    C c;
public:
    D(int ii) { B(ii); cout << "Constructor for D\n"; }
    ~D() { cout << "Destructor for D\n"; }
};

int main() {
    D d(47);
}
code12098
  • 79
  • 1
  • 8
  • 1
    Possible duplicate of [no appropriate default constructor available . (when creating a child class)](https://stackoverflow.com/questions/3070366/no-appropriate-default-constructor-available-when-creating-a-child-class) – Justin Apr 05 '18 at 00:02

5 Answers5

5

Your parent constructor should be called in the initializer list:

class D:public B {
    C c;
public:
    D(int ii) : B(ii)/* <- */ { cout << "Constructor for D\n"; }
    ~D() { cout << "Destructor for D\n"; }
};

Note the /* <- */ comment. That needs to be changed.

What you are doing right now is to create an instance of B() in you class D constructor, which is not being used:

D(int ii) { B(ii); /* <- useless*/ }
mfontanini
  • 21,410
  • 4
  • 65
  • 73
2
D(int ii) { B(ii); cout << "Constructor for D\n"; }

Calls the default constructor of B. The B(ii) creates an temporary object of B which gets destructed as soon as constructor of D returns, In short it does not call the constructor for Base class of object which is being constructed.

Solution:
To be able to call a particular constructor of your Base class you should use Member Initializer list.

D(int ii) : B(ii)
{
}
Community
  • 1
  • 1
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 1
    @LuchianGrigore: No wonder it has the same problem. OP is unaware of member initializer lists and i think the answer points it out.OPs comments indicate S/He understands it through the answers here so I dont feel a compelling need to edit anything further. – Alok Save Mar 11 '12 at 18:18
2

This code:

class C:public B
{
    C() { cout << "Constructor for C\n"; }
};

attempts to call B's default constructor.

You might want:

class C:public B
{
    C() : B(0) { cout << "Constructor for C\n"; }
};

but that depends on your logic.

The following is also wrong:

 D(int ii) { B(ii); cout << "Constructor for D\n"; }

it should be

 D(int ii) : B(ii) { cout << "Constructor for D\n"; }

Calling the base class constructor in the body of the child class constructor merely creates a temporary object which doesn't do anything. To get the behavior you expect, you must call the constructor in the initializer list.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
1

You're creating a D, which is derived from B -- but D's ctor doesn't pass a parameter to B's constructor, which would require that B have a default ctor.

To fix this, you typically need to write D to provide a parameter to B's ctor:

class D : public B { 
    C C;
public:
    D(int ii) : B(ii) { cout << "ctor for D\n"; }
};
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
1

You need to realize that base and member subobjects are constructed by the time you enter the body of your constructor! That is, if you have a base or a member which doesn't have a default you need to pass its argument in the member initializer list:

D(int ii): B(ii) { std::cout << "constructor for D\n"; }

The object you constructed in your body of the D constructor is just a temporary object which doesn't really serve any purpose in your case (temporary object may be useful in some cases, though).

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380