The difference between struct and class in C++
Sunday, 21 February 2010
I've seen a lot of people asking about the differences
between the use of the struct
and class
keywords in C++ lately. I don't know whether there's an influx of
C++ programmers due to the upcoming C++0x standard, or whether I've
just noticed people asking questions that haven't caught my eye
before. Whatever the reason, I'm writing this blog entry as
something I can point to the next time someone asks the
question.
Declaring and defining user-defined types
The primary use of both the struct
and class
keywords is to define a user-defined type. In
C++, such a user-defined type is termed a "class" regardless of
which keyword is used in the definition. The choice of keyword is in
one sense arbitrary, since the same features and facilities are
available whichever keyword is used — there is only one
semantic difference which we shall look at shortly. The following
two class definitions are thus equivalent in all respects apart from
the names of the classes:
struct type_a { private: int data; public: type_a(int data_): data(data_) {} virtual void foo()=0; virtual ~type_a() {} }; class type_b { private: int data; public: type_b(int data_): data(data_) {} virtual void foo()=0; virtual ~type_b() {} };
As this little example shows, you can have constructors,
destructors, member functions, private members and even virtual
member functions in a class declared with the struct
keyword, just as you can with a class declared using
the class
keyword. Though this example doesn't show it,
you can also use the struct
keyword to declare classes
with base classes.
You can even forward-declare your class using one keyword and then define it with the other, though compilers have been known to complain about this usage:
struct foo; class foo {}; class bar; struct bar {};
So, what of the minor semantic difference then? The change is in
the default access specifier for members and base
classes. Though classes defined using either keyword can
have public
, private
and protected
base classes and members, the default
choice for classes defined using class
is private
, whilst for those defined
using struct
the default is public
. This
is primarily for backwards compatibility with C: the members of a C
structure can be freely accessed by all code so in order to allow
existing C code to compile unchanged as C++ the default access
specifier for members of a class declared with struct
must be public
. On the other hand, private data is a
key aspect of the encapsulation aspect of object-oriented design, so
this is the default for those classes declare
with class
.
C doesn't have inheritance, but the default access specifier for
base classes varies with the keyword used to declare the derived
class too. It is public
for classes declared
with struct
and private
for those declared
with class
just the same as for data members. You can
still override it with an explicit specifier in both cases.
Let's take a quick look at some examples to see how that works:
struct s1 { int a; // public private: int b; // private protected: int c; // protected public: int d; // public again }; class c1 { int a; // private private: int b; // still private protected: int c; // protected public: int d; // public }; struct s2: s1, // public private c1, // private type_b, // public again protected foo, // protected public bar // public again {}; class c2: s1, // private private c1, // still private type_b, // private again protected foo, // protected public bar // public {};
As far as declaring and defining user-defined types in C++, that is
the only difference; in all other respects, classes declared
with struct
are identical to those declared
with class
.
C Compatibility
We touched on this a bit earlier: classes declared with
the struct
keyword can be compiled as C if they don't
use any features that are C++ specific. Thus the following is both a
valid C++ class and a valid C structure:
struct c_compatible { int i; char c; double d; };
It is therefore common to see struct
used in header
files that are shared between C and C++. Since non-virtual member
functions don't affect the class layout you can even have member
functions in such a type, provided they are hidden from the C
compiler with a suitable #ifdef
:
struct baz { int i; #ifdef __cplusplus void foo(); #endif; };
Templates
There is one place where you can use the class
keyword
but not the struct
one, and that is in the declaration
of a template. Template type parameters must be declared using
either the class
or typename
keyword; struct
is not allowed. The choice
of class
or typename
in this case is again
arbitrary — the semantics are identical. The choice of keyword
does not impose any semantic meaning, any type (whether a built in
type like int
or a user-defined type like a class or
enumeration) can be used when instantiating the template in either
case.You can of course declare a class template with
the struct
keyword, in which case the default access
for the members of the template is public
.
template<class T> // OK void f1(T t); template<typename T> // OK void f2(T t); template<struct T> // ERROR, struct not allowed here void f3(T t); template<class T> struct S { T x; // public member };
That's all folks!
These are the only concrete distinctions between the uses of
the struct
keyword and the class
keyword
in C++. People also use them for documentation purposes,
reserving struct
for C-compatible classes, or classes
with no member functions, or classes with no private data, or
whatever their coding standard says. However, this is just
documentation and convention rather than an inherent difference: you
could use struct
for all your classes,
or class
for all your classes except those that are
shared with C.
Posted by Anthony Williams
[/ cplusplus /] permanent link
Stumble It! | Submit to Reddit | Submit to DZone
If you liked this post, why not subscribe to the RSS feed or Follow me on Twitter? You can also subscribe to this blog by email using the form on the left.
Design and Content Copyright © 2005-2024 Just Software Solutions Ltd. All rights reserved. | Privacy Policy
9 Comments
Nice write-up (not to mention a nice captcha too!)
Does the committee intend to allow 'struct' to be used in the same context as 'typename' / 'class' any time in the foreseeable future (not a big deal, just consistent I guess)?
Another difference for templates, specifically for "template template" parameters, where you must use "class" and cannot use "struct" instead:
template< typename T > struct Holder { T x; }; // a struct
template< typename T, template< typename X > struct H = Holder > struct Bad { H<T> h; }; /* --> error: "expected 'class' before 'H'" (with g++) */
template< typename T, template< typename X > class H = Holder > struct Good { H<T> h; }; /* --> OK (even though H might be a struct (and Holder is)) */
int main() { Good< int > g = { { 42 } }; /* g.h.x == 42 */ }
Side note: the following is obviously an error too, you cannot use "typename" instead of "class" here:
template< typename T, template< typename X > typename H = Holder > struct Wrong { H<T> h; };@Michael: if you make the members of B public, it will compile. So this is not a real difference.
The default inheritance access specifier is also affected.
@saurabh: true. I'm an idiot.
@James: You're right, the default access specifier for inheritance is difference. I did cover that: look at the examples s2 and c2. The preceding text could probably be clearer though: "and base classes" isn't as explanatory as it could be. I'll update the wording.
Bit manupulated variables can be declared only in struct
example -------- struct a { char i : 1; char c : 1; };
Hi Ram,
Unfortunately you are mistaken. You can use bitfields in classes declared with "class" as well as those declared with "struct".