Bloomberg LP Interview Question for Software Analysts


Country: United States
Interview Type: Phone Interview




Comment hidden because of low score. Click to expand.
2
of 2 vote

1. size of array must be specified by a const int var.
2. In spite of the above, the program output would be still undefined. Because the pointer to base is being incremented which is basically adding an address value with the sizeof (base). So we need to have separate definition of derived and base. Or any class which uses "display" method.

So the second change could be to make "display" method a template method as:

template<typename T>
void display(T* obj, int ele)
{
	for (int i = 0; i < ele; i++)
	{
		cout << (obj + i)->getA() << endl;
	}

}

- Ajith April 01, 2017 | Flag Reply
Comment hidden because of low score. Click to expand.
1
of 1 vote

I think it has to do with the layout of the object. arrd is class der, which has the layout of two entries, int a (4 bytes) and int b (4 bytes). So if arrd[0] is at address x, arrd[0].a is at x+0 and arrd[0].b is at x+4.

When you pass arrd into the display function, you're passing it as a pointer. When you increment a pointer (obj+i), you're adding 4 bytes to the object's address. This does not give you the next element in the array (unless each element is size 4 bytes like an array of integers). You really need to add 8 bytes to get the next element in the array of der objects because 8 is the size of each arrd object.

In summary, you're seeing 0,1,0 because you're seeing var 'a' of the first object, var 'b' of the first object, and var 'a' of the second object.

If you print out the address of the objects, this will be make more sense. For example,

arrd[0] is at address 0xfff...e0 where var 'a' is at 0xfff...e0 and var 'b' is at 0xfff...e4
arrd[1] is at address 0xfff...e8 where 'a' is at 0xfff...e8 and 'b' is at 0xfff...ec
arrd[2] is at address 0xfff...f0 where 'a' is at 0xfff...f0 and 'b' is at 0xfff...f4

If you print the address of obj+i:

obj+0 is at address 0xfff...e0 // 'a' from arrd[0]
obj+1 is at address 0xfff...e4 // 'b' from arrd[0]
obj+2 is at address 0xfff...e8 // 'a' from arrd[1]

- kttruong July 13, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
1
of 1 vote

//
// " The output is looking like: 0 0 0 0 1 0
//   To me the output should be: 0 0 0 0 0 0
//
//   But, how come 1 is coming in ? "
//
//     - rasmiranjanbabu July 12, 2016 in United States
//       Bloomberg LP Software Analyst C++
//
// By way of the xcode debugger it was observed that
// the address size of the first display() function was
// assuming that the size of all objects passed to it were
// always the base class size. When the display() function
// is passed a derived class it does not take into
// consideration the larger sized object in it's pointer
// calculations.
//
// There are two ways to resolve the issue. One is to place
// make the base::getA() method virtual. This allows the compiler
// to take into account the actual size of the object at runtime.
//
// The slightly larger but more elegant approach would be to
// write a dedicated (albeit duplicate) function for the der
// class of the function display()
//
// In order to compile this source code under xcode 7.x however
// the "int i = 3" has to changed to a "const int i=3" otherwise
// the original source will not even compile as the size of arrays
// require a constant upon declaration.
//
// (c) 2016 Perry Anderson, All Rights Reserved, worldwide.
//
//

#include <iostream>
#include <typeinfo>

using namespace std;

class base {
public:
    int a;
    base() : a(0) {}
    // solution #1: add 'virtual' here
    virtual int getA() { return a; }
};
class der : public base {
public:
    int b;
    der() : b(1) {}
    int getB() { return b; }
};
void display(base* obj, int ele) {
    for (int i = 0; i < ele; i++) {
        cout << (obj + i)->getA() << endl;
    }
}
// solution #2: write a dedicated function here
void display(der* obj, int ele) {
    for (int i = 0; i < ele; i++) {
        cout << (obj + i)->getA() << endl;
    }
}


int main() {
    // glitch: change "int i = 3" to "const int i=3"
    const int i = 3;
    base arrb[i];
    display(arrb, 3);
    der arrd[i];
    display(arrd, 3);
    return 0;
}

- perry.anderson November 21, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 votes

This is the best explanation I've found till now. Thanks!

