Non-static member functions
A non-static member function is a function that is declared in a member specification of a class without a static
or friend
specifier.
(see static member functions and friend declaration for the effect of those keywords)
class S { int mf1(); // non-static member function declaration void mf2() volatile, mf3() &&; // can be cv-qualified and reference-qualified // the declaration above is equivalent to two separate declarations: // void mf2() volatile; // void mf3() &&; int mf4() const { return data; } // can be defined inline virtual void mf5() final; // can be virtual, can use final/override S() : data(12) {} // constructors are member functions too int data; }; int S::mf1() { return 7; } // if not defined inline, has to be defined at namespace
Constructors, destructors, and conversion functions use special syntaxes for their declarations. The rules described in this page may not apply to these functions. See their respective pages for details.
Explanation
Any function declarations are allowed, with additional syntax elements that are only available for non-static member functions: pure-specifiers, cv-qualifiers, ref-qualifiers, final
and override
specifiers (since C++11), and member initialization lists.
A non-static member function of class X
may be called
X
using the class member access operatorX
X
Calling a non-static member function of class X
on an object that is not of type X
, or of a type derived from X
invokes undefined behavior.
Within the body of a non-static member function of X
, any id-expression e (e.g. an identifier) that resolves to a non-type non-static member of X
or of a base class of X
, is transformed to a member access expression (*this).e (unless it's already a part of a member access expression). This does not occur in template definition context, so a name may have to be prefixed with this-> explicitly to become dependent.
struct S { int n; void f(); }; void S::f() { n = 1; // transformed to (*this).n = 1; } int main() { S s1, s2; s1.f(); // changes s1.n }
Within the body of a non-static member function of X
, any unqualified-id that resolves to a static member, an enumerator or a nested type of X
or of a base class of X
, is transformed to the corresponding qualified-id:
struct S { static int n; void f(); }; void S::f() { n = 1; // transformed to S::n = 1; } int main() { S s1, s2; s1.f(); // changes S::n }
const- and volatile-qualified member functions
A non-static member function can be declared with a const, volatile, or const volatile qualifier (this qualifier appears after the parameter list in the function declaration). Differently cv-qualified functions have different types and so may overload each other.
In the body of a cv-qualified function, *this is cv-qualified, e.g. in a const member function, only other const member functions may be called normally. (A non-const member function may still be called if const_cast
is applied or through an access path that does not involve this
.)
#include <vector> struct Array { std::vector<int> data; Array(int sz) : data(sz) {} // const member function int operator[](int idx) const { // the this pointer has type const Array* return data[idx]; // transformed to (*this).data[idx]; } // non-const member function int& operator[](int idx) { // the this pointer has type Array* return data[idx]; // transformed to (*this).data[idx] } }; int main() { Array a(10); a[1] = 1; // OK: the type of a[1] is int& const Array ca(10); ca[1] = 2; // Error: the type of ca[1] is int }
ref-qualified member functionsA non-static member function can be declared with no ref-qualifier, with an lvalue ref-qualifier (the token
Note: unlike cv-qualification, ref-qualification does not change the properties of the |
(since C++11) |
Virtual and pure virtual functions
A non-static member function may be declared virtual or pure virtual. See virtual functions and abstract classes for details.
Special member functions
Some member functions are special: under certain circumstances they are defined by the compiler even if not defined by the user. They are:
(since C++11) |
(since C++11) |
- Destructor (until C++20)Prospective destructor (since C++20)
Special member functions along with the comparison operators (since C++20) are the only functions that can be defaulted, that is, defined using = default instead of the function body (see their pages for details)
Example
#include <iostream> #include <string> #include <utility> #include <exception> struct S { int data; // simple converting constructor (declaration) S(int val); // simple explicit constructor (declaration) explicit S(std::string str); // const member function (definition) virtual int getData() const { return data; } }; // definition of the constructor S::S(int val) : data(val) { std::cout << "ctor1 called, data = " << data << '\n'; } // this constructor has a catch clause S::S(std::string str) try : data(std::stoi(str)) { std::cout << "ctor2 called, data = " << data << '\n'; } catch(const std::exception&) { std::cout << "ctor2 failed, string was '" << str << "'\n"; throw; // ctor's catch clause should always rethrow } struct D : S { int data2; // constructor with a default argument D(int v1, int v2 = 11) : S(v1), data2(v2) {} // virtual member function int getData() const override { return data * data2; } // lvalue-only assignment operator D& operator=(D other) & { std::swap(other.data, data); std::swap(other.data2, data2); return *this; } }; int main() { D d1 = 1; S s2("2"); try { S s3("not a number"); } catch(const std::exception&) {} std::cout << s2.getData() << '\n'; D d2(3, 4); d2 = d1; // OK: assignment to lvalue // D(5) = d1; // ERROR: no suitable overload of operator= }
Output:
ctor1 called, data = 1 ctor2 called, data = 2 ctor2 failed, string was 'not a number' 2 ctor1 called, data = 3
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 194 | C++98 | ambiguous whether a non-static member function could have the same name as the enclosing class name |
explicit naming restriction added |