Class declaration

From cppreference.com
< cpp‎ | language

Classes and structs 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 class-head-name base-clause { member-specification }
class-key - one of class or struct. The keywords are identical except for the default member access and the default base class access.
attr(C++11) - optional sequence of any number of attributes
class-head-name - the name of the class that's being defined. Optionally prepended by nested-name-specifier (sequence of names and scope-resolution operators, ending with scope-resolution operator), optionally followed by keyword final. The name may be omitted, in which case the class is unnamed (note that unnamed class cannot be final)
base-clause - optional list of one or more parent 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)

See classes for general overview of the syntax. If class-key is union, the declaration introduces a union type.

[edit] Forward declaration

A declaration of the following form

class-key attr identifier ;

Declares a class or struct 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
}

A forward declaration may also appear as part of another declaration, in particular, in a parameter declaration of a function or in a decl-specifier-seq of a simple declaration.

class Y f(class T p); // declares function f and forward-declares T and Y
Y* p; // Y is a forward-declared class
T* q; // T is a forward-declared class
std::array<class T, 2>* p; // forward-declares class T
T* q; // pointers to T can be defined

[edit] 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, which are declarations of static and non-static data members and member functions, typedef declarations, scoped and unscoped enumerations, and other, nested, class declarations.
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. A semicolon after a member function definition is optional. All member functions that are defined inside a class body are automaticaly inline.
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 parent's 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;
};

[edit] Local classes

A class declaration can appear in namespace scope (in which case it defines an ordinary class), inside another class definition (in which case it defines a nested type), and inside the body of a function, in which case it defines a local class. This class only exists within the function scope, and is not accessible outside.

  • A local class cannot have static 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 cannot have member templates or friend templates
  • 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