- quirk March 29, 2017 | Flag
Comment hidden because of low score. Click to expand.
0
of 2 vote

You must declare virtual function when you call '(obj + i)->getA()'.

This is OOP 'polymorphism'.

- hclonej July 13, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Any memory layout explanation fits the output but understanding it seems complex. So here it is..

When you create derived object, base class object is created before derived class object. When you stack them one over other and try to access it with variable base address, the complier has no clue which one is variable "a" or "b".

So what it does is with respect to the current base address, it tries to access the member. So in your case.
(obj + 0) = Address of arrd as base address of object
(obj + 1) = Address of arrd + 4 byte (as your base class has 1 integer variable). Base address of object

Interestingly here, when you do (obj + 1)->getA(), complier access the first integer wrt its current base which unfortunately is the variable "b" of derived class for you.So it this output.

- hprem991 July 13, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

you are using base class pointer to point to both base class object & derived class object.

so when you point the pointer to base class object & then increment the pointer then the pointer will move to next address according to the base class size,

In case when base class pointer points to the derived class object in that case when u increment the base class pointer to +1 it will again move to next address according to base class size which will be less then derived class size. do it will point somewhere in between, & in the second iteration the value of 'b' is considered as 'a' & printed out.

always be careful while using pointers, use derived class pointer & no error will come, the output will be as you expected.

base *obj = arrb;
der *obj1 = arrd;

- swarnx July 13, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

The way you are accessing the derived class objects in the display function makes you get "1" instead "0". This is because you are incrementing the pointer to the derived class object(8 bytes) in steps of size of base class object(4 bytes). Hence when pointer to derived class object is incremented second time, it is pointing to variable b of first element of array of derived class object.

when der arrd[i] is called, below is memory footprint of this array:
arrd[0].a = 0 (offset 0 bytes)
arrd[0].b = 1 (offset 4 bytes)
arrd[1].a = 0 (offset 8 bytes)
arrd[1].b = 1 (offset 12 bytes)
arrd[2].a = 0 (offset 16 bytes)
arrd[2].b = 1 (offset 20 bytes)

The solution is to declare the getA function as virtual forcing the increment of derived class object by size of derived class object.

- swapnilsj July 13, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

Nobody say about declaring an array using a non-constant variable?

- IdontUnderstand July 18, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

The problem is due to 'Early Binding' when (obj+i)->getA() is used. So, the compiler sees pointer to base and is set to calling getA in base without knowing the object's type. To perform 'Runtime Binding' you need to use the 'virtual' keyword in base for getA. The following should work normally.

#include <iostream>
#include <typeinfo>
using namespace std;

class base 
{
    public:
	    int a;
	    base():a(0){}
	    virtual int getA(){return a;}
};

class der:public base
{
	public:
		int b;
		der():b(1){}
		int getB(){return b;}
};

void display(base *obj, int ele)
{
	for(int i = 0; i < ele; i++)
	{
		cout << (obj+i)->getA() << endl;
	}
}

int main()
{
	constexpr int i{3};
	base arrb[i];
	display(arrb, 3);
	der arrd[i];
	display(arrd, 3);
	return 0;
}

- oldoak September 05, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

when we create base "arrb" we have only one class so no matter how many time you iterate it, you will not face any problem
But in case of derived class when we create the object, memory is allocated to both 'a' and 'b' like this {{<base> = {a = 0}, b = 1}, {<base> = {a = 0}, b = 1}, {<base> = {a = 0}, b = 1}}, and when we iterate it, we only iterate it by the sizeof an integer so for the derived when we print by iterating the object it is actually iterated by 4 bytes and then we call getA, which gives 1 for the 2nd time.

just to experiment increase the loop amount and then print only the base class you will get a series of 010101

- Anonymous October 03, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

no, you do not need getA() to be virtual unless you are overriding it in the derived class, you do need a virtual destructor though and int i does need to be const, but I guess that was not the point of this task anyways. The weird behavior you are seeing is because you are not dealing with array of pointers but with array of objects rather. What you are doing here is taking an array of the derived class objects and presenting it to the function, that operates on array of base class objects (not pointers to objects). The derived class is twice the size of the base class, therefore your pointer math will be off.

- voidarg December 17, 2016 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

How can display() be called as
display(arrb, 3);

I think since display() is a member function of a class, it must be called with an object.
e.g. arrb.display(arrb, 3);
object.display(arrb, 3);

- Deeksha February 03, 2017 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

How can display() be called as
{{ display(arrb, 3); }}

I think since display() is a member function of a class, it must be called with an object.
e.g.
{{arrb.display(arrb, 3);
object.display(arrb, 3); }}

- Deeksha February 03, 2017 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

The object size changes, so incrementing the pointer based on the size of base won't work for der. You either have to fiddle around deciding on the type of the thing pointed to, or more simply just make display(...) into a template.

#include <iostream>
#include <typeinfo>

using namespace std;

class base{
public:
	int a;
	base():a(0)
	{}
	int getA(){return a;}
};

class der:public base
{
public:
	int b;
	der():b(1)
	{}
	int getB(){return b;}
};

template <typename T> void display(T *obj, int ele)
{
	for(int i = 0; i < ele; i++)
	{
        cout << (obj+i)->getA() <<endl;
	}
}

int main()
{
    int i = 3;
    base arrb[i];
    display(arrb, 3);
    der arrd[i];
    display(arrd, 3);
    return 0;
}

- robertgbjones April 17, 2017 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

the pointer passed to the template function is a pointer to Type "base" and by applying pointer arithmetic, you just add sizeof(base) as if there was only one member "int a". This c-style pointer arithmetic doesn't work in the second class where polymorphism comes into play. Therefore it would be better to pass an array of base pointers base** obj and invoke obj[i]->getA() ... or create a template function which fails again, if you pass it a true polymorphic array, since the trick about polymorphism is, it's not known at runtime... so template functions will not really solve it...

- Chris April 30, 2017 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

virtual solution is not correct, try to add another member in class base, like int c; you can see it would crash.
So, it seems that the point + i would not refer to the real object depending on the virtual or polymorphic rule, but only refer directly to the pointer type.

The solution happened to work maybe because of the code alignment that, c++ make the base class same size as der class. We can prove this by using sizeof

- chenguang.cs July 22, 2017 | Flag Reply
Comment hidden because of low score. Click to expand.
0
of 0 vote

This works perfectly without virtual and uses template technique and casting using passed parameter information. since without virtual we have no clue is base pointer is pointing to base object or derived instances of the base...The best is the do upcast via the template parameter passed.

The virtual solution also works just fine.

#include<iostream>
#include<string>

using namespace std;

class base
{
 public:
    int a;
    int c;
  base(): a(0) { }
  int getA() { return a; }
};

class der : public base
{
  public:
    int b;    
    float f;
  der():b(1) { }
  int getB() { return b; }
};

void display(base* obj, unsigned int ele)
{   
 for(unsigned int i=0; i<ele; ++i)
 {
   cout << (obj+i)->getA() << endl;    
 }
}

template <typename T> void dis(T *obj, int ele)
{
  for(int i = 0; i < ele; i++)
  {
    cout << dynamic_cast<T*>(obj+i)->getA() <<endl;
  }
}

int main(int argc, char* argv[])
{
 constexpr int i=3;
 base arrb[i];
 dis<base>(arrb, i);
 der arrd[i]; 
 dis<der>(arrd, i);
 return(0);  
}

- Anand.Kulkarni.SG November 13, 2018 | Flag Reply


Add a Comment
Name:

Writing Code? Surround your code with {{{ and }}} to preserve whitespace.

Books

is a comprehensive book on getting a job at a top tech company, while focuses on dev interviews and does this for PMs.

Learn More

Videos

CareerCup's interview videos give you a real-life look at technical interviews. In these unscripted videos, watch how other candidates handle tough questions and how the interviewer thinks about their performance.

Learn More

Resume Review

Most engineers make critical mistakes on their resumes -- we can fix your resume with our custom resume review service. And, we use fellow engineers as our resume reviewers, so you can be sure that we "get" what you're saying.

Learn More

Mock Interviews

Our Mock Interviews will be conducted "in character" just like a real interview, and can focus on whatever topics you want. All our interviewers have worked for Microsoft, Google or Amazon, you know you'll get a true-to-life experience.

Learn More