5

Why do this C++ program could run successfully even without constructing the class object? Let's see the code as below:

#include<iostream>

using namespace std;

class Dopey
{
  public:
    Dopey() {cout << "Dopey\n";}
};

class Bashful
{
  public:
    Bashful() { cout << "BashFul\n";}
    void f() { cout << " f \n";}
    int i;
};

class Sneezy
{
  public:
    Sneezy(int i) {cout << "copy int \n";}
    Sneezy(Bashful d) { cout << "copy Bashful\n";}
    Sneezy(Bashful* d) {d->f();d->i=100;} //How could this be correct without    
                                              //  constructing d !!!!!!!!
    Sneezy();
};

class Snow_White
{
  public:
    Snow_White();
    Dopey dopey;
    Sneezy sneezy;
    Bashful bashful;
  private:
    int mumble;
};

Snow_White::Snow_White() : sneezy(&bashful)
{
    mumble = 2048;
}

int main()
{

    Snow_White s;

    return 0;
}

This program could run successfully , the cout are as below:

Dopey
f
BashFul

see, without constructing bashful,the f() could be invoked, why? and when i change the function Snow_White::Snow_White() to the below:

Snow_White::Snow_White() : sneezy(bashful)
{
    mumble = 2048;
}

it also runs successfully without constructing bashful , the cout are as below:

Dopey
copy Bashful
Bashful

Any interpretation will be appreciated ! THX !

Mankarse
  • 39,818
  • 11
  • 97
  • 141
freeboy1015
  • 2,227
  • 2
  • 18
  • 15
  • You might find this useful: http://stackoverflow.com/questions/2505328/calling-class-method-through-null-class-pointer – chris Nov 14 '12 at 02:41
  • 2
    Argh... eye cancer... please use spaces! – Kerrek SB Nov 14 '12 at 02:43
  • 2
    Another tip: If you use `struct` rather than `class`, you can save yourself thousands of instances of `public`... Always think: Do they *need* to know this? – Kerrek SB Nov 14 '12 at 02:49
  • 2
    To answer the question: It's just undefined behaviour. Anything could happen. It's not particularly interesting or enlightening to muse over wrong code. – Kerrek SB Nov 14 '12 at 02:51
  • 1
    @Kerrek: If your interest is C++, no. But if you're also interested in compiler behavior, it might be interesting. – Benjamin Lindley Nov 14 '12 at 02:53

3 Answers3

6

Your program has undefined behaviour because you are accessing bashful before it has been constructed.

Mankarse
  • 39,818
  • 11
  • 97
  • 141
2

Your problem has to do with your initialization list. bashful is declared after sneezy. Therefore, in this code:

Snow_White::Snow_White() : sneezy(&bashful)

bashul has not been constructed yet, because according to Snow_White's declaration, sneezy must be constructed first (yes, the order matters). Therefore, the parameter passed in to sneezy's constructor points to an unitialized object. At this point, the reason it works is what chris has linked to. Keep in mind, that although this works, according to the C++ standard the behaviour is undefined and that means you cannot and must not rely on it to work.

However, the real problem is that bashful hasn't been constructed yet.

To fix that, you would need to alter the declaration of your Snow_White class so that bashful comes before sneezy:

class Snow_White
{
  public:
    Snow_White();
    Dopey dopey;
    Bashful bashful;
    Sneezy sneezy;
  private:
    int mumble;
};

One way to avoid this kind of thing occuring is to always keep your declarations and initialization lists in alphabetical order.

The other way is to keep your classes small to begin with, so this is never an issue :)

Community
  • 1
  • 1
Carl
  • 43,122
  • 10
  • 80
  • 104
0

The bashful member is being constructed as is shown by the inclusion of Bashful in the output. It is true that it is not constructed prior to the address of bashful being taken and passed to the other member's constructor.

There are specific rules as to the order in which member are initialized, but the order initialization or use in the constructor initialization list is not one of the factors in those rules.

Josh Heitzman
  • 1,816
  • 1
  • 14
  • 26
  • I mean the `d` in Sneezy(Bashful* d) {d->f();d->i=100;} – freeboy1015 Nov 14 '12 at 03:29
  • Right the variable named d in that function has a value that is the address of the bashful member of the Snow_White instance. The address of bashful is taken before the Bashful constructor has been called since the bashful member is declared after the sneezy member. – Josh Heitzman Nov 14 '12 at 03:36