19

I was under impression that it's impossible, see for example: Calling the constructor of the base class after some other instructions in C++
But the following program runs and produces two lines of "Constructor Person":

#include <iostream>

class Person
{
public:
    Person() 
    { 
        std::cout << "Constructor Person" << std::endl; }
    };

class Child : public Person
{
public:
    Child() 
    { 
        c = 1; 
        Person(); 
    }
    int c;
};

int main() 
{
    Child child;
    return 0;
}

The first one is implicit call of the default constructor, that's clear. What about the 2nd one - does it mean that the action described in the title is legitimate? I use Visual C++ 2010.

Community
  • 1
  • 1
TT_ stands with Russia
  • 1,785
  • 3
  • 21
  • 33
  • So according to answers/comments below the answer is: one should understand precisely the meaning of "Calling a constructor B of the base class from a subclass D constructor body". Constructor B can't be called in such way that it creates the parent's part of this child object. Thanks everybody! – TT_ stands with Russia Jan 28 '14 at 02:55
  • maybe it can. Either directly through `placement new` (not sure it's ok to do it that way), or it can be sometimes emulated with a utility function call https://stackoverflow.com/questions/62434909/manually-calling-constructor-of-base-class-outside-initialization-list – oromoiluig Jun 17 '20 at 22:17

5 Answers5

20

The call inside the child class constructor is not calling the base class constructor, it is creating a temporary, unnamed and new object of type Person. It will be destroyed as the constructor exits. To clarify, your example is the same as doing this:

Child() { c = 1; Person tempPerson; }

Except in this case, the temporary object has a name.

You can see what I mean if you modify your example a little:

class Person
{
public:
    Person(int id):id(id) { std::cout << "Constructor Person " << id << std::endl; }
    ~Person(){ std::cout << "Destroying Person " << id << std::endl; }
    int id;
};

class Child : public Person
{
public:
    Child():Person(1) { c = 1; Person(2); }
int c;
};

int main() {
Child child;

Person(3);
return 0;
}

This produces the output:

Constructor Person 1
Constructor Person 2
Destroying Person 2
Constructor Person 3
Destroying Person 3
Destroying Person 1
zdan
  • 28,667
  • 7
  • 60
  • 71
  • Yes, @happydave wrote the same in comments below. Probably, I don't understand what the constructor call means. If the `Person();` in my or your examples are not constructor calls, when what exactly people mean when then say: you can't call base constructor from subclass constructor? – TT_ stands with Russia Jan 28 '14 at 02:14
  • 1
    @TT_ They mean that you can't call it on that object. The value of the "this" pointer when your Person constructor runs the second time will be completely different from the "this" pointer the first time that it runs. Because the second time, it's just calling the constructor on a temporary, unrelated object. – happydave Jan 28 '14 at 02:21
  • @happydave ...meaning that my 2-nd constructor call has nothing to do with construction of the parent part of the child. This makes sense. It seems the terminology is not precise enough. – TT_ stands with Russia Jan 28 '14 at 02:40
12

The following is an excerpt from "Accelerated C++": "Derived objects are constructed by:
1. Allocating space for the entire object (base class members as well as derived class members);
2. Calling the base-class constructor to initialize the base-class part of the object;
3. Initializing the members of the derived class as directed by the constructor initializer;
4. Executing the body of the derived-class constructor, if any."

Summarizing the answers and comments: Calling a constructor of the base class from a subclass' constructor body is impossible in the sense that #2 above must precede #4. But we still can create a base object in the derived constructor body thus calling a base constructor. It will be an object different from the object being constructed with the currently executed derived constructor.

TT_ stands with Russia
  • 1,785
  • 3
  • 21
  • 33
  • *Calling a constructor of the base class from a subclass' constructor body is impossible* Totally possible, just undefined behavior, so it helps that the placement new syntax to actually pull such a stunt off is obscure. But e.g. completely destructing the object inside the constructor and then re-constructing it is AFAIK defined, so you can `C::C() { thread_local static C*guard; if (guard == this) return; guard = this; ~C(); new (this)C(); guard = nullptr; }`. All recent compilers I tried it on generate valid and working machine code for it, at least :) – Kuba hasn't forgotten Monica Nov 25 '20 at 17:12
9

You can't call it from the body of the child constructor, but you can put it into the initializer list:

public:
    Child() : Person() { c = 1; }

Of course it's not helpful to call the default constructor of the parent because that will happen automatically. It's more useful if you need to pass a parameter to the constructor.

The reason you can't call the constructor from the body is because C++ guarantees the parent will be finished constructing before the child constructor starts.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
  • I know I can put it into the initializer list, I am asking why my code works (so I can call it from the body of the child constructor!). – TT_ stands with Russia Jan 28 '14 at 01:59
  • You're just instantiating a temporary Person object with your call to `Person();`. It has nothing to do with the Child object that is currently being constructed (except of course, for being called from the Child object's constructor). – happydave Jan 28 '14 at 02:00
  • 1
    @TT_ I don't think it's actually calling the constructor, at least not for the object you're interested in. – Mark Ransom Jan 28 '14 at 02:00
  • @happydave And again, it does not answer the question. I am not asking about side effects, the question is: why this code works? – TT_ stands with Russia Jan 28 '14 at 02:01
  • @Mark Ransom What do you mean? Is not `Person();` a constructor call? – TT_ stands with Russia Jan 28 '14 at 02:02
  • No, it's an object instantiation. It's declaring an entirely new Person object. It's like saying `int x;`, except that it happens to be anonymous, and it has nothing to do with Child (and is a Person, not an integer). – happydave Jan 28 '14 at 02:03
  • To be clear, if the Person constructor did something like assign a value to an instance variable, it wouldn't assign it to your object, it would assign it to the anonymous object (which would then immediately be destroyed). – happydave Jan 28 '14 at 02:05
  • @happydave I see your point, but then how would the constructor call look like? You see, I know something is impossible, but it seems like I wrote it and it works. So natural question is - what exactly is impossible? What do people mean when then say: you can't call base constructor from subclass constructor? – TT_ stands with Russia Jan 28 '14 at 02:07
  • @TT_ correct, it's *not* a constructor call. Such a thing is impossible in C++ unless you use placement new, which has a completely different syntax and use case. – Mark Ransom Jan 28 '14 at 02:11
  • @TT_ you could also do `int();` which would create a temporary int. You don't really think you're calling the `int` constructor on your object do you? – Mark Ransom Jan 28 '14 at 02:12
  • @Mark Ransom You are playing with words :) (maybe we both do) I reformulate my question. Can you create a code example where compiler would produce an error because a constructor called? Then I would see the difference. – TT_ stands with Russia Jan 28 '14 at 02:20
  • 1
    @TT_ no I can't produce such an example because creating a temporary object is perfectly OK. It just doesn't accomplish what you're expecting. – Mark Ransom Jan 28 '14 at 02:33
3

The answers to this question while usually technically true and useful, don't give the big picture. And the big picture is somewhat different than it may seem :)

  1. The base class's constructor is always invoked, otherwise in the body of the derived class's constructor you'd have a partially constructed and thus unusable object. You have the option of providing arguments to the base class constructor. This doesn't "invoke" it: it gets invoked no matter what, you can just pass some extra arguments to it:

    // Correct but useless the BaseClass constructor is invoked anyway
    DerivedClass::DerivedClass() : BaseClass() { ... }
    // A way of giving arguments to the BaseClass constructor
    DerivedClass::DerivedClass() : BaseClass(42) { ... }
    
  2. The C++ syntax to explicitly invoke a constructor has a weird name and lives up to this name, because it's something that's very rarely done - usually only in library/foundation code. It's called placement new, and no, it has nothing to do with memory allocation - this is the weird syntax to invoke constructors explicitly in C++:

    // This code will compile but has undefined behavior
    // Do NOT do this
    // This is not a valid C++ program even though the compiler accepts it!
    DerivedClass::DerivedClass() { new (this) BaseClass(); /* WRONG */ }       
    DerivedClass::DerivedClass() { new (this) BaseClass(42); /* WRONG */ }
    // The above is how constructor calls are actually written in C++.
    

    So, in your question, this is what you meant to ask about, but didn't know :) I imagine that this weird syntax is helpful since if it were easy, then people coming from languages where such constructor calls are commonplace (e.g. Pascal/Delphi) could write lots of seemingly working code that would be totally broken in all sorts of ways. Undefined behavior is not a guarantee of a crash, that's the problem. Superficial/obvious UB often results in crashes (like null pointer access), but a whole lot of UB is a silent killer. So making it harder to write incorrect code by making some syntax obscure is a desirable trait in a language.

  3. The "second option" in the question has nothing to do with constructor "calls". The C++ syntax of creating a default-constructed instance of a value of BaseClass object is:

    // Constructs a temporary instance of the object, and promptly
    // destructs it. It's useless.
    BaseClass();
    // Here's how the compiler can interpret the above code. You can write either
    // one and it has identical effects. Notice how the scope of the value ends
    // and you have no access to it.
    {
      BaseClass __temporary{};
    }
    

    In C++ the notion of a construction of an object instance is all-permeating: you do it all the time, since the language semantics equate the existence of an object with that object having been constructed. So you can also write:

    // Constructs a temporary integer, and promptly destructs it.
    int();
    

    Objects of integer type are also constructed and destructed - but the constructor and destructor are trivial and thus there's no overhead.

    Note that construction and destruction of an object this way doesn't imply any heap allocations. If the compiler decides that an instance has to be actually materialized (e.g. due to observable side effects of construction or destruction), the instance is a temporary object, just like the temporaries created during expression evaluation - a-ha, we notice that type() is an expression!

    So, in your case, that Person(); statement was a no-op. In code compiled in release mode, no machine instructions are generated for it, because there's no way to observe the effects of this statement (in the case of the particular Person class), and thus if no one is there to hear the tree fall, then the tree doesn't need to exist in the first place. That's how C++ compilers optimize stuff: they do lot of work to prove (formally, in a mathematical sense) whether the effects of any piece of code may be unobservable, and if so the code is treated as dead code and removed.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
-1

Yeah, I know this is a year old but I found a way to do it. This may not be the best practice. For example, destroying the base class instance from within the derived class constructor sounds like a recipe for disaster. You could skip the destructor step, but that may lead to a memory leak if the base class constructor does any allocation.

class Derived : public Base
{
public:
   Derived()
   {
       // By the time we arrive here, the base class is instantiated plus 
       // enough memory has been allocated for the additional derived class stuff.

       // You can initialize derived class stuff here

       this->Base::~Base(); // destroy the base class
       new (this) Base(); // overwrites the base class storage with a new instance
   }
};