0

Possible Duplicate:
Calling class method through NULL class pointer

I was asked this question in the interview can someone answer it?

#include<string>
#include<iostream>
#include <stdio.h>

using namespace std;

class A
{
int k;
public:
     void f1()
    {

     int i;
     printf("1");

    }

     void f2()
    {

     k = 3;
     printf("3");

    }

};
class B
{
int i;
public:
    virtual void f1()
    {
    printf("2");
    scanf("%d",&i);
    }

};


int main()
{
    A* a = NULL;
    B* b = NULL;

    a->f1(); // works why?(non polymorphic)
    b->f1(); // fails why?(polymorphic)
            a->f2(); //fails why?
}

The last 2 cases are of polymorphic classes. The first case is a normal class .i understand that if i access i in f1 of A it will again give a runtime exception . but i am not getting why that happens

Community
  • 1
  • 1
jc tronics
  • 97
  • 1
  • 1
  • 5
  • You have a null pointer exception even in the first case. Thus, even the first one doesn't work – Seb Oct 08 '12 at 14:56
  • `a->f1();` in most cases works because (1) it does not use object member variables (2) it does not use vtable to make call of virtual function. But only it works in most cases (frankly I do not know the case when it does not work...) But you can report that question is not very correct. – PiotrNycz Oct 08 '12 at 15:13

5 Answers5

2
a->f1();
b->f1();
a->f2();

In all the three cases you are deferefencing a pointer that points to NULL, i.e. it does not point to an object. This constitutes undefined behaviour. They may work by pure chance, but you cannot rely on that. It also doesn't makes much sense to try to figure out why one version could possibly work. Undefined behaviour means anything can happen.

juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • 1
    If the interviewer said that case #1 "works" (in a general sense), he/she was wrong. It might work in a sense on certain platforms, but that would be pure chance/dumb luck. – John Dibling Oct 08 '12 at 15:10
2

I agree with the other posts that this is undefined behavior, meaning anything can happen when executing the program, including "doing the right thing".

Now, let's look at how the calls are implemented:

a->f1() is a normal method call (non virtual). Most compilers will compile this in a similar way as the following code:

    class A { int i; }
    void f1(A* a) { int i; printf("1"); }

Meaning the this pointer is actually handled like a parameter to the function (in practice there are frequently some optimizations about how the this pointer is handled, but that is irrelevant here). Now, since f1 doesn't use the this pointer, the fact that it is null doesnt cause a crash.

a->f2() will actually crash because it uses the this pointer: it updates this->k.

The call to b->f1() is a virtual function call, and this is typically implemented using a virtual table lookup as b->vtable[0](). Since b is null, the dereference to read the virtual table crashes.

anonymous
  • 471
  • 4
  • 11
1

Technically this is all undefined behaviour. So without more background (compiler, used settings) this would be the correct answer.

I don't believe this is what they expected to hear though.

Given that usually a member function call is internally translated in this manner (simplified on purpose):

class A {
    void foo(int x) {}  // compiler creates function void A_foo(A* this, int x) {}
};

A a;
a.foo(5); // compiler calls A_foo(&a, 5);

BUT the situation is different for virtual functions. I will not explain the principle of virtual dispatch here, but to simplify - the function that gets called in the end is dependent on the dynamic type of the object. If the object doesn't exist, the program can't know what function to call.

As to why your a->f2() fails. Imagine the function A_f2(A* this). Inside you access A's member k. This would in my simplified compiler get translated to this->k = 3. But in the actual call this is a null pointer.

Fiktik
  • 1,941
  • 16
  • 25
0

In a way neither of the three cases "works". But in another way, all of the three cases "work".

They all have undefined behaviour, because they all perform indirection through a null pointer.

i understand that if i access i in f1 of A it will again give a runtime exception

Maybe, maybe not. Undefined behaviour is undefined, so anything can happen.

R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
0

All three examples result in undefined behavior, so this is very implementation specific and not guaranteed to have the same behavior on all compilers.

A common way of implementing virtual functions is to add a pointer to a table of function pointers at the beginning of a class. Whenever a virtual function is called, the program follows this pointer and looks in the table to determine which function to call. Since, in the example of a null-pointer, it is looking at an invalid address for this pointer, this causes a runtime error.

When calling a non-virtual function, the compiler already knows exactly what function to call, so it can directly insert a call to this function; accessing the object is not necessary to determine which function to call. So, if the function itself does not access the object, the function call will never result in an access through the null-pointer, so it won't result in a runtime error.

Dirk Holsopple
  • 8,731
  • 1
  • 24
  • 37