Dispelling Common C++ Class Myths

Introduction

In discussions about the C++ programming language, particularly about the differences between struct and class keywords, sometimes I have read or heard the following statements:

  1. A struct is a value type, while a class is a reference type.
  2. A struct contains only primitive data members and is designed for small objects.
  3. A struct cannot inherit from another struct or class, and it cannot be the base of a class.
  4. Unlike classes, structs can be instantiated without using the new operator.

All three are false in C++ and are quoted/borrowed from other programming languages. This article can help C++ beginners to discover the differences between class and struct in the C++ programming language, for further avoiding false assumptions like the ones presented above.

Note: we'll use upper-case letters for 'CLASS' as a concept to distinguish by 'class' keyword.

What are CLASSES?

This is a general definition quoted from Bjarne Stroustrup's FAQ:

A class is the representation of an idea, a concept, in the code.

By short, as stated in the C++ standard, CLASSES are types.
CLASSES can be defined using one of the following class-keys (keywords):

  • class

    class CFoo
    {
       // CFoo is a CLASS defined by using 'class' keyword
    };
    

  • struct

    struct SFoo
    {
       // SFoo is a CLASS defined by using 'struct' keyword
    };
    

  • union

    union UFoo
    {
       // UFoo is a CLASS defined by using 'union' keyword
    };
    

What is the Difference Between Class and Struct?

The members of a class are private by default, while the members of a struct are public by default ('default' means when no 'private', 'protected', or 'public' access specifier is used).

struct SFoo
{
   int m; // SFoo::m is public by default
};

class CFoo
{
   int n; // CFoo::n is private by default
};

int main()
{
   SFoo sfoo;
   CFoo cbar;
   sfoo.m = 1; // OK. SFoo::m is public by default
   cbar.n = 1; // Error: cannot access private member CFoo::n. 

   return 0;
}

Also, the default access to a base class is private for class and public for struct.

class CBase
{
public:
   int m;
};

struct SDerived : CBase
{
   //...
};

class CDerived : CBase 
{
   // ...
};

int main()
{
   SDerived sd;
   CDerived cd;
   
   sd.m = 1; // OK
   cd.m = 1; // Error: private access to CBase

   return 0;
}

The next examples show equivalent definitions for SFoo and CFoo.

struct SFoo : CBase // default public access 
{
   int m; // SFoo::m is public by default. 
};

struct SFoo : public CBase // public access specifier.
{
public:
   int m; // SFoo::m is public because of access specifier.
};

class CFoo : CBase // default private access
{
   int m; // CFoo::m is private by default. 
};

class CFoo : private CBase // private access specifier.
{
private:
   int m; // CFoo::m is private because of access specifier.
};

Note: As a good programming practice it is recommended to explicitly use the access specifiers (private, protected, and public) even where they are not explicitly necessary.

Getting Rid of False Assumptions

Now, let's resume the three statements presented in the introduction:

  1. A struct is a value type, while a class is a reference type.

    This is false in C++. When refering to CLASSES (either defined by using 'class' or 'struct'), concepts like 'value type' and 'reference type' have no sense. However, we use 'by value', 'by reference', or 'a reference to' when we are talking about objects (instances of CLASSES). The objects of both types ('struct' and 'class') can be passed either by value or by reference. Also, we can declare references to objects of type struct and class.

    struct SFoo
    {
       //...
    };
    
    class CFoo
    {
       //...
    };
    
    void func1(SFoo foo) {/*...*/}
    void func2(CFoo foo) {/*...*/}
    void func3(SFoo& foo) {/*...*/}
    void func4(CFoo& foo) {/*...*/}
    
    int main()
    {
       SFoo sfoo;
       // pass struct type object by value
       func1(sfoo);
       // pass struct type object by reference
       func3(sfoo);
       // declare a reference to struct type object
       SFoo& rsfoo = sfoo;
    
       CFoo cfoo;
       // pass class type object by value
       func2(cfoo);
       // pass class type object by reference
       func4(cfoo);
       // declare a reference to class type object
       CFoo& rcfoo = cfoo;
       // ...
       return 0;
    }
    

  2. A struct contains only primitive data members and is designed for small objects.

    Not true. A struct can contain everything a class contains: trivial or complex data members, (static, virtual) member functions, special functions like constructors, destructor, overloaded operators, and so on. Also there is no restriction regarding the struct instance size vs. class instance size.

  3. A struct cannot inherit from another struct or class, and it cannot be the base of a class.

    This is also false. In C++, a CLASS defined by using the struct keyword can inherit from another struct or class.

    struct SBase
    {
       //...
    };
    class CBase
    {
       //...
    };
    struct SFoo : public SBase
    {
       //...
    }
    struct SBar : public CBase
    {
       //...
    };
    

    Also it can be the base of another struct or class

    // struct SBase is base class for SFoo and CFoo.  
    struct SBase
    {
       //...
    };
    struct SFoo : public SBase
    {
       //...
    };
    class CFoo : public SBase
    {
       //...
    };
    

  4. Unlike classes, structs can be instantiated without using the new operator.

    This one is false as well. In C++, both struct and class types can be instantiated by using the new operator.

    struct SFoo
    {
       //...
    };
    class CFoo
    {
       //...
    };
    
    int main()
    {
       SFoo* pSFoo = new SFoo; // OK. Instantiate a struct.
       CFoo* pCFoo = new CFoo; // OK. Instantiate a class.
       //...
       delete pSFoo;
       delete pCFoo;
    
       return 0;
    }
    

Conclusion

In C++ programming language, there is no difference between CLASSES defined by using struct or class keywords, except the default access to members and base classes.

  • objects of type struct and type class can be passed either by value or by reference;
  • we can declare references to both struct and class type objects;
  • a struct can contain everything a class contains;
  • there is no restriction regarding the struct instance size vs. class instance size;
  • both struct and class can inherit from other structs or a classes;
  • both struct and class can be the base for other structs or a classes;
  • both struct and class can be instantiated by using the new operator.

Resources



About the Author

Ovidiu Cucu

Graduated at "Gh. Asachi" Technical University - Iasi, Romania. Programming in C++ using Microsoft technologies since 1995. Microsoft MVP awardee since 2006. Moderator and article reviewer at Codeguru.com, the number one developer site. Co-founder of Codexpert.ro, a website dedicated to Romanian C++ developers.

Related Articles

Comments

  • Point 4 clarification pls

    Posted by Wilbur on 04/30/2012 04:34pm

    Yes, but can structs be initiated WITHOUT 'new' as stated in point 4?

    Reply
  • Useful

    Posted by Promotional Engine on 03/19/2011 10:46am

    Thanks... Then the only difference is: "default access to members and base classes" : struct:public; class:private;

    • RE: Useful

      Posted by ovidiucucu on 03/19/2011 11:18am

      Right!

      Reply
    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Live Event Date: September 17, 2014 @ 12:00 p.m. ET / 9:00 a.m. PT Another day, another end-of-support deadline. You've heard enough about the hazards of not migrating to Windows Server 2008 or 2012. What you may not know is that there's plenty in it for you and your business, like increased automation and performance, time-saving technical features, and a lower total cost of ownership. Check out this upcoming eSeminar and join Rich Holmes, Pomeroy's practice director of virtualization, as he discusses the …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds