I was asked this interview question and I got it wrong. "What is the output": My answer was 135, the actual output is 136. This implies that the pointer's to the two parent classes are not equal even though they pass the prior test of being equal to the child class. I thought I understood c++ pointers, but this has me stumped for an explanation. Although I think I see what's going on, I'm not sure why. Any c++ experts out there that can offer a technical explanation? It appears the first two comparisons are more logical in nature, while the last comparison is more literal...
#include <iostream>
class A
{
public:
A() : m_i(0) { }
protected:
int m_i;
};
class B
{
public:
B() : m_d(0.0) { }
protected:
double m_d;
};
class C
: public A, public B
{
public:
C() : m_c('a') { }
private:
char m_c;
};
int main()
{
C c;
A *pa = &c;
B *pb = &c;
const int x = (pa == &c) ? 1 : 2;
const int y = (pb == &c) ? 3 : 4;
const int z = (reinterpret_cast<char*>(pa) == reinterpret_cast<char*>(pb)) ? 5 : 6;
std::cout << x << y << z << std::endl;
return 0;
}
Explanation: A base class pointer can point to a derived class object, but we can only access base class member or virtual functions using the base class pointer because object slicing happens when a derived class object is assigned to a base class object.
A pointer reference is polymorphic, since it can reference objects of different dynamic type.
By default base class pointer can hold the address of base class as well as derived call we all know. But if we don't use virtual keyword in base class then the base class pointer will call methods based on the type of pointer not on based on the value it holding.
The Base class members and member functions are inherited to Object of the derived class. A base class is also called parent class or superclass. Derived Class: A class that is created from an existing class. The derived class inherits all members and member functions of a base class.
Perhaps if you print out pa
and pb
it will be more clear what is going on.
std::cout << "A: " << pa << std::endl;
std::cout << "B: " << pb << std::endl;
std::cout << "C: " << &c << std::endl;
Running this at the end of main
gives me
A: 0xbfef54e0
B: 0xbfef54e4
C: 0xbfef54e0
(your output may be different, the important thing is that they aren't all equal)
This is because of how a C
object is represented in memory. Since a C
is both an A
and a B
, it needs to have the data members from each part. The real layout of C
is something like this (ignoring padding):
int A::m_i;
double B::m_d;
char C::m_c;
When you convert a C*
to an A*
, the compiler knows that the A
part starts at offset 0, so the pointer value doesn't change. For C*
to B*
it needs to offset by sizeof(int)
(plus padding). This offset handling is done automatically for you for calculating x
and y
. For z
it is bypassed since you use reinterpret_cast
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With