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

  • Live Event Date: August 20, 2014 @ 1:00 p.m. ET / 10:00 a.m. PT When you look at natural user interfaces as a developer, it isn't just fun and games. There are some very serious, real-world usage models of how things can help make the world a better place – things like Intel® RealSense™ technology. Check out this upcoming eSeminar and join the panel of experts, both from inside and outside of Intel, as they discuss how natural user interfaces will likely be getting adopted in a wide variety …

  • Java developers know that testing code changes can be a huge pain, and waiting for an application to redeploy after a code fix can take an eternity. Wouldn't it be great if you could see your code changes immediately, fine-tune, debug, explore and deploy code without waiting for ages? In this white paper, find out how that's possible with a Java plugin that drastically changes the way you develop, test and run Java applications. Discover the advantages of this plugin, and the changes you can expect to see …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds