简体   繁体   中英

Initialization of derived classes in c++

//This program is taken from http://www.learncpp.com/cpp-tutorial/114-constructors-and-initialization-of-derived-classes/
#include <iostream>
using namespace std;

class A
{
public:
    A(int nValue)
    {
        cout << "A: " << nValue << endl;
    }
};

class B: public A
{
public:
    B(int nValue, double dValue)
    : A(nValue)
    {
        cout << "B: " << dValue << endl;
    }
};

int main()
{
    B bClass(5, 4.3);

    return 0;
}

When I run this:

$g++ inherit.cpp -o inherit
$ ./inherit 
A: 5
B: 4.3

which is expected.
But when I change class B to this:

class B: public A
{
int something;
public:
    B(int nValue, double dValue)
    : something(nValue), A(nValue)
    {
        cout << "B: " << dValue << endl;
    cout << "B.something: " << something << endl;
    }
};

the output is:

$ ./inherit 
A: 5
B: 4.3
B.something: 5

My question:

When the compiler goes through B's initialization list, does it only search for the Base Class constructor and jump to it and not execute the other statements( something(nValue) )
or does it execute all the statements till it finds the BaseClass constructor and simply does not execute the constructor body till Base Class constructor is done executing?

In other words would the value of B.something be set to nValue when the something(nValue) statement is first encountered or would it remain uninitialized till A(nValue) is called?

All sub-objects and non-static member objects of a class instance are initialized in fixed order, namely in the order of their declaration (which is: first all the subobjects in order (eg A , B , C for class Foo : A, B, C ), then the non-static member objects).

The order in which you list initializers in the initializer list does not affect this behaviour; however, you should always write the IL in the correct order to avoid surprises and to make your code as easy to read as possible.

You should generally avoid having one object initializer depend on another object, but sometimes it may be necessary. If possible, just reuse the constructor argument, though. Example:

struct Foo {
   int a;
   int b;
   Foo(int a_, int b_) : a(a_), b(a) { }   // not so good, depends on order!
   Foo(int a_, int b_) : a(a_), b(a_) { }  // better, always works
};

Now imagine we had instead struct Foo : Bar , and you might be tempted to write an initializer for Foo as a(a_), b(a), Bar(a, b) . That would be a disaster. Writing the IL in order makes this impossible: Bar(a_, b_), a(a_), b(a_) .

The order of subobject construction (and destruction) is only determine by the order the base classes and members are declared. The order in the initializer list is ignored. Using a different order of subobject in the initializer list is bound to confuse both you and other readers of the code: don't do it. Some compilers do warn about this. There is also an item on this in Scott Meyer's "Effective C++" (highly recommended reading; I consider it mandatory reading for any professional C++ programmer).

I ran the inherit program in gdb and it turns out that the something remains uninitialized till A(nValue) finishes execution.

Breakpoint 1, main () at inherit.cpp:27
27      B bClass(5, 4.3);
(gdb) nexti
0x08048693  27      B bClass(5, 4.3);
(gdb) s
B::B (this=0xbffff2dc, nValue=5, dValue=4.2999999999999998) at inherit.cpp:18
18      : something(nValue), A(nValue)
(gdb) p something
$2 = 3751924
(gdb) nexti
0x08048760  18      : something(nValue), A(nValue)
(gdb) p something
$3 = 3751924
(gdb) nexti
0x08048764  18      : something(nValue), A(nValue)
(gdb) p something
$4 = 3751924
(gdb) nexti
0x08048767  18      : something(nValue), A(nValue)
(gdb) p something
$5 = 3751924
(gdb) nexti
0x0804876a  18      : something(nValue), A(nValue)
(gdb) p something
$6 = 3751924
(gdb) nexti
A: 5 //A(nValue) HAS FINISHED EXECUTION AND something is still uninitialized
0x0804876f  18      : something(nValue), A(nValue)
(gdb) p something
$7 = 3751924
(gdb) nexti
0x08048772  18      : something(nValue), A(nValue)
(gdb) p something
$8 = 3751924
(gdb) nexti
0x08048775  18      : something(nValue), A(nValue)
(gdb) p something
$9 = 3751924
(gdb) nexti
20          cout << "B: " << dValue << endl;
(gdb) p something
$10 = 5

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM