Class declaration

From cppreference.com
< cpp‎ | language
 
 
C++ language
General topics
Flow control
Conditional execution statements
if
Iteration statements (loops)
for
range-for (C++11)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications (until C++20)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Class/struct types
Union types
Specifiers
decltype (C++11)
auto (C++11)
alignas (C++11)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Implicit conversions - Explicit conversions
static_cast - dynamic_cast
const_cast - reinterpret_cast
Memory allocation
Classes
Class declaration
Constructors
this pointer
Class-specific function properties
explicit (C++11)
static
Special member functions
Templates
Miscellaneous
 
 

Classes are user-defined types, defined by class-specifier, which appears in decl-specifier-seq of the declaration syntax. The class specifier has the following syntax:

class-key attr(optional) class-head-name final(optional) base-clause(optional) { member-specification } (1)
class-key attr(optional) base-clause(optional) { member-specification } (2)
1) named class definition
2) unnamed class definition
class-key - one of class, struct and union. The keywords class and struct are identical except for the default member access and the default base class access. If it is union, the declaration introduces a union type.
attr - (since C++11) any number of attributes, may include alignas specifier
class-head-name - the name of the class that's being defined, optionally qualified
final - (since C++11) if present, the class cannot be derived
base-clause - list of one or more base classes and the model of inheritance used for each (see derived class)
member-specification - list of access specifiers, member object and member function declarations and definitions (see below).

Forward declaration

A declaration of the following form

class-key attr identifier ;

Declares a class type which will be defined later in this scope. Until the definition appears, this class name has incomplete type. This allows classes that refer to each other:

class Vector; // forward declaration
 
class Matrix
{
    // ...
    friend Vector operator*(const Matrix&, const Vector&);
};
 
class Vector
{
    // ...
    friend Vector operator*(const Matrix&, const Vector&);
};

and if a particular source file only uses pointers and references to the class, this makes it possible to reduce #include dependencies:

// in MyStruct.h 
#include <iosfwd> // contains forward declaration of std::ostream
 
struct MyStruct
{
    int value;
    friend std::ostream& operator<<(std::ostream& os, const S& s);
    // definition provided in MyStruct.cpp file which uses #include <ostream>
};

If forward declaration appears in local scope, it hides previously declared class, variable, function, and all other declarations of the same name that may appear in enclosing scopes:

struct s { int a; };
struct s; // does nothing (s already defined in this scope)
 
void g()
{
    struct s; // forward declaration of a new, local struct "s"
              // this hides global struct s until the end of this block
 
    s* p;     // pointer to local struct s
 
    struct s { char* p; }; // definitions of the local struct s
}

Note that a new class name may also be introduced by an elaborated type specifier which appears as part of another declaration, but only if name lookup can't find a previously declared class with the same name.

class U;
 
namespace ns
{
    class Y f(class T p); // declares function ns::f and declares ns::T and ns::Y
 
    class U f();          // U refers to ::U
 
    // can use pointers and references to T and Y
    Y* p;
    T* q;
}

Member specification

The member specification, or the body of a class definition, is a brace-enclosed sequence of any number of the following:

1) Member declarations of the form
attr(optional) decl-specifier-seq(optional) member-declarator-list(optional) ;
attr - (since C++11) any number of attributes
decl-specifier-seq - sequence of specifiers. It is only optional in the declarations of constructors, destructors, and user-defined type conversion functions
member-declarator-list - similar to a init-declarator-list, but additionally allows bit-field declaration, pure-specifier, and virt-specifier (override or final) (since C++11), and does not allow direct-non-list-initialization syntax.

This declaration may declare static and non-static data members and member functions, member typedefs, member enumerations, and nested classes. It may also be a friend declaration.

class S
{
    int d1;            // non-static data member
    int a[10] = {1,2}; // non-static data member with initializer (C++11)
 
    static const int d2 = 1; // static data member with initializer
 
    virtual void f1(int) = 0; // pure virtual member function
 
    std::string d3, *d4, f2(int); // two data members and a member function
 
    enum {NORTH, SOUTH, EAST, WEST};
 
    struct NestedS
    {
        std::string s;
    } d5, *d6;
 
    typedef NestedS value_type, *pointer_type;
};
2) Function definitions, which both declare and define member functions or friend functions. A semicolon after a member function definition is optional. All functions that are defined inside a class body are automaticaly inline, unless they are attached to a named module (since C++20).
class M
{
    std::size_t C;
    std::vector<int> data;
public:
    M(std::size_t R, std::size_t C) : C(C), data(R*C) {} // constructor definition
 
    int operator()(size_t r, size_t c) const // member function definition
    {
        return data[r * C + c];
    }
 
    int& operator()(size_t r, size_t c)      // another member function definition
    {  
        return data[r * C + c];
    }
};
3) Access specifiers public:, protected:, and private:
class S
{
public:
    S();          // public constructor
    S(const S&);  // public copy constructor
    virtual ~S(); // public virtual destructor
private:
    int* ptr; // private data member
};
4) Using-declarations:
class Base
{
protected:
    int d;
};
 
class Derived : public Base
{
public:
    using Base::d; // make Base's protected member d a public member of Derived
    using Base::Base; // inherit all bases' constructors (C++11)
};
5) static_assert declarations:
template<typename T>
struct Foo
{
    static_assert(std::is_floating_point<T>::value, "Foo<T>: T must be floating point");
};
6) member template declarations:
struct S
{
    template<typename T>
    void f(T&& n);
 
    template<class CharT>
    struct NestedS
    {
        std::basic_string<CharT> s;
    };
};
7) alias declarations:
template<typename T>
struct identity
{
    using type = T;
};
(since C++11)
8) deduction guides of member class templates:
struct S
{
    template<class CharT>
    struct NestedS
    {
        std::basic_string<CharT> s;
    };
 
    template<class CharT>
    NestedS(std::basic_string<CharT>) -> NestedS<CharT>;
};
(since C++17)
9) Using-enum-declarations:
enum class color { red, orange, yellow };
 
struct highlight
{
    using enum color;
};
(since C++20)

Local classes

A class declaration can appear inside the body of a function, in which case it defines a local class. The name of such a class only exists within the function scope, and is not accessible outside.

  • A local class cannot have static data members
  • Member functions of a local class have no linkage
  • Member functions of a local class have to be defined entirely inside the class body
  • Local classes other than closure types (since C++14) cannot have member templates
  • Local classes cannot have friend templates
  • Local classes cannot define friend functions inside the class definition
  • A local class inside a function (including member function) can access the same names that the enclosing function can access.
  • local classes could not be used as template arguments
(until C++11)
#include <vector>
#include <algorithm>
#include <iostream>
 
int main()
{
    std::vector<int> v{1, 2, 3};
 
    struct Local
    {
        bool operator()(int n, int m)
        {
            return n > m;
        }
    };
 
    std::sort(v.begin(), v.end(), Local()); // since C++11
 
    for (int n : v)
        std::cout << n << ' ';
}

Output:

3 2 1

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 1693 C++98 member declarations could not be empty empty declaration allowed
CWG 1930 C++98 member-declarator-list could be empty when decl-specifier-seq
contains a storage class specifier or cv qualifier
the list must not be empty

See also