Friday, 28 November 2014

Why is the size of an empty class not zero in C++? Explain with example.

Why is the size of an empty class not zero in C++? Please explain the same with examples.

The size of an empty class is not zero. It is 1 byte generally.
See the following example.
#include<iostream>
using namespace std;
class EmptyCls {};
int main ()
{
  cout <<”Size of Pointer”<< sizeof (EmptyCls);
  return 0;
}


Output:
Size of the class1

The size of empty class is nonzero, but the addresses of the two classes are not equal to ensure that see the below example

#include<iostream>
using namespace std;
class EmptyCls { };
int main()
{
    EmptyCls ocEmpty1, ocEmpty2;
    if (&ocEmpty1 == &ocEmpty2)
      cout << "The address is equal " << endl;
    else
      cout << "The address is not equal " << endl;
   return 0;
}
See the output
The address is not equal

See another sample; there is an interesting rule that says that an empty base class need not be represented by a separate byte. So compilers are free to make optimization in case of empty base classes. Which means the size of the derived class is the total size of the base and derived class  As an exercise, try the following program on your compiler.
#include<iostream>
using namespace std;
class EmptyCls { };
class BaseCls : public EmptyCls
{
  int i;
};
int main()
{
    BaseCls ocEmpty1;
      cout << "total size is:\t" << sizeof (ocEmpty1) << endl;
      getchar ();
   return 0;
}
 Output of the above program is:
total size is:  4 
In the above example the size of the derived class is the size of the base and derived class
#include<iostream>
using namespace std;
class EmptyCls { float f; };
class BaseCls : public EmptyCls
{
  int i;
};
int main()
{
    BaseCls ocEmpty1;
      cout << "total size is:\t" << sizeof (ocEmpty1) << endl;
      getchar ();
   return 0;
}
Output is
total size is:  8
If the derived class is inherited virtual base class, in this case the size of the class is different, see here once
#include <iostream>
using namespace std;
class BaseCls
{};
class Derived_1 : public BaseCls
{};
class Derived_2 : virtual public BaseCls
{};
class Derived_3 : public BaseCls
{   
    char ch; int iVal2;
};
class Derived_4 : virtual public BaseCls
{
    char ch; int iVal1;
};
class Sample
{
    char ch; int iVal;
};
int main()
{
    cout << "sizeof (BaseCls) " << sizeof (BaseCls) << endl;
    cout << "sizeof (Derived_1) " << sizeof (Derived_1) << endl;
    cout << "sizeof (Derived_2) " << sizeof (Derived_2) << endl;
    cout << "sizeof (Derived_3) " << sizeof (Derived_3) << endl;
    cout << "sizeof (Derived_4) " << sizeof (Derived_4) << endl;   
    cout << "sizeof (Sample) " << sizeof (Sample) << endl;
    return 0;
}
The output of the above program is
sizeof (BaseCls) 1
sizeof (Derived_1) 1
sizeof (Derived_2) 4
sizeof (Derived_3) 8
sizeof (Derived_4) 12
sizeof (Sample) 8
Why class size depend only on data members and not on member functions? The functions of the class is not saved inside the object, only the member variables are stored in the object. So the size of the class becomes the total size of the member variables of the class.

What is the size of the class when the base class contains virtual functions? Existence of virtual function(s) will add 4 bytes of virtual table pointer in the class, which will be added to size of class. Again, in this case, if the base class of the class already has virtual function(s) either directly or through its base class, then this additional virtual function won't add anything to the size of the class. Virtual table pointer will be common across the class hierarchy. That is
#include <iostream>
using namespace std;
class BaseCls
{
  virtual void SomeFunction() {}
private:
        int iVal;
};
class Derived_1 : virtual public BaseCls
{
virtual void SomeFunction () {}
private:
        int iVal1;
};
class Derived_2 : virtual public BaseCls, virtual public Derived_1
{};
class Derived_3 : virtual public BaseCls, virtual public Derived_1
{   
    char ch; int iVal2;
};
class Derived_4 : virtual public BaseCls
{
    char ch; int iVal1;
};
class Sample
{
   char ch; int iVal;
};
int main()
{
    cout << "sizeof (BaseCls) " << sizeof (BaseCls) << endl;
    cout << "sizeof (Derived_1) " << sizeof (Derived_1) << endl;
    cout << "sizeof (Derived_2) " << sizeof (Derived_2) << endl;
    cout << "sizeof (Derived_3) " << sizeof (Derived_3) << endl;
    cout << "sizeof (Derived_4) " << sizeof (Derived_4) << endl;   
    cout << "sizeof (Sample) " << sizeof (Sample) << endl;
    getchar ();
    return 0;
}
The output of the above program is
sizeof (BaseCls) 8
sizeof (Derived_1) 16
sizeof (Derived_2) 20
sizeof (Derived_3) 28
sizeof (Derived_4) 20
sizeof (Sample) 8
In the example above, sizeof(BaseCls) will be 8 bytes--that is sizeof(int) + sizeof(int) + sizeof(vptr). sizeof(Derived_1) will be 16 bytes.

Now Derived will set the vptr to its own virtual function table.

 Mainly the size of the class depends on the below factors

1. Depends on the order of data members
2. Depends on the  size of all non-static data members
3. Depends on the byte alignment or byte padding
4. Depends on the  size of its immediate base class
5. The existence of virtual function(s) (Dynamic polymorphism using virtual functions).
6. Compiler being used 7. Depends on the mode of inheritance (virtual inheritance)

No comments: